78k0s/KA1+ でRHT03を味見

 2012-04-14
今まではLM61CIZを使って気温データを取っていたが、ちょっと欲を出して湿度もとってみたいと思い始めた。


というわけで、RHT03を使って気温・湿度のデータを取得してみるテスト。
 

なぜRHT03


最初のうちは、簡単に計れるお便利なセンサーがないか探して見たのですが、インピーダンスの変化容量の変化でセンシングするものはあったのですが簡単お手軽にA/D変換して計測できるようなお便利センサーはなかなか無いようでした。補正も面倒そう。
仕方がないのでシリアル通信で測定値を渡してくれるお利口さんなセンサーを買うことにしました。それがRHT03でした。他にもシリアルで値をくれるセンサーはありましたが、そのなかでも頭一つ抜き出て安かったのが、RHT03。


購入するときはDHT22だった


DSC_0492.jpgストロベリーリナックスさんでDHT22というものを購入しました。1個987円。
しかし届いたものはなぜかRHT03というブツ。
どうやらDHT22の供給会社が変わった(名称変更?)らしく、型番も変更された模様。新しい名前はRHT03のようなので、本記事では基本的にRHT03と呼称します。
DHT22で検索して出てくる仕様書には中国語っぽい?感じで説明が描いてあったりするのですが、RHT03名称の仕様書だとちゃんと(?)英語での説明になっているのでそっちの方が理解しやすいです。


シリアル通信


wave.pngRHT03には4端子ついていますが1本はopenにします。残る3本で電源、グラウンド、信号線です。
信号線は1Kの抵抗でプルアップするように記載があります。この信号線を1ms以上ローに落とすことで、センサーへのデータ要求になります。ローに落とした後はプルアップによるハイが20-40usあった後にセンサーから要求に対する応答として80usのロー、80usのハイが返ります。それに続いてデータ送信が始まります。
ロー50usの後、ハイが26-28usあるいは70usが来て、コレで1bit。データはハイ期間で0,1を見分けます。
データは湿度16bit、温度16bit、CRC8bitの順に全部で40bit来る。なので、仮に全データが1だった場合は5msくらいの通信時間になる。


78k0s/KA1+で読む


DSC_0493.jpgなんで78k0s/KA1+なのか? それは環境がそれしかないから!
一応RL78/G13 Stickも入手はしているがまだそれをバリバリ使える状態にはない&そろそろ78k0s使ってやらないと二度と使わなくなりそうなので。

しかしスペック的にはキビシイ感じです。アセンブラで書けばまだマシかもしれませんがそこまでパワーかける気力は・・・ない。
タイマのパルス幅測定など手段はいろいろありそうですが、内蔵8MHzでCPU動かしていると間に合いません。結局、原始的に端子の値を取り込んでから、後で時間を掛けてデコードする手法を採りました。

#define DATA_MAX      500
unsigned char dat[DATA_MAX/8 +1];

PORT_ChangeP123Output(0); /* output P12_3=L */
wait_ms(10); /* wait over 1ms */
WDT_Restart();

/* ************************************************************
** receive sensor data **
************************************************************ */
DI(); /* disable interrupt */
PORT_ChangeP123Input(1); /* input P12_3 with pullup */
for(cnt=0; cnt<=(DATA_MAX/8);cnt++){
dat[cnt]|=P12.3<<0;
dat[cnt]|=P12.3<<1;
dat[cnt]|=P12.3<<2;
dat[cnt]|=P12.3<<3;
dat[cnt]|=P12.3<<4;
dat[cnt]|=P12.3<<5;
dat[cnt]|=P12.3<<6;
dat[cnt]|=P12.3<<7;
}
WDT_Restart();
EI(); /* enable interrupt */
/* **************** end receive sensor data ******************* */

