ESP32-DevKitC + 2.8インチTFT液晶(ILI9341)で作った環境モニタ用の二合枡ケース

ブレッドボードで動作テストした後で悩むのが、ユニバーサル基板へのモジュールの配置とそれらを収めるケースです。
今回使ったパーツの中で最も大きな2.8インチTFT液晶(ILI9341)モジュールの横幅が二合枡の内部寸法にジャストフィットで収まりました。センサ類は外気に晒しておきたいので前面下部に設置。
室内専用となりますがケースとして二合枡を使い、木工ドリルでACアダプター接続用のDCジャック、スケッチ書き込み用のUSBケーブルの差し込み穴、ユニバーサル基板とゴム足固定用の小穴をあける作業でした。
ユニバーサル基板ではんだ付けして実装することでブレッドボードとワイヤの接触不良がなくなり安定動作しています。
今回CO2濃度測定に使ったSCD41センサモジュールはSCD30センサモジュールと基板サイズやピン配置がコンパチブルなので同一のユニバーサル基板、ケースが使えます。

二合枡に格納した環境モニタ
目次

ケース作製用に集めたパーツ

ネット通販と手持ちのパーツを集めて組み立てました。

#パーツ数量備考
二合枡
外寸: 約108 × 108 × 58
内寸: 約 87 × 87 × 47.5
1板厚は約10.0mm ~ 10.6mm
2ユニバーサル基板適量両面スルーホール、2.54mmピッチ、ガラスエポキシ製
3ラッピングワイヤ適量ユニバーサル基板上の配線には30AWG、電源引き出しには24AWGを利用
4分割ロングピンソケット
(細ピン用) 1×40 (40P)
適量モジュールのピン数に合わせてニッパでカット
5樹脂スペーサ(1)
オス-メス M3 x 15mm
4ユニバーサル基板の固定
手持ちの樹脂スペーサ(1)と(2)を結合して23mmで利用
6樹脂スペーサ(2)
オス-メス M3 x 8mm、
プラナット
4
7平頭小ネジ、ナット
M3 x 16mm
4二合枡の背面から樹脂スペーサ(1)を固定
8樹脂スペーサ(3)
オス-メス M2 x 10mm
2DS3231 と SCD41モジュールの固定、プラスペーサは高さの微調整用。
手持ちの樹脂スペーサ(3)にプラスペーサは挟んで11mmで利用
9M2プラナット、
プラスペーサ(1mm)
2
10ACアダプター
(2.1mmプラグ)
19V 1.3A 100~240V
11DC-DC降圧モジュール
(9Vを5Vに降圧)
任意5VのACアダプター利用時は不要
122.1mm標準DCジャック1
13ゴム足、
木ネジ(タッピングネジ)
4

ユニバーサル基板に実装

ブレッドボード上のテストで動作確認が取れたので、ユニバーサル基板に実装しました。今回使ったパーツの中で最も大きな2.8インチTFT液晶(ILI9341)モジュールの横幅に合わせて、ユニバーサル基板のサイズは約86mm x 80mmとしています。二合枡の内部寸法は約 87 mm× 87mm。
その際、TFT液晶モジュールの両端の接続ピン(J2(14本のピン)、J4(4本のピン))がユニバーサル基板上の2.54mmピッチの両面スルーホールの位置とあっていることを確認しておきます。

各モジュールは分割ロングピンソケットを介してはんだ付け

各モジュールは、ユニバーサル基板に直接はんだ付けしないで、分割ロングピンソケットを介して実装しています。
ユニバーサル基板のおもて面に2.8インチTFT液晶(ILI9341)モジュールとCO2濃度センサSCD41、気圧・温湿度センサBME280を、裏面にESP32-DevKitCとRTCモジュールDS3231、DC-DC降圧モジュールを実装。
ACアダプター接続用の2.1mm標準DCジャックとユニバーサル基板をつなぐ配線ケーブルの中間地点に脱着用の中継コネクタを追加しておくと、ユニバーサル基板を点検する際に二合枡と分離できて便利です(今回、中継コネクタはオス・メスのジャンパーワイヤのピンを24AWG配線ケーブルではんだ付けして自作)。
ケースに収めた際に、(ぎりぎりの寸法ですが)2.8インチTFT液晶(ILI9341)モジュールのSDカードソケットからSDカードを出し入れができること、ESP32-DevKitCのUSBコネクタに外部からスケッチ書き込み用のUSBケーブルが刺せることを確認して配置を決めました。
ユニバーサル基板上のモジュール間の配線には手持ちのラッピング用ワイヤ30AWG(細い)、電源引き出しには24AWGを利用。

