02.M5Unifiedで温湿度・気圧測定


02.M5Unifiedで温湿度・気圧測定

温湿度・気圧測定で"01.M5StickC+で簡易熱中症計"のスケッチを修正し4機種で動作するようにしました。温度等の取得は共通でできますが、画面構成は共通ではできないので、位置は比例計算し、文字サイズは実物合わせで拡大縮小しました。

説明

元画面のM5StickC+は、240x135なので
320x240は、1.33倍(=x320/240)x1.78倍(=x240/135)
200x200は、0.83倍(=x200/240)x1.48倍(=x200/135)
128x128は、0.53倍(=x128/240)x0.95倍(=x128/135)
です。
長辺幅WWの320,240,200,128で4機種を区別しました。
1.画面サイズを取得
2.横長に回転し
3.画面サイズから比例でカーソル位置を計算
4.画面5行目の温湿度・気圧測定値が1行に収まるフォントサイズに変更
5.行間は、文字の縦サイズを変更

フォントサイズ


switch (WW) {                                        // 機種ごとの画面設定
  case 128:                                          // ATOMS3
    M5.Display.setFont(&fonts::lgfxJapanGothic_12);  // ゴシック(8,12,16,20,24,28,32,36,40)
    M5.Display.setTextSize(1, HH / 135.0 * 2.0);     // テキストサイズ(倍) 縦を伸ばす
    break;
  case 200:                                          // CoreInk
    M5.Display.setFont(&fonts::lgfxJapanGothic_20);  // ゴシック(8,12,16,20,24,28,32,36,40)
    M5.Display.setTextSize(1, HH / 135.0 * 1.2);     // テキストサイズ(倍) 縦を伸ばす
    break;
  case 240:                                          // M5StickCPlus
    M5.Display.setFont(&fonts::lgfxJapanGothic_24);  // ゴシック(8,12,16,20,24,28,32,36,40)
    break;
  case 320:                                          // M5Stack Basic
    M5.Display.setFont(&fonts::lgfxJapanGothic_32);  // ゴシック(8,12,16,20,24,28,32,36,40)
    M5.Display.setTextSize(1, HH / 135.0 * 0.8);     // テキストサイズ(倍) 縦を縮める
    break;
  default:  // それ以外
    break;
}

バッテリー

ATOMS3はバッテリーが無く、バッテリー残量取得で、マイナス値が出るので、別表示としました。

if (WW == 128) {                         // ATOMS3はバッテリーが無いので
  M5.Display.print("BT---%%");           // 表示 バッテリ残量
} else {
  batP = M5.Power.getBatteryLevel();   // バッテリー残量値を取得(0-100)
  M5.Display.printf("BT%3d%%", batP);  // 表示 バッテリ残量
}
・M5Stack Basic
・CoreInk
・M5StickCPlus
・ATOMS3

flash memory

CoreInkは標準では
Arduino-IDE > ツール > Partition Scheme "Default 4MB with spiffs(1.2MB APP/1.5MB SPIFFS)"

"スケッチが大きすぎます。"
と表示されるので
"8M with spiffs(3MB APP/1.5MB SPIFFS)"
に変更しましたがエラー無しで書込みはするが、何も表示しないので、
"No OTA (2MB APP/2MB SPIFFS)"
に変更しました。表示は、
最大2097152バイトのフラッシュメモリのうち、スケッチが1470461バイト(70%)を使っています。最大327680バイトのRAMのうち、グローバル変数が26800バイト(8%)を使っていて、ローカル変数で300880バイト使うことができます。

通常時の電源on/off

・M5Stack Basic
on :電源ボタンをクリック
off:USBを外して、電源ボタンをダブルクリック

・CoreInk
on :PWRボタンを2秒長押し
off:背面のRSTボタン

・M5StickCPlus
on :PWRボタンを2秒押す
off:PWRボタンを6秒押す

・ATOMS3 TailBat(190mAh)を接続した状態
on :TailBatのボタンをクリック
off:TailBatのボタンをダブルクリック
書込待機モード:ATOMS3のRSTボタンを2秒長押し、緑LEDが点灯したら離す

スケッチ


