環境モニタリングや自動制御システムを構築する際、DHT11 温湿度センサーは低コストかつ簡単なインターフェースで非常に有用である。このセンサーは工場出荷時に校正済みであり、外部部品なしで動作可能。単一信号線(1-Wire)による通信方式を採用しており、最小限の配線とソフトウェア実装で温度・湿度データを取得できる。
ハードウェア仕様と内部構造
DHT11 は DHTxx シリーズの中でも広く使われるモデルで、温度範囲は 0~50°C(精度 ±2°C)、湿度範囲は 20~80% RH(精度 ±5%)をサポートする。ただし、サンプリングレートは 1Hz(1秒に1回の測定)に制限されている点に注意が必要である。
| 項目 | 仕様 |
|---|---|
| 動作電圧 | 3.0V ~ 5.0V |
| 最大消費電流 | 2.5mA |
| 湿度測定範囲 | 20~80% RH(±5%) |
| 温度測定範囲 | 0~50°C(±2°C) |
| サンプリング周期 | 1Hz(1秒間隔) |
| 外形寸法 | 15.5mm × 12mm × 5.5mm |
| 主な特徴 | 低コスト、内蔵校正、簡易接続 |
モジュール版 DHT11 には、信号線用の 10kΩ 上 pull 抵抗および電源ノイズ対策のためのバイパスコンデンサがすでに実装されているため、直接マイコンに接続可能である。内部には、NTC 熱敏抵抗による温度センサと、導電性ポリマーを用いた湿度センサが搭載されており、これらからのアナログ信号を内蔵 IC(8ビットプロセッサ)がデジタル変換し、シリアル形式で出力する。
ピン配置と初期化手順
DHT11 モジュールは以下の3ピン構成となっている:
- VCC: 電源(3.3V または 5V)
- GND: グラウンド
- DATA: 双方向データ信号線
電源投入後、センサーは約1秒間の安定化期間を必要とする。この間に通信を開始するとエラーが発生する可能性があるため、ソフトウェア側で適切な遅延を挿入する必要がある。
通信プロトコルとデータ取得ロジック
DHT11 はカスタム 1-Wire プロトコルを使用し、1回の通信で合計40ビット(5バイト)のデータを送信する。データ構造は以下の通り:
- バイト0: 湿度整数部
- バイト1: 湿度小数部(DHT11 では常に 0)
- バイト2: 温度整数部
- バイト3: 温度小数部(DHT11 では常に 0)
- バイト4: チェックサム(上記4バイトの合計の下位8ビット)
起動シーケンスとタイミング制御
ホスト(OrangePi ZERO 2)はまず DATA 線を少なくとも18ms間ローにすることで起動信号を送信する。その後、ラインをハイに戻し、入力モードに切り替えて DHT11 の応答(80μs のロー信号+80μs の準備信号)を待つ。このタイミングを正確に制御するために、以下のような関数を実装する。
void initDHT11(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
delay(1000); // 電源安定待ち
}
void requestDHT11(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(25); // 起動信号(>18ms)
digitalWrite(pin, HIGH);
pinMode(pin, INPUT);
// 内蔵プルアップを利用(オプション)
pullUpDnControl(pin, PUD_UP);
delayMicroseconds(35); // 応答待ち(20-40μs)
}
ここで使用される pullUpDnControl() は wiringOP ライブラリの関数で、入力ピンに対して内部プルアップ/プルダウン抵抗を有効化する。DHT11 モジュール自体に外部プルアップ抵抗が含まれているため必須ではないが、信号の安定性向上のために推奨される。
データビットのデコード
DHT11 は各ビットを「50μs のロー期間」+「可変長のハイ期間」で表現する。ハイ期間が約26–28μsならビット値は「0」、約70μsなら「1」となる。ソフトウェアでこのパルス幅をマイクロ秒単位で計測し、40ビット分を逐次読み取る必要がある。
データ受信後、チェックサムを検証して整合性を確認する。一致しない場合は通信エラーとみなし、再試行を行うのが一般的である。
データ読み取りの実装例
受信データは32ビット整数としてバッファに格納し、最後にチェックサムを個別に読み取るのが効率的である。以下に基本的な読み取りルーチンの骨子を示す:
uint32_t dhtData = 0;
void readDHT11(int pin) {
dhtData = 0;
for (int i = 0; i < 40; i++) {
while (digitalRead(pin) == LOW); // ロー期間スキップ
delayMicroseconds(30); // 中央付近でサンプリング
if (digitalRead(pin) == HIGH) {
dhtData |= (1UL << (39 - i)); // MSB first
while (digitalRead(pin) == HIGH); // ハイ期間スキップ
}
}
// チェックサム検証は省略
}
実際のアプリケーションでは、タイムアウト処理やエラーリトライ機構を追加することで、より堅牢な動作を実現できる。