アウトドア系YouTubeを見ていると、よく「ただいまの気温15度です」なんてセリフと共に大きなデジタル温度計が映されます。
自分の時計プロトレックでも温度センサーが付いているので測定はできますが腕に装着しているので体温に近い温度になっています。気温を測ろうと思ったら腕時計を外してしばらくその辺に吊るしておいて気温と同じになるまで待つ必要があります。
デジタル温度計を買えば早いのはわかっていますが、やっぱり趣味の電子工作で、と考えました。
I2C通信で温度・湿度を測ってくれるAHT25というセンサが秋月電子で350円で売っていましたのでポチリました。
結果表示用に小型の液晶表示器も720円で購入。昨日とりあえず完成したので掲載。
AHT25のデータシートを秋月電子のその商品説明リンクから取得してよく読みます。が、なんとも中途半端な感じです。
「初期化コマンド0x71を送信して返ってきた値と0x18の論理積を取って、0x18じゃなかったら0x1B,0x1C,0x1Eレジスタを初期化してください、詳細は私たちのWEBページで。」なぜレジスタ詳細をデータシートに乗せないのか意味不明です。
手順的には、
1.初期化(0x71レジスタを読む)、
2.測定トリガをかける(0xACレジスタに0x33、次に0x00を書き込む)、
3.連続した7バイト(センサ状態8bit、湿度20bit、温度20bit、CRC8bit)を読み込む、
ということらしいです。
試験的に、0x71を指定して1バイト読み込みをすると0x18が返ってきたので、プログラム上はそのまま残しました。
測定トリガをかけて80ミリ秒以上待ってから7バイト読み込みをかけると何かしら値が返ってくるのでそれを温度・湿度に変換して液晶表示器に出せばOKです。最初、生のデータとして温度が 0x57D1E と返ってきたので16進数でそのまま表示しました。データシートにある計算式(T =D / 2^20 * 200 - 50)通りに電卓をたたいてみると、
0x57D1E=359710(10進数)、2^20=1048576、なので T=359710/1048576*200-50=18.6092…
部屋の温度計も大体19度を指しているので合っていそうです。
あとは楽勝かと思いきや、ここからが大変でした。
使ったPIC12LF1822のプログラム領域はたったの2048ワード、I2C用のライブラリやLCD(液晶)用のライブラリによって領域がひっぱくしています。20bitの値を扱うには long int の変数を使わなければならないのと、long int 浮動小数点割り算関数が組み込まれる必要があります。普通に上記の計算式を記述してコンパイルをすると no space for xxx(関数名や変数名) のエラーラッシュでどうにもなりませんでした。
小数点が出るような割り算はできないことがわかったので計算方法で回避するしかありません。温度や湿度を整数で表示すれば簡単ですが、せっかく20bit精度のセンサを買って、結果が整数値なのは寂しすぎます。
割り算の代わりにシフト演算を使えば回避できるかと思いましたが、16bit以上のシフトはできません、とエラー。
最終的に数式を変形して精度を12bitまで落として、10倍の値で計算して整数除算、整数余りの2項に結果を格納する方法をとりました。プログラム作法的にはよくないのですが、使い回しのきく変数はすべて使い回ししました。long int 変数3つ追加でコンパイル通らない(領域不足)プログラム、PIC書き込みのときにプログラム内を見てみたら空きが16ワードくらいしか残っていませんでした。
MPLAB X IDE V2.3 を使っているのですが、sprintf の書式指定にも悩まされました。おそらくコンパイラのバグだと思います。
sprintf(buf, "%d %d", 20, 5); の出力が ”20 0” になってしまいます。%x %x では起きない現象で、%d 2個目が必ず0になってしまいます。以下のようなコードが書きたかったのに2行に分けざるを得ませんでした。以下のコードは gcc では問題なく -21.5 と表示されます。
(追記)----------
sprintf に渡す整数のサイズを、書式指定してもよいらしく(しなくてもよい) 、h(エイチ:short とみなす)と、l(エル:long とみなす)の2種類があります。MPLAB X の C言語は、h はサポートしていませんが(無効)、l をサポートしており、具体的には
sprintf(buf, "%3ld.%1ld C", i, j);
と書けば、整数引数を long とみなして正しい出力になりました。
----------
ほぼ完成したところで、動作をウォッチドッグタイマ(16秒)付きのスリープ形態に変更しました。
電源投入後、1秒程度で最初の温度・湿度表示、→スリープモード→16秒後にアウェイク再測定と表示→スリープモード 繰り返しで節電します。センサは測定時3mW(ミリワット)程度電力消費があるので微小ながら温度が上がるため2秒以上置きの測定がおすすめとあったので、ウォッチドッグタイマ動作を思いつきました。
以下プログラム。