https://github.com/github0013/rpi-dht J'ai essayé de gemme
$ gem install rpi-dht
J'ai essayé d'utiliser [dht-sensor-ffi] 1, mais lorsque je l'ai utilisé pendant longtemps, j'ai eu une erreur et je n'ai pas pu comprendre ce qui n'allait pas.
Je n'ai pas d'autre choix que de créer moi-même la bibliothèque (je ne peux pas écrire C). avec rubis
Tout d'abord, DHT est «Communication à bus unique (ONE-WIRE)». Donc je pense que [GPIO4] 4 est ça.
--3.3v / 5v comme un plus pour Raspberry Pi ――De moins au moins de Raspberry Pi --Ligne de données vers [GPIO4] 4 de Raspberry Pi
[Fiche technique DHT11] 2 [Fiche technique DHT22] 3
Il n'y a pas de différence le 22/11 jusqu'à ce que les données finales soient prises. Le flux est comme ça
HIGH / LOW coule à chaque instant (en microsecondes), et vous devez le lire (donc c'est dur pour ruby ...).
Notez que ce n'est pas simplement HIGH = 1 et LOW = 0. Après que LOW dure environ 50us, il est jugé si HIGH dure plus de 50us (= 1) ou non (= 0) (c'est donc strict pour le rubis ...).
Par exemple, si vous le prenez avec Time.now.to_f
lors de l'acquisition de données, ce processus prendra probablement beaucoup de temps et les données circuleront en premier. Pour cette raison, les données ont d'abord été sauvegardées successivement, et le nombre moyen de fois que LOW a continué après cela a été sauvegardé, et il a été jugé si HIGH était supérieur ou inférieur à la moyenne.
Organiser 40 bits en octets 8 bits,
Diviser en.
Octet supérieur d'humidité + Octet inférieur d'humidité + Octet supérieur de température + Octet inférieur de température == parité
Vérifier avec.
Octet supérieur d'humidité + octet inférieur d'humidité + octet supérieur de température + octet inférieur de température
00000001 + 00000001 + 00000001 + 00000001 # => 00000100
Si la parité est 00000100
, c'est OK
La précision étant faible, l'octet inférieur est toujours «00000000», vous pouvez donc l'ignorer. Simplement
L'humidité et la température sont exprimées en 2 octets.
Exemple:
2 octets de «0000001000001111» (527) en supposant une humidité de 52,7%, divisé par 10 à 52,7%
2 octets de 0000000100000111
(263) en supposant que l'humidité est de 26,3 ℃, et en divisant cela par 10, cela donne 26,3 ℃
Par conséquent, la valeur correcte ne peut être obtenue que si l'octet supérieur est décalé de 8 bits et ajouté à l'octet inférieur.
Exemple
humidity = ((humidity_high << 8) + humidity_low) / 10.to_f
De plus, seulement dans le cas de la température, le moins peut être exprimé. Cela dépend du fait que le bit de température de poids fort commence par 1. Par conséquent, il est nécessaire de supprimer le premier bit après avoir confirmé si le premier bit est 1.
is_negative = temp_high & 0b10000000
temp_high &= 0b01111111
Le dernier calcul est le même que l'exemple d'humidité ci-dessus.
La question de savoir si les données circulant en microsecondes peuvent être obtenues avec précision (que le contrôle de parité réussisse ou non) dépend du degré de congestion du traitement à ce moment-là, de sorte que l'on ne sait pas si les données peuvent être obtenues de manière fiable à chaque fois avec un seul appel. .. Par conséquent, il est nécessaire de l'exécuter plusieurs fois jusqu'à ce que les données puissent être obtenues. En fait, [dht-sensor-ffi] 1 vaut également [50 essais] 5 par défaut.
Classe DHTBase
require "rpi_gpio"
RPi::GPIO.set_numbering :bcm #Spécifiez la broche par un numéro basé sur bcm
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 #Nombre de fois où des données suffisantes peuvent être obtenues (environ)
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, ...]
#Résumer comme
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
#Pour cette raison, inverser et vrai du bas/Après avoir créé une fausse paire de tableaux
#5 octets de données sont préparés pour chaque 8 bits.
# ture/Fausse paire de tableaux = 0 ou 1 bit
#C'est 5 octets, 40 bits=80 séquences
# [false, false, false, ...]
# [true, true, true, ...]
# [false, false, false, ...]
# [true, true, true, ...]
# [false, false, false, ...]
# [true, true, true, ...]
# ...
# ...
# ...
#La fin se termine toujours par une série de faux et une longue série de vrais, et ce ne sont pas des données, alors ne les utilisez pas
# [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 /fausse paire de tableaux=1 bit
#1 octet pour 8 éléments
# [
# [[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
# ]
# ...
#5 octets au total
# ]
#Premier vrai pour le signal de réponse/J'ai un faux tableau mais je n'ai pas besoin de le lire
#Je prends seulement les 5 derniers
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) #Aplatir du tableau d'octets en bits dans les octets
average_false_count = all_falses.sum(&:size) / all_falses.size.to_f
#Jugez si c'est 1 ou 0 en comparant avec le nombre de vrais éléments en fonction du nombre de fausses consécutives équivalentes à 50us en moyenne.
@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
Classe DHT11
class DHT11 < DHTBase
def convert
humidity_high, _, temp_high, _, _ = bytes
humidity = humidity_high
temperature = temp_high #Vous ne devriez pas connaître la température négative
{ humidity: humidity, temperature: temperature }
end
end
Classe DHT22
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
Exemple d'exécution
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