ESP32-DevKitCに温湿度・気圧センサBME280を屋内、屋外用に2個接続、LTC4331とLANケーブルでI2Cバスを10m延長:環境モニタ(4)

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)と同じです。

#今回、追加したパーツ個数
1LTC4331 絶縁型I2C延長モジュール
※マスターとスレーブの2個セット
1
2LANケーブル(RJ45)10m
※LTC4331マスターとスレーブ間の接続用
1
3BME280 温湿度・気圧センサーモジュール
Vin、I2Cレベル変換回路付き
1
42004 LCDモジュール 20×4キャラクタ 青
I2C I/F モジュール、バックライト付き、
バックライト調整用半固定ボリューム付き
1
5サンハヤト ニューブレッドボード SAD-101
※屋外のBME280モジュール組み立て用
1
6ジャンパーワイヤ
※屋外のBME280モジュール組み立て用
適量
#環境モニタ(2)で準備したパーツ個数
1ESP32-DevKitC ESP-WROOM-32開発ボード1
2DS3231SN  I2C RTCモジュール1
32004 LCDモジュール 20×4キャラクタ 青
I2C I/F モジュール、バックライト付き、
バックライト調整用半固定ボリューム付き
1
4I2Cバス用双方向電圧レベル変換モジュール
(PCA9306)
1
5XL4015 可変DC-DCステップダウンコンバータ
3個入り
1
(手持ち)
6DC-POWER-JACK基板1
7サンハヤト ニューブレッドボード SAD-011
8ジャンパーワイヤ適量
9USBケーブル (USB A オス to microB オス)1
(手持ち)
10コイン形リチウムイオン2次電池「LIR2032」
4個入り
1
11スイッチングACアダプター
9V 1.3A 100~240V
1
12BME280 温湿度・気圧センサモジュール
Vin、I2Cレベル変換回路付き
1

結線図

各モジュール間をジャンパーワイヤで接続した際の結線図です。網掛け部分はCO2センサ、microSDカードスロットなど拡張予定箇所です。

BME280、2004 LCDモジュール、LTC4331絶縁型I2C延長モジュールを各々2個使うのでI2Cアドレスが重複しないように設定変更を行います。

環境モニタ(4)の結線図

BME280の I2Cアドレスの変更

BME280を屋内用(0x76)と屋外用(0x77)として2個接続します。
デフォルトのI2Cアドレス(0x76)では、BME280チップのSDO線はプリントパターンでGNDにつながっています。(黄色の矢印部分、プリントパターンはロットによって異なるものがあるので要確認)。
GNDにつながるプリントパターンをカットして、SDOと右側のVDDIOをハンダ付けしてショートすると0x77に設定完了です。

BME280モジュール基板
BME280モジュール基板の裏面(左:VccとI2Cのレベル変換回路)と表面(右:BME280センサ)。黄色の丸点線部分のSDOとGNDにつながるプリントパターンをカット。
SDOとGNDにつながるプリントパターン部分の拡大画像
SDOとGNDにつながるプリントパターン部分の拡大画像。黄色のGNDにつながる矢印部分をカット。
矢印部分のプリントパターンをカット、SDOと右側のVDDIOをハンダ付け
矢印部分のプリントパターンをカット、SDOと右側のVDDIOをハンダ付け

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です。

20文字×4行キャラクタLCDの背面。I2C I/F基板の黄色の点線部分がI2Cアドレス設定用の ソルダジャンパ パターン
20文字×4行キャラクタLCDの背面。I2C I/F基板の黄色の点線部分がI2Cアドレス設定用の ソルダジャンパ パターン

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は黒線です。

LTC4331モジュールのマスタ側とスレーブ側をつなぐLANケーブルは4本の信号線を使います。通信用には4番線と5番線のみですが、スレーブ側(延長先、屋外)のLTC4331モジュールとBME280センサモジュールに給電するために1番線に5V、2番線にGNDを追加で結線します。
LANケーブルを使っていますが ネットワークHUBに刺しての延長はできません。

