
特価品(見切り品?)のGR-CITRUSボード(ルネサスRX631搭載)で組み込みRuby(mruby)してます。前回は定番の温湿度センサDHT11の読み取りプログラムを作成しましたが、湿度の読み取りまでで止まってました。今回は温度も読み取れるようにしてみました。成り行きで現物合わせのタイミング制御、危ないっす。
※Rubyと一緒 投稿順indexはこちら
ソフトウエア制御のDHT11読み取り3レベル
DHT11は、Arduinoなど「電子工作業界」定番の温湿度センサですが、1-wire的な半二重双方向通信(マイコンからDHT11へは測定のトリガをかけるだけだけれども)で、かつ速度も遅いので「ソフトウエア制御」でインタフェースすることが多いのではないかと思われます。しかし同じソフトウエアでタイミングを取るといっても処理系の性能によってレベルが違う、と。
-
- 機械語命令コードで制御している場合(C言語などで記述されているライブラリの使用。Arduino環境、あるいはMicroPythonでのDHT向けライブラリの使用)
- DHT11の「プロトコル」速度にそこそこ対応できる速度の処理系(MircoPythonのPython記述によるソフトウエア制御)の場合
- DHT11の「プロトコル」速度にキチンと追従するのが難しい速度の処理系(今回のmruby)で、無理やり現物あわせの場合
上記の1のケースは何度となくやってますが、タイミングが遅れるということもなく安定。最近も以下の別シリーズで、MicroPython処理系でやってみています。
MicroPython的午睡(106) ESP32版、DHT11を接続してみる
ライブラリが存在しなくても、処理系の速度がそこそこ速いのであれば、以下の別シリーズ記事のように、MicroPython記述でタイミング制御しても安定してデータ受信(CRC検証までOK)できてます。
MicroPython的午睡(27) ラズパイPico、DHT11接続、ソフト現物合わせ
しかし今回のGR-CITRUSボード上のmrubyは、ソフトウエア的にタイミングがクリティカルです。ちょっとループ処理などでオーバヘッドがあるとデータを取りこぼしてしまいます。また、タイミングの頭出し(シンクロナイズ)も困難です。失敗するとこんな感じ。‐25℃ってなによ?きょうはちょっと蒸し蒸しする感じなんだけれども。
温度、湿度対応に「改良」したコード
DHT11は先に湿度16ビット、後に温度16ビット、末尾に検証用のCRC8ビットというデータ構成です。前回は湿度の整数部分8ビットでタイミング的にギリギリで残りは捨ててました。しかし、折角の温湿度センサです。温度、湿度両方読みたいということで今回再びのタイミング現物合わせに挑戦。
-
- 前回はタイミングを外部から観察するために1ピン使っていたが、その制御のタイミングすら惜しいのでその制御を削除した。闇夜に手探りで調整するがごとし。
- どうせ湿度の小数部分にはデータが載ってないと思われるので無視
- 温度の整数部分まで読み取る、小数部分は断念。また一部読んでないフィールドがあるのでCRCは計算できない。
現物合わせの「やっつけ」なRubyコードが以下に。
#!mruby
class Dht11
def initialize(pinname)
@pin = pinname
@buf = []
@mjVH = [0, 0, 0]
@mjVT = [0, 0, 0]
@temperature = 0
@humidity = 0
@error = 0
pinMode(@pin, 3) #output, opendrain
end
def readERROR
return @error
end
def readTemperature
return @temperature
end
def readHumidity
return @humidity
end
def readERROR
return @error
end
def readBUF
return @buf.join
end
def clearBUF
@buf = []
end
def majorityVotesH(v)
@mjVH.shift
@mjVH.push(v)
if @mjVH[0] == @mjVH[1] then
return @mjVH[0]
else
return @mjVH[2]
end
end
def majorityVotesT(v)
@mjVT.shift
@mjVT.push(v)
if @mjVT[0] == @mjVT[1] then
return @mjVT[0]
else
return @mjVT[2]
end
end
def startSignal
digitalWrite(@pin, 0)
delay(19) #min low pulse > 18msec
digitalWrite(@pin, 1)
end
def waitSIG(sig, timeOut)
count = 0
while digitalRead(@pin) == sig do
count +=1
if count > timeOut then
return false
end
end
return true
end
def bitRead
while digitalRead(@pin) == 0 do
end
return 0 if digitalRead(@pin) == 0
return 0 if digitalRead(@pin) == 0
return 1 if digitalRead(@pin) == 0
return 1
end
def b2B(lis)
work = 0
for i in lis do
work <<=1
work += i
end
return work
end
def convertData
rhI = b2B(@buf[1..8])
tmI = b2B(@buf[10..17])
temp= tmI & 0x7F
if (tmI & 0x80) != 0 then
temp *= -1
end
@temperature = majorityVotesT(temp)
if rhI < 99 then
@humidity = majorityVotesH(rhI)
end
end
def read
@error = 0
startSignal
if !waitSIG(0, 100) then
@error = 1
return false
end
# rhI
b1 = bitRead #bit 0
@buf.push(b1)
b1 = bitRead #bit 1
@buf.push(b1)
b1 = bitRead #bit 2
@buf.push(b1)
b1 = bitRead #bit 3
@buf.push(b1)
b1 = bitRead #bit 4
@buf.push(b1)
b1 = bitRead #bit 5
@buf.push(b1)
b1 = bitRead #bit 6
@buf.push(b1)
b1 = bitRead #bit 7
@buf.push(b1)
# rhD
b1 = bitRead #bit 8
@buf.push(b1)
b1 = bitRead #bit 9
b1 = bitRead #bit 10
b1 = bitRead #bit 11
b1 = bitRead #bit 12
b1 = bitRead #bit 13
b1 = bitRead #bit 14
b1 = bitRead #bit 15
# tmI
b1 = bitRead #bit 16
@buf.push(b1)
b1 = bitRead #bit 17
@buf.push(b1)
b1 = bitRead #bit 18
@buf.push(b1)
b1 = bitRead #bit 19
@buf.push(b1)
b1 = bitRead #bit 20
@buf.push(b1)
b1 = bitRead #bit 21
@buf.push(b1)
b1 = bitRead #bit 22
@buf.push(b1)
b1 = bitRead #bit 23
@buf.push(b1)
#
b1 = bitRead #bit 24
@buf.push(b1)
convertData
return true
end
end
usb = Serial.new(0, 9600)
usb.println("DHT11 Read, Pin.4")
dht11pin=4
dht11 = Dht11.new(dht11pin)
loop_interval = 2000
while true do
usb.println("DHT11 temperature & humidity")
if dht11.read then
usb.println("BUF:" + dht11.readBUF)
dht11.clearBUF
usb.println("TEMPERATURE:" + dht11.readTemperature.to_s)
usb.println("HUMIDITY: " + dht11.readHumidity.to_s)
usb.println("ERROR:" + dht11.readERROR.to_s)
end
delay(loop_interval)
end
上記ソース読んでいただけると、タイミング調整のためのやっつけな工夫が随所に。わざわざ読むようなもんでもないですが。
実機実行結果
Rubic環境から、GR-CITRUSボード上で上記プログラムを動作させている様子が以下に。
上記みると、温度25℃、湿度66%とな。ちょっと手元の温度計より温度は高めか。湿度はほぼほぼ一致。まあ、ここだけだと読めているような気がする。大丈夫か?ま、成り行きの現物合わせなので信用しないでね。

