前回で BMP180・DHT11・Grove Light Sensor の正体が分かりました。今回はこの3つを同時に繋いで、実際にデータを取ってみます。
結論から言うと、DHT11 だけ動きませんでした。 この記事はその顛末です。
目次
3つ同時に繋いでみる
BMP180 は I2C(GPIO26/25)、Grove Light Sensor はアナログ(GPIO35)、DHT11 はデジタル1線(GPIO27)。使うピンが重ならないので、配線自体はそのまま足すだけです。
ライブラリは Adafruit のものを使いました。
lib_deps =
adafruit/Adafruit BMP085 Library@^1.2.4
adafruit/DHT sensor library@^1.4.7
書き込んで動かしてみると、こうなりました。
BMP180 初期化失敗。配線(3.3ピン給電・SDA/SCL)を確認してください
DHT11 を追加しただけなのに、無関係のはずの BMP180 まで動かなくなりました。
無関係な BMP180 が巻き添えを食う
診断ツールで確認すると、I2C バスは完全に沈黙していました。
SDA=26 SCL=25 応答なし(アドレスに NACK 126)
まだ使っていない GPIO32/33 に BMP180 を移してみると、あっさり復活します。
チップ ID 0x55 → BMP180(気圧・温度)
ところが、ここで DHT11 を接続し直すと、今度は GPIO32/33 まで同じように沈黙しました。同じことが2回起きたわけです。
これは「GPIO が壊れた」と考えたくなる状況です。実際、私も一度そう判断しかけました。
「壊れた」の前に確かめること
センサーを全部外して ESP32 単体にしてみました。異常はありません。そのまま BMP180 だけを GPIO32/33 に繋ぎ直すと、また普通に動きます。
本当に壊れているなら、こんなに簡単に復活しません。 この時点で「GPIO 故障」という仮説は捨てました。
繰り返し配線をいじる過程で、ブレッドボードの接触不良が起きていたのだと思います。診断ツールの出力を振り返ると、実はヒントがありました。
GPIO32/33 HIGH率 100% / 6% ← SCL だけ低い
SDA は 100%、SCL だけ 6%。片方だけ数値が違うのは、どちらか一方の線だけが半差しになっている、というサインでした。SCL の線を挿し直すと直りました。
同じ「応答なし」でも、内部の状態は一様ではありません。
| HIGH率 | 意味 |
|---|---|
| 100% / 100% | 正常、または接続済みで応答待ち |
| 0% / 0% | GND と短絡、または電源なし |
| 中間・左右で不一致 | 未接続、または片方だけ接触不良 |
3番目のパターンに気づけたのは、診断ツールが2本のピンの数値を別々に出していたからです。まとめて「フローティング」とだけ表示していたら見逃していたと思います。

DHT11 だけが最後まで応答しない
BMP180 の問題が片付いたところで、DHT11 単体でもう一度試しました。BMP180 は完全に外し、DHT11 だけを ESP32 に直接繋ぎます。
結果は変わりません。
DHT11 : 読み取り失敗(配線 or タイミングを確認)
ただ、電気的には正常でした。
GPIO27 (DHT11 DATA) HIGH率 100% プルアップ検出 → 配線と電源は生きている(応答するかは別)
配線も電源も生きているのに、ライブラリでの読み取りだけが失敗する。 ここで困りました。電気的なチェックはパスしているので、「配線ミスではない」というところまでは分かります。でも、それ以上は普通の方法では確かめようがありません。
ライブラリを介さず直接見る
DHT11 は、こちらが DATA 線を18ミリ秒ほど LOW にしてリリースすると、センサー側が 80マイクロ秒 LOW → 80マイクロ秒 HIGH という短いパルス(ACK)を返してくる、という手順で通信します。ライブラリはこれを解釈してくれますが、そもそも ACK が返ってきているのかどうかは、ライブラリのエラーメッセージからは分かりません。
そこで、起動信号を送った直後の5ミリ秒だけ、レベルの変化を数えるだけの簡単なコードを書きました。
pinMode(DHT_PIN, OUTPUT);
digitalWrite(DHT_PIN, LOW);
delay(20);
digitalWrite(DHT_PIN, HIGH);
pinMode(DHT_PIN, INPUT);
int edges = 0;
int last = digitalRead(DHT_PIN);
const unsigned long start = micros();
while (micros() - start < 5000) {
const int now = digitalRead(DHT_PIN);
if (now != last) { edges++; last = now; }
}
結果です。
起動信号後 5ms のレベル変化: 0 回 → 応答なし
5回試して、5回とも0でした。ACK パルスが一度も返ってきていません。 配線と電源は生きているのに、センサー自身が何も答えない。これはもう、モジュールの故障と判断するしかありませんでした。
安価な DHT11 モジュールには、こうした個体不良が一定の確率であるようです。今回は諦めて撤去しました。湿度は測れなくなりましたが、気圧・温度・照度の3種類でひとまず進めることにします。
もう一つの落とし穴:接続していないのに値が出る
DHT11 を諦めて BMP180 と光センサーの2つに戻したとき、もう一つ見落としに気づきました。
光センサーをまだ繋いでいない状態で実行したところ、こう出力されていたのです。
照度 : 582 (raw, 0-4095)
繋いでいないのに、それらしい値が出ています。 しかも実行するたびに 295、1241、857 と変動するので、一見「センサーが反応している」ように見えてしまいます。
原因は単純でした。GPIO35 に何も繋がっていないと、ピンは電気的に浮いた状態(フローティング)になります。浮いたピンは電荷を保持できないため、近くの配線からの静電結合やちょっとしたノイズを拾って、読むたびに違う値になります。それをそのまま「照度」として出力していたわけです。
BMP180 のほうは bmp.begin() が失敗を返すので、接続の有無をコードで判定できました。でも光センサーの analogRead() は、繋がっていようがいまいが何かしらの数値を返してしまいます。 この違いに気づかず、最初は「センサーの値が変動している」と誤って解釈してしまいました。
対処は、診断ツールで使っていたのと同じ考え方です。何度か連続で読んで、値のばらつき(最大 - 最小)を見ます。
if (v < lightMin) lightMin = v;
if (v > lightMax) lightMax = v;
...
const int lightSpread = lightMax - lightMin;
if (lightSpread > 500) {
Serial.println("照度: 未接続(ばらつき大、フローティングの疑い)");
}
ばらつきが大きければ未接続と判定し、実際に光センサーを繋いでから確認すると、値は安定しました。
照度 : 2615 (raw, 0-4095)
照度 : 2611 (raw, 0-4095)
照度 : 2621 (raw, 0-4095)
実測値を扱うコードは、値が取れることだけでなく、値そのものが妥当かどうかも確認する必要がある。 今回いちばんの収穫はここだったかもしれません。
最終的に得られたデータ
BMP180 と Grove Light Sensor の2つで、気圧・温度・照度が安定して取れるようになりました。
気圧 : 1009.7 hPa
高度 : 29.9 m
温度 : 28.9 C
照度 : 2615 (raw, 0-4095)
次回
センサーからのデータが揃ったので、次はいよいよ AWS 側です。IoT Core を使うか、API Gateway + Lambda にするか、まだ決めていません。ここでアーキテクチャを決めて、実際にデータを送るところまで進めます。