LTC4331モジュールとLANケーブルでI2Cバスを延長
LTC4331モジュールとLANケーブルでI2Cバスを延長。左側がベランダの軒下に設置したLTC4331とBME280センサをのせたブレッドボード

モジュールのI2Cアドレスの確認

ArduinoサイトにあるI2CアドレスをスキャンするスケッチArduino Playground – I2cScannerを実行すると、I2Cバス上に6個のデバイスが検出されました。
LTC4331モジュール + LANケーブルで10m延長した屋外設置のBME280のI2Cアドレスも 0x77 と認識できています。

#パーツI2C
アドレス
備考
12004 LCD0x26追加
22004 LCD0x27デフォルト
3DS32310x57

0x68
EEPROM
AT24C32
RTC
4BME2800x76デフォルト
5BME2800x77追加
I2C Scannerで6個のデバイスを検出
I2C Scannerで6個のデバイスを検出

開発ツールarduino-esp32をインストール

arduino-esp32のインストール手順を別ページに纏めました。

あわせて読みたい
ESP32-DevKitCの開発ツール arduino-esp32 のインストール手順 Arduino IDE上で動作する ESP32-DevKitC の開発ツール arduino-esp32(Arduino core for the ESP32)をインストールした際の手順メモです。 arduino-esp32は、Seeed Stu...

スケッチ1:BME280センサ2個で屋内と屋外の温湿度・気圧をシリアルモニタに出力

屋内用のBME280センサ(0x76)と屋外用のBME280センサ(0x77)の両センサから測定データを取得してシリアルモニタに出力します。
ライブラリとしてGitHub掲載の adafruit/Adafruit_BME280_Libraryadafruit/Adafruit_Sensor を利用させていただきました。このライブラリのサンプルスケッチを使って、2つの BME280センサからデータ取得できるように修正したスケッチ1です。

Adafruit_I2CDevice.hが無いとのエラーメッセージがでた場合はadafruit/Adafruit_BusIO(Adafruit_BusIO-master.zip)をインクルードします。

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つの測定結果をシリアルモニタに出力
屋内と屋外の2つの測定結果をシリアルモニタに出力。()内は、左から温度、気圧、湿度。

スケッチ2:Tera Termでシリアルポート接続して屋外の温湿度、気圧データをPCで記録

2つのBME280モジュールで屋内とLANケーブル延長した屋外の温湿度、気圧を測定しました。手順はESP32-DevKitCとBME280で測った温湿度・気圧データをTera Termのログに記録、EXCELでグラフ化:環境モニタ(3)と同じです。

Tera Termが文字化けする時は、 Tera Termのシリアルポート設定とスケッチで定義した通信速度が一致しているかを確認します。

Tera Termのシリアルポート設定
Tera Termのシリアルポート設定。「スピード(E)」がスケッチで定義した115200bpsになっているかを確認

簡易的なデータロガーとして使えるように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の測定結果を表示します。

屋内と屋外に設置したBME280の測定結果を2つの2004 LCDで表示
屋内と屋外に設置したBME280の測定結果を2つの2004 LCDで表示(左側:屋内 PRESS1、右側:屋外 PRESS2)。PC画面ではTera Termで受信した測定データ(CSV形式)を表示&ログファイルとして保存中。※温湿度の残像(%が2文字)処理ができてません。

屋内、屋外の温湿度、気圧を測定してグラフ化

スケッチ3を使ってTera Termログとしてリビングとベランダの温湿度、気圧を6日間受信して記録しました。LTC4331モジュールとLANケーブルを使って、屋外に設置したBME280センサモジュールへのI2C信号と電源の伝送によって安定したデータ収集ができました。
BME280センサは高感度です。昼間の生活時間帯の人の動き(LCDを覘いた際の呼気など)や窓を開けての換気などで湿度や温度が瞬間的に大きく変化しました。
気圧は天候の移り変わりの影響で980〜1015hPa間で変化しましたが、同じ高度のリビングとベランダ程度では差異は無いです。

BME280_teraterm_graph_r2
屋内(リビング)と屋外(ベランダの軒下)で測った温湿度、気圧の変化
よかったらシェアしてね!
  • URLをコピーしました!
目次