![](https://jhalfmoon.com/dbc/wp-content/uploads/2018/11/JH-2-150x150.png)
特価品(見切り品?)のGR-CITRUSボード(ルネサスRX631搭載)で組み込みRuby(mruby)してます。今回はMicroPython上で動いている「フルソフトウエア」のDHT11センサ読み取りプログラムのRubyへの移植にトライ。しかし湿度の読み取りだけ成功?したところで止めました。タイミング違い過ぎ。
※Rubyと一緒 投稿順indexはこちら
今回は、以下の別シリーズ記事にて動作確認済のMicroPythonスクリプトのRuby(mruby)への移植トライアルです。元になったMicroPythonソースは以下の記事の後ろの方に貼り付けてあります。
MicroPython的午睡(27) ラズパイPico、DHT11接続、ソフト現物合わせ
DHT11は、Arduinoなどへの接続で定番の温湿度センサです。インタフェースはDHT11規格とでもいうべき「1-wire風」の双方向通信です。1本の線でマイコン側からのトリガを受信すると今度はDHT11が自分のタイミングで、湿度、温度、CRCを送信してくるもの。
通信スピードは結構遅いので、MicroPython上では遅延関数以外のタイミングを用いず、ソフトウエアで「タイミング」をとって通信してました。特段ハードウエアを使っていないので、「タイミング」さえMicroPythonと合わせられればRubyちゃんでも通信可能な筈。ただ、ラズパイPico上のMicroPythonで元のプログラムを作成したときはオシロで波形を見ながら「現物あわせでタイミングを調整」してます。成り行きまかせ。ただ、Pico上のMicroPythonはそこそこ速かったので「なんとかできた」感じ。Rubyちゃんではどうか?
Rubyちゃん上での実装、湿度だけ
最初、湿度、温度、CRC全てを受信すべくMicroPythonコードをほぼほぼ1対1な形でRubyに移植しました。Ruby素人は沢山コーディングミスをして結構手間取りました。なにせ使用している、Rubic処理系のエラー表示が素っ気なさすぎます。
前にも書きましたが、どこにエラーがあるのかサッパリです。まあ、Runtimeエラーの方が多少筋がいいですが、「多少」です。こんな感じ。
苦難の道のりを乗り越え、ようやく移植完了。当然ながら動きはしません、はい。
そこからはオシロでタイミング調整です。成り行きまかせの現物あわせ。なおDHT11との通信タイミングを外部から観察するのに
-
- DHT11はピン4で双方向通信(以下のオシロ画面で黄色C1)
- 通信タイミングを知るためにピン6にパルス出力(青色C2)
DHT11は生きてなにやらデータを送ってきている感じですが、受け取る側のスクリプト、青色パルスの方はほとんどデータ終わってから動き始めてないかい?
MicroPythonのコードはデータシートの波形に従って「マイコンとDHT11間の頭出しプロトコル」的なところを実装していたのですが、そんなものを受け入れる余裕はRubyちゃんには無さそうでした。仕方ないのでバッサリやって頭を合わせました。こんな感じ。
青色パルスの最初の一発は頭出しのところですが、引き続く4発は4ビットを「捕獲」するためのタイミングです。全然ダメじゃん。捕獲側が4回回っている間にDHT11の方は5ビット以上送ってきてるじゃん。ぜんぜん間に合ってねずら。
タイミング表示の青パルスの生成だけでも負荷重そうだったのでさらに軽減。最初の8ビットの頭とお尻だけに青パルスを入れ、ビットを拾うことに。最初の太いハイは無視して次の細いパルスが0、太いパルスが1ということであります。
ソフトでやることはこのパルス幅を測って0/1決定すれば良いのですが、MicroPythonで余裕をもってできていた観察ができません。forループでビット処理を回転させることすら負荷重いみたい。それでもかなり無理やりだけれども最初の8ビットは受信できる感じになってきました(でも8ビット以上長くするとどこかでSYNCハズレそうな感じがヒシヒシと。)
最初の8ビットに%表示の湿度が載っているので、そこだけ取り出してみることにいたしました。
実験に使用したRubyスクリプト
現物あわせのやっつけが以下に。結構あちこちにコメントアウトしてあるのは、当初組み込んであった、温度やCRC計算やらの残骸デス。「ハードウエア」でのデバッグ用のコードもありで、かなり汚い。
#!mruby class Dht11 def initialize(pinname) @pin = pinname @buf = [] @crcR = 0 @crcC = 0 @crc = true @temperature = 0 @humidity = 0 @error = 0 pinMode(@pin, 3) # output, opendrain pinMode(6, 1) # Hardware debug only end def readCRC return @crc 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 markSignal digitalWrite(6, 0) digitalWrite(6, 1) digitalWrite(6, 0) 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 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[0..7]) # rhD = b2B(@buf[8..15]) # tmI = b2B(@buf[16..23]) # tmD = b2B(@buf[24..31]) # @crcR = b2B(@buf[32..39]) # @crcC = (rhI + rhD + tmI + tmD) & 0xFF # if @crcR == @crcC then # @crc = true # else # @crc = false # end # @temperature = (tmI & 0x7F) + (tmD / 10) # if (tmI & 0x80) != 0 then # @temperature *= -1 # end @humidity = rhI # @humidity = rhI + (rhD / 10) # @buf = [] end def read @error = 0 startSignal markSignal if !waitSIG(0, 100) then @error = 1 return false end markSignal 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) markSignal 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("HUMIDITY: " + dht11.readHumidity.to_s) usb.println("ERROR:" + dht11.readERROR.to_s) end delay(loop_interval) end
実験に使用した回路
息をDHT11に吹きかけたら値が大きくなったので、湿度センサのデータを拾っているみたいっす。しまらんなあ。