ESP32-DevKitCとRTCモジュールDS3231を使ったNTP時刻合わせLCD時計に、BOSCH社のBME280センサを使った温湿度・気圧計モジュールをI2C接続して20文字X4行のLCDモジュールに追加表示しました。
追加で集めたパーツ、結線図と組み立て(2022/4/21訂正)
集めたパーツ
「ESP32-DevKitCでNTPサーバと時刻同期して RTCモジュール DS3231の時刻合わせを行うLCD時計:環境モニタ(1)」に、セ氏零度以下の-40~+85℃の範囲を測定できる BME280温湿度・気圧センサモジュールを追加しました。
# | 今回、追加したパーツ | 個数 |
1 | BME280 温湿度・気圧センサーモジュール Vin、I2Cレベル変換回路付き | 1 |
2 | ジャンパーワイヤ | 適量 |
# | 環境モニタ(1)で準備したパーツ | 個数 |
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 |
結線図
各モジュール間をジャンパーワイヤで接続した際の結線図です。BME280 温湿度・気圧センサーモジュール(右下)と4本のジャンパー線で結線します。
網掛け部分は屋外測定用の温湿度センサ、CO2センサ、microSDカードスロットなど拡張予定箇所です。
実装
ブレッドボードに各モジュール(ESP32-DevKitC、DS3231、I2Cレベル変換、BME280、LCD)を実装し、モジュール の4つの端子:SCL(緑)、SDA(白)、給電(5V or 3.3V、赤)、GND(黒)をジャンパーワイヤで結線しました。
各モジュールの電源電圧とI2C信号レベルの確認(2021/12/5追記)
電源電圧を5V、I2Cバスの信号レベルは5Vを基準としました。BME280モジュール基板にはVinとI2C信号のレベル変換チップが実装されています。
# | モジュール | 電源電圧 | モジュールの信号レベル | I2CSCL | I2CSDA | I2C
1 | ESP32-DevKitC | 5V LDO内蔵:5V → 3.3V | 双方向電圧レベル変換 モジュールを利用 5V<—> 3.3V | GPIO22 | GPIO21 |
2 | DS3231SN RTC | 5V 仕様:3.3V~5.5V | 5V 仕様:3.3V~5.5V | 印字 | 印字 |
3 | 2004 LCD I2C I/F | 5V | 5V | 印字 | 印字 |
4 | BME280 | 5V LDO内蔵:5V → 3.3V | 5V 双方向電圧レベル変換内臓 | 印字 | 印字 |
BME280モジュールのI2Cアドレスの確認とI2C信号波形の観察
BME280データシートからチップの電源電圧、I2C信号レベルともに3.3V。今回、Amazonで購入したBME280モジュール(4ピン基板)は、裏面にI2C(SCLとSDA)側に5Vと3.3VのI2Cバスレベル変換回路とVin(5V)に3.3Vへのレギュレータ回路(LDO:Low Drop Out)を搭載しています。レベル変換回路では10kΩでプルアップされています。
ArduinoサイトにあるI2CアドレスをスキャンするスケッチArduino Playground – I2cScannerを実行するとBME280のI2Cアドレスは0x76でした。
デジタルオシロスコープでブレッドボード上のI2C(SCLとSDA)配線ワイヤの信号波形をモニタすると約4.6Vの矩形波でした。
開発ツールarduino-esp32をインストール
arduino-esp32のインストール手順を別ページに纏めました。
スケッチ1:BME280センサで測った温湿度・気圧データをシリアルモニタに出力
BME280センサ(0x76)から測定データを取得してシリアルモニタに出力します。ライブラリとしてGitHub掲載の adafruit/Adafruit_BME280_Library と adafruit/Adafruit_Sensor を利用させていただきました。
ESP32_BME280_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;
float temp;
float pressure;
float humid;
void setup() {
Serial.begin(115200);
bool status;
status = bme.begin(0x76);
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(" *C ");
Serial.print(pressure);
Serial.print(" hPa ");
Serial.print(humid);
Serial.println(" %");
delay(1000);
}
スケッチ2:RTC時計とBME280センサで測った温湿度・気圧データをLCD表示(2021/12/5修正)
NTP時刻合わせのRTC時計のスケッチとBME280温湿度・気圧センサのスケッチ1を統合して20文字 x 4行のLCDに表示するスケッチです。1行目に年月日週、2行目に時刻、3行目に気圧、4行目に温度、湿度を表示します。
ESP32_DS3232RTC_BME280_LCD.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表示
Adafruit_BME280 bme; // 屋内センサ
float temp;
float pressure;
float humid;
// 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();
// ----- 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);
}
}
void loop(void) {
dispLCD();
delay(1000);
}
void dispLCD(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,1);
lcd.print("hPa");
lcd.setCursor(0,3);
lcd.print("T:");
lcd.print(temp,1);
lcd.print("'C / H:");
lcd.print(humid,1);
lcd.print("%");
}
// ----- DS3231時計 -----
// 先頭のゼロ(0)を空白に置換
void lcdzeroSup(int digit) {
if(digit < 10)
lcd.print(' '); // 空白
lcd.print(digit);
}