// AirPressureM5Unified.ino
// 温湿度・気圧・室内簡易暑さ指数・不快指数の表示
// 暑さ指数:(温度:四捨五入で整数,湿度:切上げで5の倍数の整数) 表による
// 不快指数:式は測定値そのもので計算
// 電源on:電源ボタンを2秒, 電源off:6秒
// Adafruit BMP280 Library と Adafruit SHT31 Library が必要
// 90秒で電源が切れるプログラムなので、更新中に電源onか注意必要
#include <M5Unified.h>                         // M5Unifiedライブラリを使用
#include <Adafruit_SHT31.h>                    // 温湿度センサを使用
#include <Adafruit_BMP280.h>                   // 気圧センサを使用
Adafruit_SHT31 sht = Adafruit_SHT31(&Wire);    // sht定義
Adafruit_BMP280 bme = Adafruit_BMP280(&Wire);  // bmp定義だがbmeとする
unsigned long startTime, currentTime;          // 開始時間,現在時間 mS
unsigned long period = 90 * 1000;              // 目標経過時間 mS
int32_t WW, HH, batP;                          // 画面幅,高さ,バッテリー残量(0-100)
int16_t tmp, pre;                              // 10倍の温度,気圧 -32768~32767
int8_t hum, thi, wbgt;                         // 湿度,不快指数,暑さ指数
int8_t tmpIndex, humIndex, RemainingT;         // 温度配列,湿度配列.残り秒
int32_t xx, yy, xxx, yyy;                      // xy計算
//           ℃   %        20  25  30  35  40  45  50  55  60  65  70  75  80  85  90  95 100% 暑さ指数表ver4
int8_t wbgtT[20][17] = { { 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21 },    //21℃
                         { 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22 },    //22
                         { 15, 16, 16, 17, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22, 23, 23 },    //23
                         { 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24 },    //24
                         { 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25 },    //25
                         { 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26 },    //26
                         { 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27 },    //27
                         { 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28 },    //28
                         { 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 28, 29, 29 },    //29
                         { 21, 21, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 29, 30, 30 },    //30
                         { 21, 22, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 30, 31, 31 },    //31
                         { 22, 23, 24, 24, 25, 26, 26, 27, 28, 28, 29, 29, 30, 31, 31, 32, 32 },    //32
                         { 23, 24, 25, 25, 26, 27, 27, 28, 29, 29, 30, 30, 31, 31, 32, 33, 33 },    //33
                         { 24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31, 31, 32, 32, 33, 34, 34 },    //34
                         { 24, 25, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 33, 34, 34, 35 },    //35
                         { 25, 26, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 34, 35, 35, 36 },    //36
                         { 26, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37 },    //37
                         { 27, 28, 29, 29, 30, 31, 32, 33, 33, 34, 35, 35, 36, 36, 37, 37, 38 },    //38
                         { 27, 28, 29, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 37, 38, 38, 39 },    //39
                         { 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 36, 37, 38, 38, 39, 39, 40 } };  //40

void SetDisplay() {                  // 初期画面設定関数
  M5.Display.fillScreen(TFT_BLACK);  // 全画面黒
  WW = M5.Display.width();           // 画面幅を取得
  HH = M5.Display.height();          // 画面高さを取得
  if (WW == HH) {                    // 画面を横長にする
    M5.Display.setRotation(0);       // 0度回転
  } else {
    M5.Display.setRotation(1);  // 90度回転
  }
  if (HH > WW) {  // 横長なので交換 横:WW,縦:HHにする
    int32_t HHWW = HH;
    HH = WW;
    WW = HHWW;
  }
  M5.Display.setFont(&fonts::lgfxJapanGothic_24);  // ゴシック(8,12,16,20,24,28,32,36,40)
  M5.Display.setTextSize(1);                       // テキストサイズ(倍)
  M5.Display.setBrightness(100);                   // バックライト輝度(0-255)実際は数段階
  M5.Display.setTextColor(TFT_GREEN, TFT_BLACK);   // 色設定(文字色[,背景色])
}