電源ラインの配線を誤るとモジュールが壊れるリスクがあるので、念には念を入れて配線誤りがないかを確認しておきます。

ユニバーサル基板の前面(モジュール実装後)
ユニバーサル基板の裏面(モジュール実装後)

ESP32-DevKitCへの電源供給、結線図

電源供給は、PC等のUSBコネクタからESP32-DevkitCのUSB micro Bコネクタに給電するか、5V出力のACアダプターをESP32-DevkitCの5Vピンにつないで動作させます(ESP32-DevkitCは内部に5Vから3.3Vの降圧レギュレータを内蔵)。

ケース実装にあたり、2.1mm標準DCジャックに接続できるACアダプターを使っています。今回、手持ちのACアダプターが9V出力だったので、DC-DC降圧モジュール(MP1584EN)を使って5Vに降圧してESP32-DevkitCの5Vピンに外部給電します。

DC-DC降圧モジュールのIN+とIN-間に9Vを印可したとき、OUT+とOUT-間が5Vになるようにモジュール上の半固定ボリュームを調整しておきます。
INとOUT側の4本のジャンパーピンは、余ったワイヤ線などをはんだ付けして自作。

参考:
ESP32-DevKitC-1 pin-layout | espressif.com

外部電源部分を追加した結線図
今回使ったDC-DC降圧モジュール(MP1584EN)

二合枡の加工

二合枡の穴あけに木工用ドリル刃(3mm、8mm、18mm)、狭所での作業は先端が細く平たい精密ピンセットを使用。

DCジャック取り付け、USBコネクタ接続用の穴開け

二合枡の背面に8mm φ の木工用ドリルで穴あけしてACアダプターとつなぐ2.1mm標準DCジャックを装着。開けた穴径がやや大きかったので2.1mm標準DCジャックのねじ部分に強力両面テープを1周巻いてからねじ込んで接着。
二合枡の上面側にはESP32-DevkitCのUSB micro BコネクタにPCからのUSB ケーブルを差し込める位置に18mm φ の木工用ドリルで穴あけ、スケッチの修正が容易になりました。

背面の中央下部に2.1mm標準DCジャックを装着
天井にUSB typeBケーブル接続用の穴開け。
熱の排気口としても有効か?

二合枡ケースにユニバーサル基板を固定、ゴム足を取り付けて完成

二合枡の背面に3mm φ の木工用ドリルで4箇所穴あけして、先にユニバーサル基板と二合枡をつなぐ樹脂スペーサ(1)を二合枡の背面からM3平頭小ネジで樹脂スペーサが少し動く程度にしめておきます。

