ESP32-DevKitCのI2Cバスを10m先のベランダまで延長してI2Cアドレスを変更したBME280センサモジュール(0x77)を接続、外気の温湿度、気圧の変化を遠隔モニタした際のメモです。LTC4331モジュールとLANケーブルを使ってI2C信号と電源線を延長することで安定したデータ収集ができました。
追加で準備したパーツと結線図(2022/4/21訂正)
準備したパーツ
ネット通販(秋月電子通商、ストロベリー・リナックス、 Amazon など)でパーツを集めてブレッドボードで組み立てました。
屋外の温湿度・気圧測定用のBME280センサモジュールと測定結果を表示する20文字X4行の2004 LCDを追加しました。屋外設置のセンサとの通信のため、ストロベリー・リナックス製のLTC4331 絶縁型I2C延長モジュールとLANケーブルでI2Cバスを延長します。
それ以外のパーツはESP32-DevKitCと DS3231を使ったRTC時計& BME280を使った温湿度・気圧計を20文字x4行LCDに表示:環境モニタ(2)と同じです。
# | 今回、追加したパーツ | 個数 |
1 | LTC4331 絶縁型I2C延長モジュール ※マスターとスレーブの2個セット | 1 |
2 | LANケーブル(RJ45)10m ※LTC4331マスターとスレーブ間の接続用 | 1 |
3 | BME280 温湿度・気圧センサーモジュール Vin、I2Cレベル変換回路付き | 1 |
4 | 2004 LCDモジュール 20×4キャラクタ 青 I2C I/F モジュール、バックライト付き、 バックライト調整用半固定ボリューム付き | 1 |
5 | サンハヤト ニューブレッドボード SAD-101 ※屋外のBME280モジュール組み立て用 | 1 |
6 | ジャンパーワイヤ ※屋外のBME280モジュール組み立て用 | 適量 |
# | 環境モニタ(2)で準備したパーツ | 個数 |
1 | ESP32-DevKitC ESP-WROOM-32開発ボード | 1 |
2 | DS3231SN I2C RTCモジュール | 1 |
3 | 2004 LCDモジュール 20×4キャラクタ 青 I2C I/F モジュール、バックライト付き、 バックライト調整用半固定ボリューム付き | 1 |
4 | I2Cバス用双方向電圧レベル変換モジュール (PCA9306) | 1 |
5 | XL4015 可変DC-DCステップダウンコンバータ 3個入り | 1 (手持ち) |
6 | DC-POWER-JACK基板 | 1 |
7 | サンハヤト ニューブレッドボード SAD-01 | 1 |
8 | ジャンパーワイヤ | 適量 |
9 | USBケーブル (USB A オス to microB オス) | 1 (手持ち) |
10 | コイン形リチウムイオン2次電池「LIR2032」 4個入り | 1 |
11 | スイッチングACアダプター 9V 1.3A 100~240V | 1 |
12 | BME280 温湿度・気圧センサモジュール Vin、I2Cレベル変換回路付き | 1 |
結線図
各モジュール間をジャンパーワイヤで接続した際の結線図です。網掛け部分はCO2センサ、microSDカードスロットなど拡張予定箇所です。
BME280、2004 LCDモジュール、LTC4331絶縁型I2C延長モジュールを各々2個使うのでI2Cアドレスが重複しないように設定変更を行います。
BME280の I2Cアドレスの変更
BME280を屋内用(0x76)と屋外用(0x77)として2個接続します。
デフォルトのI2Cアドレス(0x76)では、BME280チップのSDO線はプリントパターンでGNDにつながっています。(黄色の矢印部分、プリントパターンはロットによって異なるものがあるので要確認)。
GNDにつながるプリントパターンをカットして、SDOと右側のVDDIOをハンダ付けしてショートすると0x77に設定完了です。
20文字×4行キャラクタLCDのI2Cアドレス変更
追加する20文字×4行キャラクタ 2004 LCDのスレーブアドレスを変更してI2Cバスに接続します。
購入した2004 LCDモジュール基板に搭載されているICはPCF8574TなのでデフォルトのI2Cアドレスは0x27。I2CアドレスはA0、A1、A2の3つのソルダジャンパをショートするかオープンにするかで0x20~0x27に変更可能です。今回、A0パターンをはんだ付けしてショートしたので、I2Cアドレスは 0x26です。
LTC4331絶縁型I2C延長モジュールの組み立て
I2Cは複数デバイスを2線で接続できて便利なのですが、実用的な通信距離はデバイス間や基板間程度の近距離に制限されます。LTC4331絶縁型I2C延長モジュール(マスタとスレーブ用の2個で1セット)を使うことで、I2C信号を差動通信方式に変換してLANケーブルで延長します。今回はリビングからベランダまで手持ちのLANケーブルで10m延長しました。
LTC4331モジュール説明書の手順でモジュール基板上のジャンパーパターンをはんだ付けしてショートすることでマスタ/スレーブ設定、プルアップ抵抗の有効/無効などを設定します。
ESP32-DevKitCから I2Cバス用双方向電圧レベル変換モジュールを介してI2C(SCL、SDA)、5V、GNDの4線をLTC4331モジュール(マスタ側) –> LANケーブル –> LTC4331モジュール(スレーブ側) –> BME280モジュールへと接続します。識別しやすいように、I2C(SCLは緑線、SDAは白線)、5Vは赤線、GNDは黒線です。
モジュールのI2Cアドレスの確認
ArduinoサイトにあるI2CアドレスをスキャンするスケッチArduino Playground – I2cScannerを実行すると、I2Cバス上に6個のデバイスが検出されました。
LTC4331モジュール + LANケーブルで10m延長した屋外設置のBME280のI2Cアドレスも 0x77 と認識できています。
# | パーツ | アドレス I2C | 備考 |
1 | 2004 LCD | 0x26 | 追加 |
2 | 2004 LCD | 0x27 | デフォルト |
3 | DS3231 | 0x57 0x68 | EEPROM AT24C32 RTC |
4 | BME280 | 0x76 | デフォルト |
5 | BME280 | 0x77 | 追加 |
開発ツールarduino-esp32をインストール
arduino-esp32のインストール手順を別ページに纏めました。
スケッチ1:BME280センサ2個で屋内と屋外の温湿度・気圧をシリアルモニタに出力
屋内用のBME280センサ(0x76)と屋外用のBME280センサ(0x77)の両センサから測定データを取得してシリアルモニタに出力します。
ライブラリとしてGitHub掲載の adafruit/Adafruit_BME280_Library と adafruit/Adafruit_Sensor を利用させていただきました。このライブラリのサンプルスケッチを使って、2つの BME280センサからデータ取得できるように修正したスケッチ1です。
ESP32_BME280x2_com.ino
※ここをクリックするとコード表示を開閉できます。
#include <Wire.h>
#include <Adafruit_Sensor.h> // https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h> // https://github.com/adafruit/Adafruit_BME280_Library
Adafruit_BME280 bme; // 屋内用センサ
Adafruit_BME280 bme2; // 屋外用センサ
float temp;
float pressure;
float humid;
float temp2;
float pressure2;
float humid2;
void setup() {
Serial.begin(115200);
bool status;
status = bme.begin(0x76);
while (!status) {
Serial.println("屋内BME280 sensorが使えません");
delay(1000);
}
status = bme2.begin(0x77);
while (!status) {
Serial.println("屋外BME280 sensorが使えません");
delay(1000);
}
}
void loop() {
temp=bme.readTemperature();
pressure=bme.readPressure() / 100.0F;
humid=bme.readHumidity();
Serial.print("屋内( ");
Serial.print(temp);
Serial.print(" *C ");
Serial.print(pressure);
Serial.print(" hPa ");
Serial.print(humid);
Serial.print(" % )");
temp2=bme2.readTemperature();
pressure2=bme2.readPressure() / 100.0F;
humid2=bme2.readHumidity();
Serial.print(" 屋外( ");
Serial.print(temp2);
Serial.print(" *C ");
Serial.print(pressure2);
Serial.print(" hPa ");
Serial.print(humid2);
Serial.println(" % )");
delay(1000);
}
スケッチ1の実行結果です。屋内と屋外に設置したBME280の温湿度・気圧データが取得できました。
スケッチ2:Tera Termでシリアルポート接続して屋外の温湿度、気圧データをPCで記録
2つのBME280モジュールで屋内とLANケーブル延長した屋外の温湿度、気圧を測定しました。手順はESP32-DevKitCとBME280で測った温湿度・気圧データをTera Termのログに記録、EXCELでグラフ化:環境モニタ(3)と同じです。
Tera Termが文字化けする時は、 Tera Termのシリアルポート設定とスケッチで定義した通信速度が一致しているかを確認します。
簡易的なデータロガーとして使えるようにArduino IDEのシリアルモニタ出力に代わってTera Termでシリアルポートに接続してログとしてCSV形式でPCに保存。そのファイルをEXCELで読み込んでグラフ化します。CSV形式でシリアルポートに出力するスケッチ2です。
ESP32_BME280x2_tera-term.ino
※ここをクリックするとコード表示を開閉できます。
#include <Wire.h>
#include <Adafruit_Sensor.h> // https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h> // https://github.com/adafruit/Adafruit_BME280_Library
Adafruit_BME280 bme; // 屋内用センサ
Adafruit_BME280 bme2; // 屋外用センサ
float temp;
float pressure;
float humid;
float temp2;
float pressure2;
float humid2;
void setup() {
Serial.begin(115200);
bool status;
status = bme.begin(0x76);
while (!status) {
Serial.println("屋内BME280 sensorが使えません");
delay(1000);
}
status = bme2.begin(0x77);
while (!status) {
Serial.println("屋外BME280 sensorが使えません");
delay(1000);
}
}
void loop() {
temp=bme.readTemperature();
pressure=bme.readPressure() / 100.0F;
humid=bme.readHumidity();
Serial.print(temp);
Serial.print(",");
Serial.print(pressure);
Serial.print(",");
Serial.print(humid);
Serial.print(",");
temp2=bme2.readTemperature();
pressure2=bme2.readPressure() / 100.0F;
humid2=bme2.readHumidity();
Serial.print(temp2);
Serial.print(",");
Serial.print(pressure2);
Serial.print(",");
Serial.println(humid2);
delay(1000);
}
スケッチ3:DS3231時計とBME280で屋内、屋外の温湿度・気圧を2個のLCDに表示
BME280センサ2個で屋内と屋外の温湿度・気圧をシリアルポートに出力するスケッチ2に、NTPサーバから取得したJST時刻とRTCモジュールDS3231との時刻合わせする時計のスケッチを合体して、20文字x4行表示のLCDモジュール2個に表示するスケッチ3です。
Tera Termで屋外の温湿度・気圧の測定結果を記録するシリアルポート出力のスケッチも残してあるので、必要な時にはPCとUSB接続してTera Termのログとして記録できます。
ESP32_BME280x2_LCDx2.ino
※ここをクリックするとコード表示を開閉できます。
#include <Wire.h>
#include <WiFi.h>
#include <time.h>
#include <LiquidCrystal_I2C.h> // https://github.com/johnrickman/LiquidCrystal_I2C
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include <esp_sntp.h>
#include <Adafruit_Sensor.h> // https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h> // https://github.com/adafruit/Adafruit_BME280_Library
DS3232RTC myRTC(false);
LiquidCrystal_I2C lcd(0x27, 20, 4); // DS3231時計、屋内BME280表示
LiquidCrystal_I2C lcd2(0x26, 20, 4); // 屋外BME280表示
Adafruit_BME280 bme; // 屋内センサ
Adafruit_BME280 bme2; // 屋外センサ
float temp;
float pressure;
float humid;
float temp2;
float pressure2;
float humid2;
// 2022/03/27:曜日の文字数を9文字固定に変更
const char* weekStr[7] = {"Sunday ","Monday ","Tuesday ","Wednesday","Thursday ","Friday ","Saturday "};
const char* ssid = "your ssid";
const char* password = "your password";
const char* ntpServer = "ntp.nict.jp";
const long gmtOffset_sec = 32400;
const int daylightOffset_sec = 0;
void setup() {
struct tm timeInfo;
Serial.begin(115200);
myRTC.begin();
lcd.init();
lcd.backlight();
lcd2.init();
lcd2.backlight();
// ----- DS3231時計 -----
//WiFi接続
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
lcd.print("."); // 進捗表示
delay(500);
}
// WiFi接続の表示
lcd.clear();
lcd.print("WiFi connected");
delay(2000);
lcd.clear();
// NTPサーバからJST取得
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
lcd.clear();
lcd.print("JST synchro.");
delay(2000);
lcd.clear();
// 内蔵RTCの時刻がNTP時刻に合うまで待機
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET) {
lcd.print(">"); // 進捗表示
delay(1000);
}
//内蔵RTC時刻 = NTP時刻の表示
lcd.clear();
lcd.print("Time matched");
delay(2000);
lcd.clear();
// 内蔵RTCの時刻の取得
getLocalTime(&timeInfo);
// 内蔵RTCの時刻をDS3231に時刻設定
setTime(timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec,
timeInfo.tm_mday, timeInfo.tm_mon + 1, timeInfo.tm_year + 1900);
myRTC.set(now());
//WiFi切断
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
// ----- BME280温湿度・圧力計 -----
bool status;
status = bme.begin(0x76);
while (!status) {
Serial.println("屋内BME280 sensorが使えません");
delay(1000);
}
status = bme2.begin(0x77);
while (!status) {
Serial.println("屋外BME280 sensorが使えません");
delay(1000);
}
}
void loop(void){
// ----- DS3231時計 -----
// RTCから時刻取得
tmElements_t tm;
myRTC.read(tm);
// 時計LCD表示
lcd.setCursor(0,0);
lcd.print(tm.Year + 1970);
lcd.print("/");
lcdzeroSup(tm.Month);
lcd.print("/");
lcdzeroSup(tm.Day);
lcd.print(" ");
lcd.setCursor(11,0);
lcd.print(weekStr[tm.Wday - 1]);
lcd.setCursor(0,1);
lcdzeroSup(tm.Hour);
lcd.print(":");
lcdzeroSup(tm.Minute);
lcd.print(":");
lcdzeroSup(tm.Second);
// ----- BME280温湿度・圧力計 -----
// 屋内センサ
temp=bme.readTemperature();
pressure=bme.readPressure() / 100.0F;
humid=bme.readHumidity();
lcd.setCursor(0,2);
lcd.print("PRESS1:");
lcd.print(pressure);
lcd.print("hPa");
lcd.setCursor(0,3);
lcd.print("T:");
lcd.print(temp);
lcd.print("'C / H:");
lcd.print(humid);
lcd.print("%");
// 屋外センサ
temp2=bme2.readTemperature();
pressure2=bme2.readPressure() / 100.0F;
humid2=bme2.readHumidity();
lcd2.setCursor(0,2);
lcd2.print("PRESS2:");
lcd2.print(pressure2);
lcd2.print("hPa");
lcd2.setCursor(0,3);
lcd2.print("T:");
lcd2.print(temp2);
lcd2.print("'C / H:");
lcd2.print(humid2);
lcd2.print("%");
//Tera Termログ出力用
Serial.print(temp);
Serial.print(",");
Serial.print(pressure);
Serial.print(",");
Serial.print(humid);
Serial.print(",");
Serial.print(temp2);
Serial.print(",");
Serial.print(pressure2);
Serial.print(",");
Serial.println(humid2);
delay(1000);
}
// ----- DS3231時計 -----
// 先頭のゼロ(0)を空白に置換
void lcdzeroSup(int digit)
{
if(digit < 10)
lcd.print(' ');
lcd.print(digit);
}
スケッチ3を実行すると、1台目のLCDにNTP時刻合わせのRTC時計と屋内設置のBME280の温湿度・気圧の測定結果、2台目のLCDに屋外設置のBME280の測定結果を表示します。
屋内、屋外の温湿度、気圧を測定してグラフ化
スケッチ3を使ってTera Termログとしてリビングとベランダの温湿度、気圧を6日間受信して記録しました。LTC4331モジュールとLANケーブルを使って、屋外に設置したBME280センサモジュールへのI2C信号と電源の伝送によって安定したデータ収集ができました。
BME280センサは高感度です。昼間の生活時間帯の人の動き(LCDを覘いた際の呼気など)や窓を開けての換気などで湿度や温度が瞬間的に大きく変化しました。
気圧は天候の移り変わりの影響で980〜1015hPa間で変化しましたが、同じ高度のリビングとベランダ程度では差異は無いです。