void setup() {
  auto cfg = M5.config();                      // M5設定用の構造体を代入
  M5.begin(cfg);                               // M5本体の初期化
  startTime = millis();                        // 開始時間
  SetDisplay();                                // 初期画面設定関数へ
  while (!sht.begin(0x44)) {                   // shtのアドレスで開始できない時
    M5.Display.println("エラー SHT3X未接続");  // 表示
  }
  while (!bme.begin(0x76)) {                    // BMP280のアドレスで開始できない時
    M5.Display.println("エラー BMP280未接続");  // 表示
  }
  switch (WW) {                                        // 機種ごとの画面設定
    case 128:                                          // ATOMS3
      M5.Display.setFont(&fonts::lgfxJapanGothic_12);  // ゴシック(8,12,16,20,24,28,32,36,40)
      M5.Display.setTextSize(1, HH / 135.0 * 2.0);     // テキストサイズ(倍) 縦を伸ばす
      break;
    case 200:                                          // CoreInk
      M5.Display.setFont(&fonts::lgfxJapanGothic_20);  // ゴシック(8,12,16,20,24,28,32,36,40)
      M5.Display.setTextSize(1, HH / 135.0 * 1.2);     // テキストサイズ(倍) 縦を伸ばす
      break;
    case 240:                                          // M5StickCPlus
      M5.Display.setFont(&fonts::lgfxJapanGothic_24);  // ゴシック(8,12,16,20,24,28,32,36,40)
      break;
    case 320:                                          // M5Stack Basic
      M5.Display.setFont(&fonts::lgfxJapanGothic_32);  // ゴシック(8,12,16,20,24,28,32,36,40)
      M5.Display.setTextSize(1, HH / 135.0 * 0.8);     // テキストサイズ(倍) 縦を縮める
      break;
    default:  // それ以外
      break;
  }
}
void loop() {
  currentTime = millis();                               // 現在時間
  if (currentTime - startTime < period) {               // 指定表示時間以内なら
    tmp = int16_t(sht.readTemperature() * 10.0 + 0.5);  // センサーで10倍の温度を読取る
    M5.Display.setTextColor(TFT_GREEN, TFT_BLACK);      // (文字色{,背景色})
    yy = (int32_t)(108 * HH / 135.0 + 0.5);             // y座標計算
    M5.Display.setCursor(0, yy);                        // 表示位置(x,y) 5行目
    M5.Display.printf("%5.1f℃", tmp / 10.0);            // 表示 温度

    hum = int8_t(sht.readHumidity() + 0.5);        // センサーで湿度を読取る
    M5.Display.setTextColor(TFT_CYAN, TFT_BLACK);  // (字,地)
    M5.Display.printf("%3d%%", hum);               // 表示 湿度

    pre = int16_t(bme.readPressure() / 100.0 + 0.5);  // センサーで気圧を読取る
    M5.Display.setTextColor(TFT_PINK, TFT_BLACK);     // (字,地)
    M5.Display.printf("%5dhPa\n", pre);               // 表示 気圧

    tmpIndex = int8_t(tmp / 10.0 + 0.5) - 21;  // 四捨五入で整数 配列温度番号
    humIndex = (hum - 16) / 5;                 // 配列湿度番号
    wbgt = wbgtT[tmpIndex][humIndex];          // wbgtを表から読む

    xx = (int32_t)(2 * WW / 240.0 + 0.5);     // x座標計算
    yy = (int32_t)(28 * HH / 135.0 + 0.5);    // y座標計算
    M5.Display.setCursor(xx, yy);             // 表示位置(x,y) 2行目
    yyy = (int32_t)(107 * HH / 135.0 + 0.5);  // y座標計算
    if (wbgt < 21) {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_BLUE);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_WHITE, TFT_BLUE);   // (字,地)
      M5.Display.println("ほぼ安全");                 // 表示
    } else if (wbgt < 25) {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_CYAN);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_BLACK, TFT_CYAN);   // (字,地)
      M5.Display.println("注意");                     // 表示
    } else if (wbgt < 28) {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_YELLOW);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_BLACK, TFT_YELLOW);   // (字,地)
      M5.Display.println("警戒");                       // 表示
    } else if (wbgt < 31) {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_ORANGE);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_BLACK, TFT_ORANGE);   // (字,地)
      M5.Display.println("厳重警戒");                   // 表示
    } else if (wbgt < 33) {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_RED);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_WHITE, TFT_RED);   // (字,地)
      M5.Display.println("危険");                    // 表示
    } else if (wbgt < 35) {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_VIOLET);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_WHITE, TFT_VIOLET);   // (字,地)
      M5.Display.println("警戒アラートレベル");               // 表示
    } else {
      M5.Display.fillRect(0, 0, 320, yyy, TFT_BLACK);  // 四角塗潰(x,y,w,h,色)
      M5.Display.setTextColor(TFT_WHITE, TFT_BLACK);   // (字,地)
      M5.Display.println("特別警戒アラートレベル");          // 表示
    }
    yy = (int32_t)(2 * HH / 135.0 + 0.5);       // y座標計算
    M5.Display.setCursor(0, yy);                // 表示位置(x,y) 1行目
    M5.Display.printf("(暑さ指数%d)\n", wbgt);  // 表示 wbgt

    // 不快指数
    thi = int8_t(0.081 * tmp + 0.01 * hum * (0.099 * tmp - 14.3) + 46.3 + 0.5);
    yy = (int32_t)(55 * HH / 135.0 + 0.5);      // y座標計算
    M5.Display.setCursor(0, yy);                // 表示位置(x,y) 3行目
    M5.Display.printf("(不快指数%2d)\n", thi);  // 表示 不快指数
    xx = (int32_t)(2 * WW / 240.0 + 0.5);       // x座標計算
    yy = (int32_t)(81 * HH / 135.0 + 0.5);      // y座標計算
    M5.Display.setCursor(xx, yy);               // 表示位置(x,y) 4行目
    if (thi < 50) {                             // 不快指数の感じ方
      M5.Display.println("寒くてたまらない");   // 表示 すべて8文字以下
    } else if (thi < 55) {
      M5.Display.println("寒い");
    } else if (thi < 60) {
      M5.Display.println("肌寒い");
    } else if (thi < 65) {
      M5.Display.println("何も感じない");
    } else if (thi < 70) {
      M5.Display.println("快適");
    } else if (thi < 75) {
      M5.Display.println("不快感の人がいる");
    } else if (thi < 80) {
      M5.Display.println("半数以上が不快感");
    } else if (thi < 85) {
      M5.Display.println("93%が不快感");
    } else {
      M5.Display.println("暑くてたまらない");
    }

    xx = (int32_t)(165 * WW / 240.0 + 0.5);  // x座標計算
    yy = (int32_t)(2 * HH / 135.0 + 0.5);    // y座標計算
    M5.Display.setCursor(xx, yy);            // 表示位置(x,y) 1行目
    if (WW == 128) {                         // ATOMS3はバッテリーが無いので
      M5.Display.print("BT---%%");           // 表示 バッテリ残量
    } else {
      batP = M5.Power.getBatteryLevel();   // バッテリー残量値を取得(0-100)
      M5.Display.printf("BT%3d%%", batP);  // 表示 バッテリ残量
    }

    RemainingT = (startTime + period - currentTime) / 1000;  // 残り秒数
    xx = (int32_t)(200 * WW / 240.0 + 0.5);                  // x座標計算
    yy = (int32_t)(55 * HH / 135.0 + 0.5);                   // y座標計算
    M5.Display.setCursor(xx, yy);                            // 表示位置(x,y) 3行目
    M5.Display.printf("%3d", RemainingT);                    // 電源offまでの秒数

    yy = (int32_t)(54 * HH / 135.0 + 0.5);            // y座標計算
    M5.Display.drawFastHLine(0, yy, 320, TFT_BLACK);  // 水平線(x,y,w,色)不快指数の上線

    xx = (int32_t)(164 * WW / 240.0 + 0.5);            // x座標計算
    yy = (int32_t)(1 * HH / 135.0 + 0.5);              // y座標計算
    xxx = (int32_t)(74 * WW / 240.0 + 0.5);            // w計算
    yyy = (int32_t)(26 * HH / 135.0 + 0.5);            // h計算
    M5.Display.drawRect(xx, yy, xxx, yyy, TFT_BLACK);  // 四角枠 (x,y,w,h,色) バッテリー枠

    xx = (int32_t)(198 * WW / 240.0 + 0.5);            // x座標計算
    yy = (int32_t)(56 * HH / 135.0 + 0.5);             // y座標計算
    xxx = (int32_t)(40 * WW / 240.0 + 0.5);            // w計算
    yyy = (int32_t)(21 * HH / 135.0 + 0.5);            // h計算
    M5.Display.drawRect(xx, yy, xxx, yyy, TFT_BLACK);  // 四角枠 (x,y,w,h,色) 残秒枠

    delay(5000);  // 5秒待つ
  } else {
    M5.Power.powerOff();  // 電源off
  }
}
* M5CoreInkで"2MB APP"に設定の時、flash memory(2.1Mbyte)のうち、スケッチが70%使用。RAM(328kbyte)のうち、global変数が8%使用、local変数で301kbyte使用可能。(1000byte=1kbyteで計算)