裏面実装になるモジュール(ESP32-DevKitC、RTCモジュールDS3231、DC-DC降圧モジュールを分割ロングピンソケットに差し込んだユニバーサル基板と基板上の電源ケーブルを脱着用の中継コネクタを介して2.1mm標準DCジャックに接続。そのユニバーサル基板を二合枡に組み入れてM3プラナットで樹脂スペーサに固定。その際ユニバーサル基板の4隅に開けた3mm φ 穴と樹脂スペーサのM3ねじの頭がずれて刺さらないときは、開けた3mm φ 穴から見えるねじの頭を精密ピンセットで引き込みます。
ユニバーサル基板と樹脂スペーサを4個のプラナットで固定できたら、二合枡の背面側のM3平頭小ネジを固定します。
最後に、おもて面実装の2.8インチTFT液晶(ILI9341)モジュールとCO2濃度センサSCD41、気圧・温湿度センサBME280を分割ロングピンソケットに差し込んで完成です。
二合枡の底面 4か所にゴム足(壊れた冷却ファンから流用)を木工用のタッピングネジで取り付けました。

ユニバーサル基板と樹脂スペーサを4個のプラナットで固定。2.8インチTFT液晶(ILI9341)モジュールやセンサ類は未装着
ユニバーサル基板固定用の樹脂スペーサを二合枡の背面からM3平頭小ネジで固定

動作確認に使ったスケッチ

ACアダプターを2.1mm標準DCジャックに差し込んで動作確認。初期化状況のメッセージがエラーなく表示されれば完成です。

CO2濃度測定にSCD41センサモジュールを利用

動作確認に使ったスケッチは、CO2濃度測定にSCD41センサモジュールを使い、1秒毎に日時・時刻表示、10秒毎に気圧、CO2濃度、温度、湿度を表示、SDカードにその値をファイル名「logdata.txt」でCSV形式で書き込む「esp32-devkitc_ili9341_scd4x_bme280_ds3231_SD.ino」。

あわせて読みたい
ESP32-DevKitC + DS3231 + SCD4x + BME280で日時・時刻、CO2濃度、気圧、温湿度を2.8インチ液晶表示、SD... ESP32-DevKitCとILI9341を搭載した2.8インチTFT液晶モジュールをSPI接続(液晶とタッチパネルはVSPI、SDカードはHSPI)、RTCモジュールDS3231、CO2濃度センサSCD41と気...

 

CO2濃度測定にSCD30センサモジュールを利用

今回CO2濃度測定に使ったSCD41センサモジュールは、SCD30センサモジュールと基板サイズやピン配置がコンパチブルでした。

スケッチの修正は必要ですが、SCD30センサモジュールに差し替えで動作できます。

動作確認中。CO2濃度測定にSCD30センサモジュールを利用

動作確認につかったスケッチは「esp32-devkitc_ili9341_scd30_bme280_ds3231_SD.ino」のCとOの文字サイズを小さめにしたHEXデータを使った「esp32-devkitc_ili9341_scd30_bme280_ds3231_SD_v2.ino」に変更しています。

留意点
・再起動の都度、前回起動時に書き込まれたSDカードのデータは削除されます。
・23、24行には、WiFi接続環境のSSIDとそのパスワードを記述ください。
公開後のコード修正履歴
・「C」と「O」の文字サイズを見直しました。これに伴い30行、31行のHEXデータを修正、文字サイズの変更に伴い130行の「C」の位置を修正(2024/08/02)。

esp32-devkitc_ili9341_scd30_bme280_ds3231_SD_v2.ino
※ここをクリックするとコード表示を開閉できます。
#include <Wire.h>
#include <SPI.h>
#include <WiFi.h>
#include <SD.h>
#include <TimeLib.h>    // https://github.com/PaulStoffregen/Time
#include <TFT_eSPI.h>   // https://github.com/Bodmer/TFT_eSPI
#include "SparkFun_SCD30_Arduino_Library.h"  // https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
#include <Adafruit_Sensor.h>   // https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h>   // https://github.com/adafruit/Adafruit_BME280_Library
#include <DS3232RTC.h>         // DS3232、DS3231用ライブラリ https://github.com/JChristensen/DS3232RTC
#include <esp_sntp.h>

TFT_eSPI tft = TFT_eSPI();
SPIClass spiSD(HSPI);
SCD30 airSensor;
float co2_tmp;
Adafruit_BME280 bme;
float pressure;
float temp;
float humid;
DS3232RTC myRTC(false);
const char* weekStr[7] = {"(Sun)","(Mon)","(Tue)","(Wed)","(Thu)","(Fri)","(Sat)"};
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;
const unsigned char kii_bmp[] PROGMEM = {0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0xF0, 0xFF, 0xFF, 0x1F, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x8E, 0xFF, 0xFF, 0x03, 0x86, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x83, 0x01, 0xE0, 0xC0, 0x81, 0x01, 0xC0, 0xC3, 0x80, 0x01, 0x00, 0x67, 0x80, 0x01, 0x00, 0x7E, 0x80, 0x01, 0x00, 0x3C, 0x80, 0x01, 0x00, 0x7C, 0x80, 0x03, 0x00, 0xEF, 0x00, 0x43, 0x80, 0xC3, 0x01, 0x63, 0xE0, 0x81, 0x03, 0x63, 0xF8, 0x00, 0x07, 0x66, 0x3E, 0x00, 0x06, 0x7E, 0x0E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x18, };
const unsigned char atu_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 0xF0, 0xFF, 0xFF, 0x7F, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0xFE, 0xFF, 0x1F, 0x30, 0xFE, 0xFF, 0x1F, 0x30, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x38, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0xCE, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
const unsigned char ccc_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0xF8, 0xC0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
const unsigned char ooo_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x1E, 0x78, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x80, 0x07, 0xC0, 0x01, 0x80, 0x03, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x03, 0xC0, 0x01, 0x80, 0x03, 0xC0, 0x01, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x01, 0x00, 0x03, 0xC0, 0x01, 0x80, 0x03, 0xC0, 0x01, 0x80, 0x03, 0x80, 0x03, 0x80, 0x01, 0x80, 0x03, 0xC0, 0x01, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1E, 0x78, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
const unsigned char onn_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x38, 0xF8, 0xFF, 0x07, 0x70, 0xF8, 0xFF, 0x07, 0xE0, 0x18, 0x00, 0x06, 0xC0, 0x18, 0x00, 0x06, 0x00, 0x18, 0x00, 0x06, 0x00, 0xF8, 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x07, 0x02, 0x18, 0x00, 0x06, 0x07, 0x18, 0x00, 0x06, 0x1E, 0x18, 0x00, 0x06, 0x38, 0x38, 0x00, 0x06, 0x70, 0xF8, 0xFF, 0x07, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x3F, 0x00, 0x8C, 0xE3, 0x18, 0x60, 0x0C, 0x63, 0x18, 0x60, 0x0C, 0x63, 0x18, 0x70, 0x0C, 0x63, 0x18, 0x30, 0x0C, 0x63, 0x18, 0x30, 0x0C, 0x63, 0x18, 0x18, 0x0C, 0x63, 0x18, 0x18, 0x0C, 0x63, 0x18, 0x1C, 0x0C, 0x63, 0x18, 0x8C, 0xFF, 0xFF, 0xFF, 0xCE, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
const unsigned char doo_bmp[] PROGMEM = {0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xF0, 0xFF, 0xFF, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x30, 0x60, 0xC0, 0x00, 0x30, 0x60, 0xC0, 0x00, 0x30, 0x60, 0xC0, 0x00, 0x30, 0x60, 0xC0, 0x00, 0xB0, 0xFF, 0xFF, 0x7F, 0x30, 0xE7, 0xE0, 0x70, 0x30, 0x60, 0xC0, 0x00, 0x30, 0x60, 0xC0, 0x00, 0x30, 0x60, 0xC0, 0x00, 0x30, 0xE0, 0xFF, 0x00, 0x30, 0xE0, 0xFF, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0x03, 0x38, 0xFF, 0xFF, 0x07, 0x18, 0x30, 0x00, 0x03, 0x18, 0x60, 0x80, 0x01, 0x18, 0xE0, 0xC0, 0x01, 0x18, 0xC0, 0xE1, 0x00, 0x1C, 0x80, 0x7B, 0x00, 0x0C, 0x00, 0x1F, 0x00, 0x0E, 0x00, 0x3F, 0x00, 0x0E, 0xE0, 0xFB, 0x01, 0x06, 0xFE, 0xC0, 0x3F, 0xC6, 0x1F, 0x00, 0xFE, 0xC0, 0x01, 0x00, 0x60, };
const unsigned char deg_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x04, 0x10, 0x3C, 0xC0, 0x07, 0x08, 0x18, 0x24, 0xF0, 0x1F, 0x10, 0x0C, 0x42, 0x38, 0x18, 0x30, 0x04, 0x42, 0x18, 0x30, 0x20, 0x06, 0x24, 0x0C, 0x70, 0x60, 0x06, 0x18, 0x0C, 0x00, 0x40, 0x02, 0x00, 0x0C, 0x00, 0x40, 0x02, 0x00, 0x0E, 0x00, 0xC0, 0x02, 0x00, 0x06, 0x00, 0xC0, 0x02, 0x00, 0x06, 0x00, 0xC0, 0x02, 0x00, 0x0E, 0x00, 0xC0, 0x02, 0x00, 0x0E, 0x00, 0xC0, 0x02, 0x00, 0x0C, 0x00, 0x40, 0x06, 0x00, 0x0C, 0x60, 0x40, 0x04, 0x00, 0x1C, 0x30, 0x60, 0x0C, 0x00, 0x38, 0x38, 0x20, 0x08, 0x00, 0xF0, 0x1F, 0x30, 0x18, 0x00, 0xC0, 0x0F, 0x18, 0x30, 0x00, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, };
const unsigned char sit_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0xF8, 0xFF, 0x1F, 0x70, 0xF8, 0xFF, 0x1F, 0xE0, 0x18, 0x00, 0x18, 0xC0, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x06, 0x18, 0x00, 0x18, 0x1E, 0x18, 0x00, 0x18, 0x3C, 0x18, 0x00, 0x18, 0x70, 0x18, 0x00, 0x18, 0x20, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x0C, 0x63, 0x30, 0x60, 0x0C, 0x43, 0x30, 0x60, 0x18, 0x43, 0x18, 0x70, 0x18, 0x43, 0x18, 0x30, 0x30, 0x43, 0x0C, 0x30, 0x30, 0x43, 0x0C, 0x38, 0x30, 0x43, 0x06, 0x18, 0x00, 0x63, 0x00, 0x1C, 0x00, 0x63, 0x00, 0x8C, 0xFF, 0xFF, 0xFF, 0x8E, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };


void setup(void) {
// TFT液晶初期化
  tft.init();
  tft.setRotation(1);
  tft.setTextSize(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  tft.drawString("Initializing TFT library", 0, 20, 4);
delay(1000);
//-------------DS3231-------------
struct tm timeInfo;
myRTC.begin();
//WiFi接続
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
  tft.drawString("WiFi bigin", 0, 50, 4);
}
delay(1000);
// WiFi接続の表示
  tft.drawString("WiFi connected", 0, 50, 4);
delay(1000);
// NTPサーバからJST取得
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  tft.drawString("JST synchronized", 0, 50, 4);
delay(1000);
// 内蔵RTCの時刻がNTP時刻に合うまで待機
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET) {
delay(1000);
}
//内蔵RTC時刻 = NTP時刻の表示
  tft.drawString("Time matched        ", 0, 50, 4);
delay(1000);
//内蔵RTCの時刻の取得
getLocalTime(&timeInfo);
//内蔵RTCの時刻をDS3231に時刻設定
// setTime(12, 40, 0, 14, 11, 2022);  // 手動設定・動作確認用(時、分、秒、日、月、年)
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);
// SDカード初期化
spiSD.begin(14, 33, 13, 15); //SCK,MISO,MOSI,CS
  tft.drawString("Initializing SD library", 0, 80, 4);
