BME680で温湿度・気圧計の作成(5) スケッチの作成
◯やりたいこと
(4)で確定した回路図をもとにスケッチを作成する。
(現在は実際に電池稼働での実験に入っています。)
◯やったこと
・スケッチの作成
現時点で動いているスケッチは以下の通りとなっています。
/** * * WiFi 温湿度・気圧計 WR02_BME680_OLED v0.0.5b * * CPU : WROOM-02(ESP8266) シンプル版 * Pin Function * IO0 : SCL * IO1 : TX (OLED Power) * IO2 : SDA * IO3 : RX (SW) * IO4 : - * IO5 : - * IO12 : - * IO13 : - * IO14 : - * IO15 : - * IO16 : Reset出力(OnBord) * TOUT : - * Board * ESP8266 Community : Generic ESP8266 Module * URL : http://arduino.esp8266.com/stable/package_esp8266com_index.json * */ // Standerd Library (IDE v1.8.19) #include <Arduino.h> #include <time.h> #include <Wire.h> // Board Library (ESP8266 Boards v2.7.2) #include <ESP8266WiFi.h> #include <WiFiClient.h> // Install Library #include <Adafruit_GFX.h> // v1.11.3 #include <Adafruit_SSD1306.h> // v2.5.7 #include <Adafruit_Sensor.h> #include <Adafruit_BME680.h> // v2.0.2 // Global Value /* WiFi */ #define CONN_SSID "YOUR_SSID" #define CONN_PASS "YOUR_PASSWORD" /* My ID,IP,MAC */ String MY_NAME = "ESP093"; IPAddress ip (YOUR_IP); IPAddress gateway (YOUR_GATEWAY); IPAddress dnServer (YOUR_DNSSERVER); IPAddress netmask (YOUR_NETMASK); /* UART */ #define TX 1 // D1 #define RX 3 // D3 /* I2C */ #define I2C_SDA 2 // D2 #define I2C_SCK 0 // D0 #define I2C_CLK 50000 // fSCL=50KHz /* WakeUp Interval */ #define wup_itvl 10 // [分] /* SW */ #define SW_RES RX #define SW_on HIGH /* OLED */ #define OLED_ADR 0x3C // I2C ADDRESS #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height,in pixels #define OLED_PWR TX // OLED 電源制御ピン #define OLED_off LOW #define OLED_on HIGH Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); /* NTP DATA */ #define JST (3600 * 9) #define DAYLIGHTOFFSET_JST (0) #define NTP_SERVER1 "ntp.nict.jp" // NTP1 #define NTP_SERVER2 "ntp.jst.mfeed.ad.jp" // NTP2 static const char *pszWDay[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static const char *pszMonth[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; /* BME680 */ #define SEALEVELPRESSURE_HPA (1013.25) #define BME_ADR 0x76 Adafruit_BME680 bme; // I2C接続:引数なし /* Flag */ boolean flg_wifi = false; // True: WiFi on boolean flg_boot = false; // True: Manual boot /* Value */ float tmp, hum, prs, gas; ///// ハードウエア 初期設定 void setup() { /* Serial (TXピンをGPIOとして利用) */ Serial.begin(115200,SERIAL_8N1,SERIAL_RX_ONLY); /* Manual boot Check */ pinMode(SW_RES, INPUT); if(digitalRead(SW_RES)==SW_on) flg_boot = true; /* Sleep Mode */ wifi_set_sleep_type(MODEM_SLEEP_T); /* I2C */ Wire.begin(I2C_SDA, I2C_SCK); // I2C pins Wire.setClock(I2C_CLK); // I2C clock(fSCL) delay(100); /* OLED */ digitalWrite(OLED_PWR, OLED_off); pinMode(OLED_PWR, OUTPUT); dsp_start(); /* WiFi */ WiFi.config(ip, gateway, netmask, gateway); if (!wifi_connect()) wifi_end(); flg_wifi = true; /* NPT */ configTzTime("JST-9", NTP_SERVER1, NTP_SERVER2); if (!ntp_connect()) wifi_end(); /* BME680 */ unsigned long timeout = millis(); while(millis() - timeout < 1000) { if (bme.begin(BME_ADR)) { delay(150); break; } delay(150); } if (!bme.begin(BME_ADR)) wifi_end(); } ///// メインルーチン void loop() { // 時刻表示 dsp_datetime(); // 温湿度・気圧測定(BME680) unsigned long timeout = millis(); while(millis() - timeout < 1000) { if (bme.performReading()) { tmp = bme.temperature; hum = bme.humidity; prs = bme.pressure / 100.0; gas = bme.gas_resistance / 1000.0; break; } else delay(250); } // DATA 表示 dsp_data(); // SQL DATA送信 /* ~ ここにWiFiでデータを送信するスケッチを書く 〜 */ // 測定結果表示 wifi_stop(); if (flg_boot) delay(8000); // 計測終了 wifi_end(); } ///// Display Control ///// /* OLED 起動処理 */ void dsp_start() { // Manual Boot Check if (!flg_boot) return; // OLED digitalWrite(OLED_PWR, OLED_on); delay(500); // 初期化 display.begin(SSD1306_SWITCHCAPVCC, OLED_ADR); // 初期表示 display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(1); display.setCursor( 10, 20); display.print("Sensor Startup.."); display.display(); display.clearDisplay(); } /* OLED 時刻表示 */ void dsp_datetime() { // Manual Boot Check if (!flg_boot) return; // NPT 現在時刻の取得 time_t timeNow = time(NULL); struct tm* tmNow = localtime(&timeNow); // DATE 文字列作成 char fmtDate[11]; sprintf( fmtDate, "%02d/%02d(%s)", tmNow->tm_mon + 1, tmNow->tm_mday, pszWDay[tmNow->tm_wday] ); // TIME 文字列作成 char fmtTime[6]; sprintf( fmtTime, "%02d:%02d", tmNow->tm_hour, tmNow->tm_min ); // 表示 display.clearDisplay(); //display.fillRect( 0, 0,128, 16,BLACK); display.setTextSize(1); display.setCursor( 4, 4); display.println(fmtDate); display.setTextSize(2); display.setCursor( 68, 0); display.println(fmtTime); display.display(); } /* OLED 測定結果表示 */ void dsp_data() { // Manual Boot Check if (!flg_boot) return; // 変数初期化 char buf1[9], buf2[21]; // 測定結果表示 display.setTextColor(WHITE); display.setTextSize(1); /* Temp 表示 */ display.setCursor( 0, 19); dtostrf (tmp,4,1,buf1); sprintf (buf2, "Tmp: %sC", buf1); display.print (buf2); /* Humi 表示 */ display.setCursor( 0, 28); dtostrf (hum,4,1,buf1); sprintf (buf2, "Hum: %s", buf1); display.print (buf2); display.print ('%'); /* Press 表示 */ display.setCursor( 0, 37); dtostrf (prs,4,0,buf1); sprintf (buf2, "Prs: %sHp", buf1); display.print (buf2); /* GAS 表示 */ display.setCursor( 0, 46); dtostrf (gas,4,1,buf1); sprintf (buf2, "Gas: %s", buf1); display.print (buf2); /* MY_NAME 表示 */ display.setCursor( 70, 54); display.print (" "+ MY_NAME); display.display(); } /* OLED 終了処理 */ void dsp_end() { // Manual Boot Check digitalWrite(OLED_PWR, OLED_off); } ///// WiFi Control ///// /* WiFi接続開始処理 -> True:WiFi接続完了, False:WiFi接続失敗 */ boolean wifi_connect() { // WiFi 接続サイクルスタート(接続->確認->再接続) 3トライ for(int i = 0; (i < 2); i++) { // WiFi接続 接続が記憶されていない場合接続情報を記憶させ次回自動接続にする。 if (WiFi.SSID() != CONN_SSID) { WiFi.persistent(true); WiFi.mode(WIFI_STA); WiFi.setAutoConnect(true); WiFi.begin(CONN_SSID, CONN_PASS); } // 5秒間 0.5秒毎に接続確認 unsigned long timeout = millis(); while(millis() - timeout < 10000) { // 接続できた場合 Trueリターン if(WiFi.status() == WL_CONNECTED) return true; // 未接続は 500ms待ちしてループ delay(500); } } // WiFi 接続不可 エラーリターン return false; } /* WiFi stop処理 */ void wifi_stop() { if (WiFi.status() == WL_CONNECTED) { WiFi.persistent(false); WiFi.disconnect(); // ステーションモード維持,ssid・passwordをクリアしない delay(10); } } /* WiFi stop,終了処理 */ void wifi_end() { // 現在時刻取得 time_t tmUnix = time(NULL); // unix struct tm* tmNow = localtime(&tmUnix); // unix // WiFi切断 wifi_stop(); // 現在から起動までの分を計算 int minSlp = (wup_itvl<2) ? 1:(wup_itvl-(tmNow->tm_min % wup_itvl)); // 30秒過ぎは起動を30秒早める int secSlp = 0; if (tmNow->tm_sec>30) { minSlp = minSlp-1; secSlp = 30; } // 諸機能停止 dsp_end(); ESP.deepSleep((minSlp*62+ secSlp)*1000*1000); delay(500); } ///// NTP Control ///// /* NTP 同期処理 */ boolean ntp_connect() { // NTP サーバー同期確認 (max 5sec) unsigned long timeout = millis(); while (millis() - timeout < 10000) { // 現在時刻読込 time_t timeNow = time(NULL); struct tm* tmNow = localtime(&timeNow); // NPT同期完了 & 起動時間は正常リターン if(tmNow->tm_year>=100) { if (flg_boot) return true; if (wup_itvl==0) return true; if ((tmNow->tm_min % wup_itvl)==0) return true; return false; } // 同期未了は0.25秒おきに再確認 delay(250); } // 接続できなかったので エラーリターン return false; }
(2023.06.24 v0.0.5b改訂 マニュアルブート時のみ8秒の表示待ちを行う)
(2023.08.05 マニュアルブート判断文のバグ修正)
まあ基本的に起動して測定して終了するという一本道スケッチです。
主な注意点を箇条書きしますと、
・インストールが必要なモジュールは // Board Library, // Install Libraryにまとめてあります。
・起動してすぐ手動起動SWを読込みマニュアルブートかをチェック、そうであればflg_bootを立てます。
・WiFiのSSIDやパスワード、ipアドレスなどは適宜自分の環境に合わせた設定が必要です。
・測定値を格納する変数はグローバル変数にしていて各関数で引数の引渡しを不要にしています。
・WiFiでデータを送信する部分は別に作成が必要です。ロギングが不要であればなくても構いません。
・wifi_end()で次の正10分迄の時間を計算し、その時間deepsleepします。
・起動時にNTPに接続して正10分の確認をし、違っていればwifi_end()を呼びます。
・手動起動の場合は無条件で起動し測定を実施します。
・シリアルのTXをGPIOピンとして利用するためRXオンリーモードで起動しています。(参考
ESP-01 and ESP-01S How program and use the Pins and Leds)
てなところでしょうか。
スケッチは独学で自分がわかりやすい(忘れない!)ように書いているため一般的なフォーマットで記述されていないと思います。少々見にくい点はご容赦ください。