Raspberry Piで部屋の温度を取得するという、いかにもな題材に取り組んでいる人がいて、
ふーんと思って見ていたら、使ってる温度センサーの通信方式がけっこう独特だった。
DHT11というよく使われている温湿度センサーもモジュールがあるようで。
足が4本生えているが、1本はNC(未使用)、1本はGND、1本はVcc(電源)で、
すなわち、通信線は1本だけということ。
通信線1本でデータをやりとりする手段自体はいろいろある。
調歩同期式シリアル通信(UART)はその典型ですよね。
どうなってるのかなーと見てみたら、なんかえらく複雑なんですが。
詳しいことはデータシートを確認して欲しいが、だいたいこういうこと。
- 18ms以上のローパルスをマスターから送る
- センサーからLo:80us, Hi:80us出力される
- 40bitのデータを0はLo:50us, Hi:26~28us、1はLo:50us, Hi:70usとして出力
- センサーから52us以上のローパルスを出力して、Hi状態が続く
なんだこれ。
Raspberry PiでDHT11からデータを取得するプログラムの実装を見てみると、
GPIOでピンの状態を取得し続けて、0が連続する数、1が連続する数を数えて、
0のカウント数と1のカウント数、どちらが多いかでデータが0か1か判定する仕組みになっているようだ。
ひたすらGPIOの値を読み続けるのがちょっとなぁとは思うんだけど、
Raspberry Piのプログラムとしては案外実装しやすいようだ。
とはいえ、取得失敗することも多いようで、あまり完成度は高くないのかなぁ。
UARTが線1本で通信ができるというのは、便利そうだけど、いくつか難点がある。
その最たるものが、送受信双方のクロック精度が要求されるということ。
マイコン内蔵のCR発振回路を使って、UARTで通信しようとしたこともあるが、うまくいかなかったこともある。
CR発振回路は温度による変動も大きいから、常温では通信できたが、温度が変化するとダメということもあるかも。
その点ではSPIやI2Cのような、クロックとデータの2本以上の信号線を使う方式は扱いやすい。
これは、マスター側が発生させたクロックに応じて、スレーブ側が出力すればよいだけだから。
おそらく、DHT11の通信方式は、1本の線で全て完結するということを重視したんだろうと。
SPIだと典型的にチップセレクト・クロック・データの3本の線が必要である。
複数のデバイスを接続する場合、チップセレクトはデバイスごとに必要、クロック・データは複数で共用できる。
I2Cはクロック・データの2本で、複数のデバイスをぶら下げることが出来る。
ただ、デバイスごとにアドレスの設定が必要なので、その点では不便かなと。
これが1本で済めばやっぱり便利だろということである。
LoとHiが連続する時間が長い・短いぐらいの判別がつけばよいのだから、
マスター・センサー双方のクロックに10%ぐらい誤差があっても全く問題ないだろう。
ただ、OSなしのマイコンで動かすことを考えると、GPIOの状態を読み続けると、
通信中マイコンを占有し続けて大変かなぁ、とか思ってしまうよね。
UARTとかSPIとか、マイコンのペリフェラルで対応している通信方式ならば、通信中は手放しで済む。
ところが、DHT11のような特殊な変調方式だと、どうしてもソフトウェアで復調しなければならない。
どうせこのデバイス、温湿度の更新周期が2sおきというのだから、ゆっくり送ればよいのである。
あと10倍ぐらい長いパルスだったら、数百usおきに割り込みとかそんなんでもいけたかなぁと。
温湿度測定に使える安価なデバイスは他にもいろいろあって、I2C対応だとAM2320というのがあったりするようだ。
でもDHT11に比べるとだいぶ高いですね。流通量の差か。