delay(1000);
// SDカードマウント確認
if (!SD.begin(15, spiSD)) {
  tft.setTextColor(TFT_RED, TFT_BLACK);
  tft.drawString("Card Mount Failed             ", 0, 80, 4);
return;
}
else  {
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  tft.drawString("Card Mount Successful         ", 0, 80, 4);
}
delay(1000);
// SDカードファイル書き込み ※前回起動時に書き込んだデータは削除されます。
File dataFile = SD.open("/datalog.txt", FILE_WRITE);
dataFile.println("File written");
dataFile.close();
  tft.drawString("File written", 0, 110, 4);
delay(1000);
// BME280初期化
bool status;
status = bme.begin(0x76);
while (!status) {
  tft.setTextColor(TFT_RED, TFT_BLACK);
  tft.drawString("BME280 connection failed", 0, 140, 4);
}
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  tft.drawString("BME280 connected", 0, 140, 4);
delay(1000);
// SCD30初期化
  Wire.begin();
  if (airSensor.begin() == false)  {
      tft.setTextColor(TFT_RED, TFT_BLACK);
  tft.drawString("SCD30 not detected", 0, 170, 4);
    while (1);
  }
//The SCD30 has data ready every two seconds
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  tft.drawString("SCD30 detected", 0, 170, 4);
delay(2000);
// 画面クリア
   tft.fillScreen(TFT_BLACK);
   tft.setTextColor(TFT_WHITE, TFT_BLACK);
// ----- 項目名を日本語で表示 ----- 
// 気圧(hPa)
   tft.drawXBitmap(10, 0, kii_bmp, 32, 32, 0xFFFF);
   tft.drawXBitmap(42, 0, atu_bmp, 32, 32, 0xFFFF);
   tft.drawString("(hPa)", 250, 5, 4);
// CO2濃度(ppm)
   tft.drawXBitmap(5, 47, ccc_bmp, 32, 32, 0xFFFF);
   tft.drawXBitmap(30, 47, ooo_bmp, 32, 32, 0xFFFF); 
   tft.drawString("2", 64, 62, 4);
   tft.drawString("(ppm)", 250, 53, 4);
// 温度(℃)
   tft.drawXBitmap(10, 95, onn_bmp, 32, 32, 0xFFFF);
   tft.drawXBitmap(42, 95, doo_bmp, 32, 32, 0xFFFF);
   tft.drawXBitmap(250, 85, deg_bmp, 40, 40, 0xFFFF);
// 湿度(%)
   tft.drawXBitmap(10, 142, sit_bmp, 32, 32, 0xFFFF);
   tft.drawXBitmap(42, 142, doo_bmp, 32, 32, 0xFFFF);
   tft.drawString("(%)", 250, 146, 4);
