温度・湿度を測定するのに、本HPで度々使っているDHT11と言うセンサが有ります(下図)。
DHT11は独自規格の1線式シリアル通信なので、I/Oポートが1本あればデータを読み出すことができるし、温度・湿度データを計測可能な、とても使い勝手の良いセンサです。ただ、いくつか使い難い点もあって、「もう一息💨」なのでした。以下に挙げて解説します。
DHT11使用における難点:
電源電圧定格問題は、いつもの事ながらレベルシフタ(L/S)を挟むくらいしか手が無いので、放置します。今回テーマとして取り組むのは、2)、3)についてです。
ここでは、328duino(下図、およびリンクを参照)を使って、DHT11から読み出した温度・湿度データをI2C経由アクセス可能な、「I2Cインターフェイス温度・湿度センサ」にして見ようと思います。
言い換えると、間に328duinoを挟むことで、DHT11の通信インターフェイスをI2Cに変換するのです。
通信規格がI2Cに変換できれば、I2C通信をサポートしたM5StickC PlusのUIFlowや、Raspberry PiのRaspbian OSからでもアクセス可能となります。
まずは、DHT11のおさらいからですが、DHT11からデータを読み出すと、一回前に読み出した時に計測したデータを送信してきます(「第7回 AM2302の制御手順を仕上げる」)。
※上にリンクした記事は、DHT11と姉妹品となる、AM2302と言うセンサについて言及した物ですが、DHT11でも同じです。
DHT11には、データを読み出した後、次のデータ読み出しが可能になるまでのサイクルタイムが規定されています。このサイクルタイム中に、次回の読み出しに備えて温度・湿度データの計測を実行しています。
つまり、読み出しプロトコルが始まると:
次に読み出し要求があると、前回計測しておいたデータを返してくるので、今現在のデータを取得したい場合、2回連続で読み出して二度目のデータを選択する必要があるのです。
DHT11のサイクルタイム=2sなので、2回読み出すのに2〜4[s]の時間を要します。人間時間では大した時間ではないのですが、マイコン時間では、かなり長い時間です。その間、他の処理を実行できませんから。
I2C通信でデータを読み出す様にインターフェイスを変換した場合、暫く温度・湿度データを読み出さなかった後で、「現在の温度・湿度を読み出したい場合は2回読み出してください」と、言うのも、酷い話です。やはり、読み出したデータは、今現在の温度・湿度であるべきです。
以下のような動作にしようと思います。
定期的に読み出すことで、都度、現時点の温度・湿度データを読み出すことができるようになるのですが、一方で、折角定期的に読み出しておいても、I2Cから読み出しが無ければ、ほとんどのデータを捨てることとなって勿体ないです。
そこで、I2Cから読み出しが無くても、定期的に読み出したデータの移動平均を取ることで、見かけ上の解像度を水増しして読み出すことができるオーバサンプリングモードを設けようと思います。
I2Cからアクセスできる設定レジスタに、サンプリングレートとオーバサンプル数を設定可能なレジスタを持っておき、設定値に従って粛々と計測し続けるようなプログラムを328duino上で実行しておきます。
DHT11の通信インターフェイスを、独自の1線式シリアル方式からI2C通信にブリッジするため、328duinoを制御マイコンとして使います。一旦、328duinoがDHT11のデータを読み出し、それをI2Cスレーブとなってインターフェイスすることで、他のI2C仕様で接続するマイコンなどとデータをやり取りすることができるようになります。
同時に、定期的にデータを読み出してフィルタ(移動平均)をかけることで、小数点以下の解像度を上げ、I2Cで読み出したデータが、ほぼ現在時刻の測定データとなります。
なにより、328duinoを使うのは久しぶりです。以下記事などを参考に、328duino(第二形態)をご準備ください。それがスタートとなります。
「#9-5 ブレッドボードにArduinoっぽい物」
「#9-9 328duinoをArduino IDEに組み込む」
今回のテーマでは、328duino(第二形態)を使って、DHT11を接続すれば終わりなので、回路は以下図の通りとなります。
これまで、328duinoを使った電子工作(本HP)では、「○○化328duino」とシリーズ化してきました(以下記事を参照)。
「#13-4 シリアルEEPROM化328duino」
「#13-7 赤外線リモコン化328duino(試作編)」
「#19-2 オルゴール化328duino」
「○○化328duino」では、1つの170タイポイントミニブレッドボード(下図)上に、328duinoと周辺回路を押し込んで、小さなモジュールを実装してきました。
今回も、DHT11まで含めて1個のミニブレッドボードに集積して、「I2C温度・湿度センサ化328duino」を実装します。
17行しかないミニブレッドボードに、28ピンDIP(片側14ピン)のATmega328P-PUを実装すると、それだけで一杯一杯なので、Power Pointを使って、ミニブレッドボードに実装するプランを立てて臨みました(下左図)。
上右図は、結果としての完成図です。
DHT11モジュールは、3ピンのピンヘッダでインターフェイスします(上図、中央下方)。ピン配置は、正面左からSDA,VCC,GNDの順なので、VCC,GND端子をATmega328のVCC,GNDの端子配置に合わせてミニブレッドボードに実装し、その時1線式シリアル通信SDA端子が接続されるPD4_D4端子(ATmega328の6番ピン)で、通信を行います。
※もし、ピン配置の異なるモジュールを使う場合は、適宜、プログラムと回路を変更してください。
ミニブレッドボードには十分な空き領域が有ったので、SPI書き込み回路(SCK,MISO,MOSI)も予約してあります。今回は、USB⇔UART変換モジュール(FTDI等)を使って、Arduino IDEからUSB経由で書き込み可能な様に、シリアル書き込み回路(DTR,TXO,RXI、R1,C3等)を実装してあるので、そちらを使います。
従って、SPI接続端子(SCK,MISO,MOSI)はオプションです。Arduino as ISP等を使ってSPI書き込みしないのなら、接続不要です。
USB⇔UART変換モジュール(FTDI等)を使うので、シリアルモニタを使ってデバッグすることも可能であり、お勧めです。
世の中に出回っている、I2C接続のセンサやモジュールには、スレーブアドレスが選択可能となっている物を多く見かけます。外部端子設定で、2〜4個のアドレスから選択可能なモジュールが多い様です。
I2C通信規格はバス形式になっていて、1対のI2C通信バス(SCL,SDA)上に、複数のマスタデバイスや複数のスレーブデバイスを接続することが可能です。この時、通信相手のスレーブデバイスを指定するため、スレーブアドレスを使います。
このため、I2Cバス上のスレーブモジュールは、ユニークなスレーブアドレスを持っている必要があるのです。
I2C温度・湿度センサ化328duinoでも、I2CA1,I2CA0端子に適切なI/Oポート(空き端子)を割り当てておき、起動時の端子状態によって、スレーブアドレスを変化させる事とします。
pinMode (pin_I2CA0, INPUT_PULLUP);
pinMode (pin_I2CA1, INPUT_PULLUP);
// i2c slave address
i2c_slv_adr=i2c_slv_base;
i2c_slv_adr += (digitalRead (pin_I2CA1)==LOW)? 0: 2;
i2c_slv_adr += (digitalRead (pin_I2CA0)==LOW)? 0: 1;
後付けでスレーブアドレスを変更する必要のない時には、I2CA1,I2CA0端子を処理しなくて済むように、pinMode()関数でINPUT_PULLUPを指定してあります。端子を開放状態で放置しても{I2CA1,I2CA0}=0b11となって、不都合なく使用する事が可能です。
1つのシステム中に、複数の温度・湿度センサを持ち、I2Cバス上に接続する場合や、不運にも、全く異なるモジュールのスレーブアドレスが一致してしまった場合等、I2CA1,I2CA0端子を設定して異なるスレーブアドレスにすることで、同一のI2Cバス上に接続できるようになるのです。
今回のお買い物は、以下の通りです。
400タイポイントや830タイポイントなど、大きめなブレッドボードも必要な時はあるのですが、170タイポイントのミニブレッドボードは、機能ブロック毎に分割して実装した後で、ミニブレッドボード同士を接続して大きな回路を構築することもできるので使い勝手が良いのです。
ミニブレッドボードを使って機能ブロック毎に実装した回路は、そのまま崩さずに置いておくと、後で使い回せたりするので、最近だんだん足りなくなってきてしまい、追加購入してしまいました。
以上、ハードウェア設計が終了した所で、残りは次回に回します。次回、ソフトウェア設計を進めて完成させ、動作確認を兼ねた実験まで終了させようと思います。