Skip to content
まことの手帳
Go back

ESP32 でセンサーデータを AWS に送る #5 実測編

前回で 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本のピンの数値を別々に出していたからです。まとめて「フローティング」とだけ表示していたら見逃していたと思います。

最終的な配線。BMP180 と Grove Light Sensor が接続された状態

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 にするか、まだ決めていません。ここでアーキテクチャを決めて、実際にデータを送るところまで進めます。

参考リンク


Share this post on:

Previous Post
ESP32 でセンサーデータを AWS に送る #4 センサー特定編
Next Post
ESP32 でセンサーデータを AWS に送る #6 電源設計編