// ----- 測定周期を1分間にしたのでTFT画面への初期表示用 -----
// ----- SCD30センサが稼働している時の処理 -----
   if (airSensor.dataAvailable())  {
// ----- SCD30センサからデータ取得、測定値をTFT表示 ----- 
co2_tmp=airSensor.getCO2();
   tft.setTextColor(TFT_WHITE, TFT_BLACK);
   tft.fillRect(105, 47, 140, 45, TFT_BLACK);  // 残像消去
   tft.drawFloat(co2_tmp, 0, 105, 47, 6);
// ----- BME280センサからデータ取得、測定値をTFT表示 ----- 
pressure=bme.readPressure() / 100.0F;
temp=bme.readTemperature();
humid=bme.readHumidity();
   tft.setTextColor(TFT_YELLOW, TFT_BLACK);
   tft.fillRect(105, 0, 140, 45, TFT_BLACK);  // 残像消去
   tft.drawFloat(pressure, 0, 105, 0, 6); 
   tft.drawFloat(temp, 1, 105, 93, 6);
   tft.drawFloat(humid, 1, 105, 140, 6);
  }
}


void loop() {
// RTCから時刻取得
tmElements_t tm;
char d_mes[12] ;
char t_mes[12] ;
myRTC.read(tm);
sprintf(d_mes, "%04d/%02d/%02d", tm.Year + 1970, tm.Month, tm.Day);
sprintf(t_mes, "%02d:%02d:%02d", tm.Hour, tm.Minute, tm.Second);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
   tft.setCursor(70, 190, 4);
   tft.println(d_mes);
   tft.setCursor(200, 190, 4);
   tft.println(weekStr[tm.Wday - 1]);  
   tft.setCursor(110, 220, 4);
   tft.println(t_mes); 
// -------- 10秒毎に測定してTFT表示、SDカード記録 --------
   if((String(tm.Second) == "0")  || (String(tm.Second) == "10") || 
      (String(tm.Second) == "20") || (String(tm.Second) == "30") || 
      (String(tm.Second) == "40") || (String(tm.Second) == "50")){ 
// ----- SCD30センサが稼働している時の処理 -----
   if (airSensor.dataAvailable())  {
// ----- 液晶画面に測定値を表示 -----
   tft.setTextColor(TFT_WHITE, TFT_BLACK);
// ----- SCD30センサからデータ取得、測定値を表示 ----- 
co2_tmp=airSensor.getCO2();
   tft.fillRect(105, 47, 140, 45, TFT_BLACK);  // 残像消去
   tft.drawFloat(co2_tmp, 0, 105, 47, 6);
// ----- BME280センサからデータ取得、測定値を表示 ----- 
pressure=bme.readPressure() / 100.0F;
temp=bme.readTemperature();
humid=bme.readHumidity();
   tft.setTextColor(TFT_YELLOW, TFT_BLACK);
   tft.fillRect(105, 0, 140, 45, TFT_BLACK);  // 残像消去
   tft.drawFloat(pressure, 0, 105, 0, 6); 
   tft.drawFloat(temp, 1, 105, 93, 6);
   tft.drawFloat(humid, 1, 105, 140, 6);
// ----- SDカードへの書き込み用データファイルの生成 ----- 
// データ格納ファイル生成
String dataString = "";
// RTCの年月日と時分秒を記録
dataString += String(d_mes);
dataString += ",";  // カンマセパレータ
dataString += String(t_mes);
// 測定データ1:BME280の気圧
    dataString += ",";  // カンマセパレータ
    if(!isnan(pressure)){
      dataString += String(pressure,0);
    }else{
      dataString += " ";
    }
// 測定データ2:CO2濃度
    dataString += ",";  // カンマセパレータ
    if(!isnan(co2_tmp)){
      dataString += String(co2_tmp,0);
    }else{
      dataString += " ";
    }
// 測定データ3:BME280の温度
    dataString += ",";  // カンマセパレータ
    if(!isnan(temp)){
      dataString += String(temp,1);
    }else{
      dataString += " ";
    }
// 測定データ4:BME280の湿度
    dataString += ",";  // カンマセパレータ
    if(!isnan(humid)){
      dataString += String(humid,1);
    }else{
      dataString += " ";
    }
// ----- SDカードのdatalog.txtにdataStringを追加 ----- 
File dataFile = SD.open("/datalog.txt", FILE_APPEND);
dataFile.println(dataString);
dataFile.close();
   }
  }
// SDカードに2重書込みが起らないように設定
delay(1000);
}

 

よかったらシェアしてね!
  • URLをコピーしました!
目次