DHT11 という温湿度センサーを読む
DHT11 という比較的価格の安い(ただし精度はいまいちな)デジタル温湿度センサーがあるので読んでみた。1-wire ライクな (1-wireではない) プロトコルで、データシートを読みながら頑張って読む感じ。
- 18ms 以上バスをローにすることでデータ送信を行わせる
- 18ms のローを送信したあと、入力状態に変えて 50us ロー + 50us ハイを待つ (初期メッセージ)
- そのあと 40回 50us ロー + (28us or 70us ハイ) のセットが送られてくる。70us のほうが「1」のビット
だいたいすぐできるんだけど、waiting for slope up と書いてあるところのディレイを入れないと、バスがハイになる前に loop_until_bit_is_clear してしまって状態がズレてしまうので、立ちあがる時間を適当に待つ必要があった。
湿度・温度それぞれ16bitが送られてくるんだけど、下位8bitは、このモジュールの場合、どちらも全部0しか返ってこない。のでコードでは無視している。下位 8bit はAM2302とか精度が良いがコストが高いというモジュールがあって、そちらの場合使われるっぽい。
あと、送られてくるデータは前回測定時のデータなので、2回読み出しを行って2回目を採用しないと、正しいデータにならない。連続して読むなら関係ない。
int main(void) {
logger_init(9600);
setup_io();
printf("initializing...\r\n");
sei();
printf("initialized\r\n");
uint8_t i, j, us;
int16_t humidity, temperature;
uint8_t res[5];
set_input(DDRD, PD7); clear_bit(PORTD, PD7); // hi-z
for (;;) {
set_output(DDRD, PD7); clear_bit(PORTD, PD7);
_delay_ms(20);
set_input(DDRD, PD7); // hi-z
// waiting for slope up
_delay_us(5);
// waiting for slave initial response
loop_until_bit_is_clear(PIND, PD7);
loop_until_bit_is_set(PIND, PD7);
loop_until_bit_is_clear(PIND, PD7);
for (i = 0; i < 5; i++) {
for (j = 0; j < 8; j++) {
us = 0;
// 50us
loop_until_bit_is_set(PIND, PD7);
while (bit_is_set(PIND, PD7)) {
us++;
_delay_us(1);
}
res[i] <<= 1;
if (us > 50) { // 0: <28us 1: <70us
res[i] |= 1;
}
}
}
printf("%02x %02x %02x %02x %02x\r\n", res[0], res[1], res[2], res[3], res[4]);
if (( (res[0] + res[1] + res[2] + res[3]) & 0xff) == res[4]) {
humidity = res[0];
temperature = res[2];
printf("%d%%RH %dC\r\n", humidity, temperature);
} else {
printf("invalid data\r\n");
}
_delay_ms(5000);
}
} 信号全体
最初の長いロー部分が、AVR 側からのローで 18ms ある。その後、ちょっとハイになってるところは、センサー待ちの部分、そして 50us ロー・50us ハイに続いてデータが流れてくる。目で見てビット読める感じでたのしい。
立ちあがり時間
これは 18ms 待ちあとで AVR 側を入力に切り替えてハイインピーダンス状態にした直後の立ちあがり。立ちあがりにちょっとかかっていて、その後11usぐらい待ち時間がある。
参考
DHT22 というプロトコル互換デバイスについてのものがあったのでコードほぼそのままです。
関連エントリー
- RC サーボの制御 cho45 ★ 4.0 / 5.0 cho45 いくつかサーボモータを購入していたのだけど、ようやく試した。持っているのは上記 SG90 と...
- AD9850 DDS モジュール ebay で800円ぐらいで買ったものです。 この手のモジュールにはAD9851(源クロック6倍周波数逓倍器付き)のものとAD9850のもの...
- AD9851 DDS モジュール AD9850 DDS モジュール に続き AD9851 で、別基板バージョンのものです。 ジャンパとかが一切ない簡略版?なのか進化版?でしょ...
- 任意固定小数点→浮動小数点変換スニペット I2Cセンサーとかを扱うと固定小数点表現によく出会う。が、固定小数点のままだと計算がめんどうなので、とりあえず浮動小数点に変換しときたいとい...
- Ubuntu LTS 16 → 18 → 20 一応バックアップ sudo parted -l Model: Virtio Block Device (virtblk) Disk /dev...

