https://github.com/github0013/rpi-dht Ich habe versucht zu schmücken
$ gem install rpi-dht
Ich habe versucht, [dht-sensor-ffi] 1 zu verwenden, aber als ich es lange verwendet habe, habe ich einen Fehler erhalten und konnte nicht herausfinden, was falsch war.
Ich habe keine andere Wahl, als die Bibliothek selbst zu erstellen (ich kann kein C schreiben). mit Rubin
Zuallererst ist DHT "Single-Bus-Kommunikation (ONE-WIRE)". Ich denke, [GPIO4] 4 ist das.
--3,3 V / 5 V als Plus für Raspberry Pi ――Von Minus bis Minus von Raspberry Pi --Datenzeile zu [GPIO4] 4 von Raspberry Pi
[DHT11 Datenblatt] 2 [DHT22 Datenblatt] 3
Am 22.11. Gibt es keinen Unterschied, bis die endgültigen Daten erfasst sind. Der Fluss ist so
HIGH / LOW fließt jeden Moment (in Mikrosekunden) und Sie müssen es lesen (also ist es hart für Rubin ...).
Beachten Sie, dass es nicht einfach HIGH = 1 und LOW = 0 ist. Nachdem LOW ungefähr 50us dauert, wird beurteilt, ob HIGH länger als 50us dauert (= 1) oder nicht (= 0) (also ist es streng für Rubin ...).
Wenn Sie es beispielsweise beim Erfassen von Daten zusammen mit "Time.now.to_f" verwenden, dauert dieser Vorgang wahrscheinlich lange und die Daten fließen zuerst. Aus diesem Grund wurden die Daten zuerst nacheinander gespeichert, und die durchschnittliche Häufigkeit, mit der LOW danach fortgesetzt wurde, wurde gespeichert, und es wurde beurteilt, ob HIGH über oder unter dem Durchschnitt lag.
Organisieren Sie 40 Bit in 8-Bit-Bytes.
Teilen in.
Oberes Feuchtigkeitsbyte + Unteres Feuchtigkeitsbyte + Oberes Temperaturbyte + Unteres Temperaturbyte == Parität
Überprüfen Sie mit.
Feuchtigkeitsoberbyte + Feuchtigkeitsunterbyte + Temperaturoberbyte + Temperaturunterbyte
00000001 + 00000001 + 00000001 + 00000001 # => 00000100
Wenn die Parität "00000100" ist, ist es OK
Da die Genauigkeit gering ist, ist das untere Byte immer "00000000", sodass Sie es ignorieren können. Einfach
Sowohl Luftfeuchtigkeit als auch Temperatur werden in 2 Bytes ausgedrückt.
Beispiel: 2 Bytes "0000001000001111" (527) bei einer Luftfeuchtigkeit von 52,7%, geteilt durch 10 bis 52,7% 2 Bytes von "0000000100000111" (263) unter der Annahme, dass die Luftfeuchtigkeit 26,3 ° C beträgt, und Teilen durch 10 ergibt 26,3 ° C.
Daher kann der korrekte Wert nur erhalten werden, wenn das obere Byte um 8 Bit verschoben und zum unteren Byte addiert wird.
Beispiel
humidity = ((humidity_high << 8) + humidity_low) / 10.to_f
Weiterhin kann nur bei Temperatur Minus ausgedrückt werden. Dies hängt davon ab, ob das höherwertige Temperaturbit mit 1 beginnt. Daher muss das erste Bit gelöscht werden, nachdem bestätigt wurde, ob das erste Bit 1 ist.
is_negative = temp_high & 0b10000000
temp_high &= 0b01111111
Die spätere Berechnung entspricht dem obigen Feuchtigkeitsbeispiel.
Ob die in Mikrosekunden fließenden Daten genau abgerufen werden können (ob die Paritätsprüfung erfolgreich ist oder nicht), hängt vom Grad der Verarbeitungsstauung zu diesem Zeitpunkt ab. Daher ist nicht bekannt, ob Daten jedes Mal mit einem einzigen Aufruf zuverlässig abgerufen werden können. .. Daher ist es notwendig, es mehrmals wiederholt auszuführen, bis Daten erhalten werden können. Tatsächlich hat [dht-sensor-ffi] 1 standardmäßig auch [50 Versuche] 5.
DHTBase-Klasse
require "rpi_gpio"
RPi::GPIO.set_numbering :bcm #Geben Sie den Pin anhand der bcm-basierten Nummer an
class DHTBase
CLEAR_SIGNALS = 500 / 1000.to_f # ms
START_SIGNAL = 1 / 1000.to_f # ms
VALID_BYTE_SIZE = 5 # humidity_high, humidity_low, temp_high, temp_low, parity
BITS_IN_BYTE = 8
HUMIDITY_PRECISION = 10.to_f
TEMPERATURE_PRECISION = 10.to_f
ENOUGH_TO_CAPTURE_COUNT = 1000 #Häufigkeit, mit der ausreichende Daten abgerufen werden können (ungefähr)
class << self
def read(pin)
dht = new(pin)
dht.send_start_signal
dht.collect_response_bits
dht.convert
end
end
def initialize(pin)
@pin = pin
end
def send_start_signal
RPi::GPIO.setup pin, as: :output
RPi::GPIO.set_high pin
sleep(CLEAR_SIGNALS)
RPi::GPIO.set_low pin
sleep(START_SIGNAL)
end
def collect_response_bits
RPi::GPIO.setup pin, as: :input, pull: :up
@bits = ENOUGH_TO_CAPTURE_COUNT.times.collect { RPi::GPIO.high?(pin) }
release
break_into_byte_strings
check_parity!
end
private
attr_reader :pin, :bits, :byte_strings
def release
RPi::GPIO.clean_up pin
end
def break_by_high_or_low
# HIGH = true
# LOW = false
# [false, false, false, ...]
# [true, true, true, ...]
#Fassen Sie wie zusammen
last_value = :not_yet
bits.slice_before do |value|
(last_value != value).tap { |not_same| last_value = value if not_same }
end.to_a
end
def break_into_byte_strings
#Aus diesem Grund umgekehrt und wahr von unten/Nach dem Erstellen eines falschen Array-Paares
#Für jeweils 8 Bits werden 5 Datenbytes vorbereitet.
# ture/Falsches Array-Paar = 0 oder 1 Bit
#Dies sind 5 Bytes, 40 Bits=80 Sequenzen
# [false, false, false, ...]
# [true, true, true, ...]
# [false, false, false, ...]
# [true, true, true, ...]
# [false, false, false, ...]
# [true, true, true, ...]
# ...
# ...
# ...
#Das Ende endet immer mit einer Reihe von falschen und einer langen Reihe von wahren, und da es sich nicht um Daten handelt, wird es nicht verwendet.
# [false, false, false, ...]
# [true, true, true, true, true, true, true, true, true, ...]
end_part, *low_high_pairs = break_by_high_or_low.reverse.each_slice(2).to_a
# low_high_pairs = [
# ture /falsches Array-Paar=1 Bit
#1 Byte für 8 Elemente
# [
# [[true, true ...], [false, false ...]], 1
# [[true, true ...], [false, false ...]], 2
# [[true, true ...], [false, false ...]], 3
# [[true, true ...], [false, false ...]], 4
# [[true, true ...], [false, false ...]], 5
# [[true, true ...], [false, false ...]], 6
# [[true, true ...], [false, false ...]], 7
# [[true, true ...], [false, false ...]], 8
# ]
# ...
#Insgesamt 5 Bytes
# ]
#Zuerst wahr für Antwortsignal/Ich habe ein falsches Array, muss es aber nicht lesen
#Ich nehme nur die letzten 5
valid_bytes =
low_high_pairs.reverse.each_slice(8).to_a.last(VALID_BYTE_SIZE).select do |pair|
pair.all? { |x| x.is_a?(Array) }
end
unless valid_bytes.size == VALID_BYTE_SIZE
raise "not valid byte set (#{valid_bytes.size}bytes, should be #{
VALID_BYTE_SIZE
}bytes)"
end
valid_bytes.each do |byte|
unless byte.size == BITS_IN_BYTE
raise "not a byte (#{byte.size}bits, should be #{BITS_IN_BYTE}bits)"
end
end
all_falses = valid_bytes.collect { |byte| byte.collect(&:last) }.flatten(1) #Innerhalb von Bytes von Byte zu Bitarray reduzieren
average_false_count = all_falses.sum(&:size) / all_falses.size.to_f
#Beurteilen Sie, ob es 1 oder 0 ist, indem Sie die Anzahl der wahren Elemente anhand der Anzahl der falschen aufeinanderfolgenden Elemente vergleichen, die durchschnittlich 50us entsprechen.
@byte_strings =
valid_bytes.collect do |byte|
byte.collect { |trues, _| average_false_count <= trues.size ? 1 : 0 }.join
end
end
def bytes
byte_strings.collect { |x| x.to_i(2) }
end
def check_parity!
humidity_high, humidity_low, temp_high, temp_low, parity = bytes
unless (humidity_high + humidity_low + temp_high + temp_low) == parity
raise "parity check failed"
end
end
end
DHT11-Klasse
class DHT11 < DHTBase
def convert
humidity_high, _, temp_high, _, _ = bytes
humidity = humidity_high
temperature = temp_high #Sie sollten die negative Temperatur nicht kennen
{ humidity: humidity, temperature: temperature }
end
end
DHT22 Klasse
class DHT22 < DHTBase
def convert
humidity_high, humidity_low, temp_high, temp_low, _ = bytes
is_negative = 0 < (temp_high & 0b10000000)
temp_high &= 0b01111111
humidity = ((humidity_high << 8) + humidity_low) / HUMIDITY_PRECISION
temperature = ((temp_high << 8) + temp_low) / TEMPERATURE_PRECISION
temperature *= -1 if is_negative
{ humidity: humidity, temperature: temperature }
end
end
Ausführungsbeispiel
100.times do
begin
p DHT22.read(4)
break
rescue => exception
p exception
puts exception.backtrace.first(10).join("\n")
sleep 0.1
end
end
Recommended Posts