上記はデータ受信部のエッセンスのみ。
PORT_ChangeP123Output(0);でマイコンから信号線をロードライブ。
1ms以上待ってから、PORT_ChangeP123Input(1);でマイコンの端子を入力モードにし、内部プルアップを有効にする。
あとはDI();で割り込みを禁止してひたすら端子の値を変数にぶち込みます。
処理速度がギリギリなので、8bit分の取り込みをベタ書きにしてそれをforで回してます。なんとかこれで動きました。

これで、変数dat[]にMAX_DATA数分の端子値が格納されます。あとはこれをデコードしてやります。
格好良くデコード論理を記述してやろうと思っていましたが、コーディングしているうちに、処理速度の限界やRAM領域の限界が見えてきてしまい、今後の(保守の)ために格好良く書くというモチベーションがだだ下がりしてしまいました。
というわけで、汚くベタ書きコードです。(言い訳)

デコード時のステートをいくつか定義してそれをloop内のswitchで処理させてます。
statejob
STATE_REJECT_PULLUP先頭にあるプルアップによるハイ期間を無視する
STATE_WAIT_READER_Lセンサー応答ロー80usを判定する
STATE_WAIT_READER_Hセンサー応答ハイ80usを判定する
STATE_GET_DATA_LセンサーデータL期間
STATE_GET_DATA_HセンサーデータH期間 データの0,1を判定する
STATE_FIN40bit分受信したらこのステートになる CRCを確認する
STATE_ERRORCRCエラー


# おまけ
# これまで使用していたLM61CIZとコリレーションを取るため、A/D変換の処理も入れてます。

最後に、取得したデータをUARTで出力して、一連の動作は完了。
CRCエラー(STATE_ERROR)になっていたらその旨を出力してます。
# LM61CIZ専用の温度換算出力も書いてます。 変換テーブルを事前に持っておくという姑息な手法。


出力


PCでシリアルポートから出力を確認する
wakeup...ok
decode: 041.4%RH , 026.3degC
ADC0:0173
ADC1:0460
ADC2:0180
ADC3:0681
temp1(24.4),temp2(27.8),
decode: 041.3%RH , 026.3degC
ADC0:0174
ADC1:0460
ADC2:0180
ADC3:0681
temp1(24.9),temp2(27.8),
decode: 041.3%RH , 026.3degC
ADC0:0174
ADC1:0461
ADC2:0180
ADC3:0681
temp1(24.9),temp2(27.8),
decode: 041.2%RH , 026.3degC
ADC0:0174
ADC1:0460
ADC2:0180
ADC3:0680
temp1(24.9),temp2(27.8),

だいたい妥当っぽい値は取れてきている。
センサーの値更新が2秒以上必要とのことなので、出力も2秒以上あけています。
最初のwakeup...は、電源投入後1secはなにもしてはいけない、というセンサーの仕様のための待ち時間。


デバッグ出力


デバッガ等の高度な機材(?)は持っていないため、原始的なprintデバッグを行ってます。
define DEBUGすると有効になり、下記のような出力が得られます。
wakeup...ok
rcv: 110000001111110000110000111000010000011000001100001100001100000111110000011
00000111110000011111000001100001111110000110000110000111111000001100001110000110
00011000011100001100011100001111110000011000011000001000001100001110000110000111
11100001100001110000111111000011111100001100001111110000111110000011000011111000
00111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111
1(1)1(1)0(1)0(2)0(2)0(2)0(2)0(2)1(2)1(3)1(3)1(3)1(3)1(3)0(3)0(4)0(4)0(4)1(4)1(5)
0(5)[0]0(4)0(4)0(4)1(4)1(5)1(5)0(5)[0]0(4)0(4)0(4)1(4)0(5)[0]0(4)0(4)0(4)0(4)1(4
)1(5)0(5)[0]0(4)0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(
4)1(4)1(5)0(5)[0]0(4)0(4)0(4)0(4)1(4)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)0(4)1(4)
1(5)0(5)[0]0(4)0(4)0(4)0(4)1(4)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)0(4)1(4)1(5)1(
5)1(5)1(5)0(5)[1]0(4)0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)1(5)1(5)1(5)
1(5)0(5)[1]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4
)1(5)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)1
(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)
1(5)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)1(4)1(5)1(5)0(5)[0]0(4)0(4)0(4
)1(4)1(5)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1
(5)0(5)[0]0(4)0(4)0(4)0(4)1(4)0(5)[0]0(4)0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)
1(4)1(5)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)1(5)1(5)1(5)1(
5)0(5)[1]0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)1(5)0(5)[0]0(4)0(4)0(4)1
(4)1(5)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)1(4)1(5)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4
)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)1(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)1(4)1
(5)1(5)1(5)1(5)0(5)[1]0(4)0(4)0(4)0(4)1(4)1(5)0(5)[0]0(4)0(4)0(4)1(4)1(5)1(5)1(5
)1(5)0(5)[1]
hum:0000000101101001,tem:0000000100000010,CRC:01101101
decode: 036.1%RH , 025.8degC

rcvの部分はセンサー波形の生データ。決め打で500サンプル取得していますが、ちゃんと通信終了までサンプリング出来ているのが確認できる。実用上、はみ出てしまうことはない・・ハズ。

その後の数字と()と[]は、デコード部分。数字のみの部分がセンサーデータ(生データ)、()でくくられているのが、デコード処理のステート。[]でくくられているのが、デコード結果の値。注意深く見ていると、1の後に0が来た部分(センサー波形立ち下がり)でデコード値が決定されているのが分かります。

デコード部の後は湿度、温度、CRCのデコード後のデータを16bit,16bit,8bitで表示。
CRCチェック用の出力。

最後に、デコード結果を湿度と温度で表してゴール。

作業中、突然CRCエラーが頻発するようになって、原因がわからずしばらくそこで嵌っていたのですが、デコード処理時に使っている一時変数をvolatile指定するとピタリとCRCエラーは収まりました。いつもはマイコン向けCを書くことはないので、ついつい忘れがち。。


問題点


LM61_RHT03_temp.pngいままで「ぎりぎり動いた」などと書いてきましたが、厳密には動いてません><;
左図はRHT03とLM61CIZの温度データをプロットしたモノ。RHT03はデータ抜けがあります。
CRCエラーなんですね、これ。。。 どうやら、温度が下がるとCRCエラーが頻発する傾向があるらしく、これは実用にはなりません。
温度依存があるということで、おそらく通信速度について行けてないと思われます。しかしコードの工夫による最適化はこれ以上は難しい。。。(アセンブラは嫌~)


対応予定


内蔵8MHzでは遅いとのことなので、外部発振で10MHz動作させるしかありませんね。
手持ちパーツが無いのでとりあえず手配中。。。


現状のCソース(mainのみ)



とりあえず終わり。


追記:

バグがあります


Umbrella 78k0s/KA1+ でRHT03 改 http://wbbwbb.blog83.fc2.com/blog-entry-82.html
デコード時の処理でアホっぽいバグがありました。。。
 
コメント
CRCチェックのデコード論理がマズい気がします。 8bitの足し算して9bit目にあふれると、必ずエラーとして判定されちゃうかも。
気が向いたら確認します。
【2012/06/18 13:51】 | umbrella #mvcB0rpk | [edit]
温湿度センサAM2302とPICで計測をしています。
チェックサムでエラーが出て困ってました。
コメントの記述を見て、和が8bitをオーバーフローした
時だけエラーが起こることに気付き、解決することができました。

ありがとうございました。

【2014/07/12 21:20】 | ito #LZUhE/Ak | [edit]
コメントありがとうございます。
お役に立てたようで恐悦至極~。
バグを修正した記事のURLを追記しておきました。(←追記したつもりになっていた)
【2014/07/12 23:28】 | umbrella #mvcB0rpk | [edit]












管理者にだけ表示を許可する
トラックバック
トラックバックURL:
http://wbbwbb.blog83.fc2.com/tb.php/71-dcdd7e89
≪ トップページへこのページの先頭へ  ≫