11.T-Watchをwifiで時刻合わせ


11.T-Watchをwifiで時刻合わせ

注意:この機種は技適が通っていません。中国で動作確認したスケッチとメモを日本で整理してブログ発信しています。

記入してある国名を選択すると、GMTオフセット値を得て時刻合わせをします。これは、アイコンの2行1列目をタッチします。前回のスケッチに追加します。

国の設定画面

GMTからのオフセット時間(H)
+9:Japan
+8:China
+2:Spain(夏)
+1:Portugal(夏)
-4:Canada Toronto(夏)

wifiは、WiFiMultiを使用し、3つのssidを登録し、最もRSSI(受信信号強度)の強い接続先に接続します。

前回からの大きな変更点は、3x3のタッチ入力部分を
void touch3x3()
へ移動し、
void setWifi() // wifiの設定関数
void apptimeAutoSet() // Mcase=4 wifiで時刻合わせ
を追加しました。

アイコン動作

今までに作成した関数です。
アラーム時刻時刻set(手動)
時刻set(wifi)
時計へ戻る

関数一覧

このスケッチで作成した関数です。
void SetFont() // Font等初期化関数
void printBT() // バッテリー残量表示関数
void RTCread() // RTCのデータを読込む
void SetBMA423() // 3軸加速度センサーのオプション設定と有効
void Dsleep() // 復帰はext1でdeep sleep
void flashRead() // flashのデータ読込関数
void flashWrite() // flashにデータ書込関数
void setWifi() // wifiの設定関数
void touch3x3() // 3x3タッチ入力関数
void appWatch() // Mcase=0 時計表示
void appMenu() // Mcase=10 アイコンメニュー
void appalarmSet() // Mcase=1 アラーム時刻設定
void apptimeSet() // Mcase=2 時刻合わせ 手動
void app3() // Mcase=3 未作成
void apptimeAutoSet() // Mcase=4 wifiで時刻合わせ
void app5() // Mcase=5 未作成
void app6() // Mcase=6 未作成
void app7() // Mcase=7 未作成
void app8() // Mcase=8 未作成
void appReturn() // Mcase=9 時計画面へ戻る
void setup() // setup
void loop() // loop

スケッチ

"icon9.h"も同一ホルダに必要です。"***************"は自分のssidとパスワードを記入してください。

// timeAutoSet.ino
// 国名を選択して、wifiで時刻合わせ
#include "icon9.h"  // 3x3アイコンpng1枚
// 1:目覚まし時計,2:時計+手,3:袋,4:時計+wifi
// 5:太陽,6:歯車,7:トレイ,8:風車,9:戻る
#define LGFX_AUTODETECT                 // 機種の自動認識
#include <LovyanGFX.hpp>                // ヘッダをinclude
#include <LGFX_AUTODETECT.hpp>          // クラス"LGFX"を用意
static LGFX lcd;                        // LGFXのインスタンスを作成
#define LILYGO_WATCH_2020_V3            // T-Watch2020v3を使用
#define LILYGO_WATCH_HAS_MOTOR          // 振動モータを使用
#include <LilyGoWatch.h>                // LilyGoWatchを使用
#include <FS.h>                         // ファイル操作
#include <SPIFFS.h>                     // Flashにデータ保存
#include <WiFi.h>                       // wifiを使用
#include <WiFiMulti.h>                  // wifiを複数アクセス
WiFiMulti wMulti;                       // WiFiMultiのインスタンスを準備
TTGOClass *ttgo;                        //
AXP20X_Class *power;                    // 電源管理 AXP202
PCF8563_Class *rtc;                     // PCF853 RTC(Real-Time Clock)
BMA *sensor;                            // 3軸加速度センサー BMA423
extern const unsigned char img[];       // 表示png画像1枚
uint8_t Mtouch, Mcase = 0;              // 3x3タッチ番号,メニュー番号
int16_t x, y;                           // タッチ位置変数
int8_t mmonth, dday, week, hh, mm, ss;  // 時分秒等の変数 0-255
int16_t yyear;                          // 年は16bit整数 0-65535
int8_t almH, almM;                      // アラーム時分
char dayWeek[7][4] = { "土", "日", "月", "火",
                       "水", "木", "金" };  // 曜日
uint8_t timeSetNo = 1;                      // 1:年,2:月,3:日,4:時,4:分
uint8_t touchNo;                            // 1:+1,2:SET,3:-1,10:+10,30:-10
uint32_t Stime, Ctime, period = 20 * 1000;  //開始時間,現在時間,off時間(mS)
String flashF = "/flashData.txt";           // flashに保存するtxtファイル
int8_t flashD[2];                           // flashに保存する変数 almH,almM
const char *ssid1 = "***************";      // 自分のwifiのssid
const char *pass1 = "***************";      // そのパスワード
const char *ssid2 = "***************";      // 自分の携帯1のssid
const char *pass2 = "***************";      // そのパスワード
const char *ssid3 = "***************";      // 自分の携帯2のssid
const char *pass3 = "***************";      // そのパスワード

void SetFont() {                            // Font等初期化関数
  ttgo = TTGOClass::getWatch();             // ttgoに略します
  ttgo->begin();                            // 本体の初期化
  lcd.init();                               // LCDの初期化
  lcd.setRotation(2);                       // 画面回転 0-3 (4-7で上下反転)
  lcd.setBrightness(128);                   // バックライト輝度 0-255(実際は256通りの輝度ではない)
  lcd.fillScreen(TFT_BLACK);                // 全画面黒
  lcd.setFont(&fonts::lgfxJapanGothic_28);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
  lcd.setTextColor(TFT_GREEN, TFT_BLACK);   // (緑字,黒地)
  lcd.setTextSize(1);                       // 文字サイズの倍数
  lcd.setTextWrap(true);                    // 自動折返し
}

void printBT() {                                // バッテリー残量表示関数
  lcd.setCursor(185, 0);                        // カーソル位置
  lcd.setTextSize(0.7);                         // 文字サイズ(倍)
  uint8_t per = power->getBattPercentage();     // 電池%測定
  if (power->isChargeing()) {                   // 充電中の時
    lcd.setTextColor(TFT_CYAN, TFT_BLACK);      // (水字,黒地)
    lcd.print("充");                            // 画面表示
  } else {                                      // 充電中でない時
    lcd.print(" ");                            // 画面表示
    if (per <= 20) {                            // 0-20%時
      lcd.setTextColor(TFT_RED, TFT_BLACK);     // (赤字,黒地)
    } else if (per <= 40) {                     // 21-40%
      lcd.setTextColor(TFT_YELLOW, TFT_BLACK);  // (黄字,黒地)
    } else if (per <= 80) {                     // 41-80%時
      lcd.setTextColor(TFT_GREEN, TFT_BLACK);   // (緑字,黒地)
    } else {                                    // 81-100%時
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);   // (白字,黒地)
    }
  }
  lcd.printf("%3d%%", per);  // 電池%表示
  lcd.setTextSize(1);        // 文字サイズを戻す
}

void RTCread() {                             // RTCのデータを読込む
  RTC_Date tnow = ttgo->rtc->getDateTime();  // 現在のデータを取得
  yyear = tnow.year;                         // 年
  mmonth = tnow.month;                       // 月
  dday = tnow.day;                           // 日
  hh = tnow.hour;                            // 時
  mm = tnow.minute;                          // 分
  ss = tnow.second;                          // 秒

  uint16_t yearA = yyear;  //ツェラーの公式 年月日から曜日weekを求める
  uint8_t monthA = mmonth;
  if (monthA < 3) {
    monthA += 12;
    yearA--;
  }
  uint16_t year1 = yearA / 100;
  uint16_t year2 = yearA % 100;
  week = (dday + (int)(26 * (monthA + 1) / 10) + year2 + (int)(year2 / 4)
          + (5 * year1) + (int)(year1 / 4))
         % 7;
}

void SetBMA423() {                                 // 3軸加速度センサーのオプション設定と機能を有効
  Acfg cfg;                                        // BMA423パラメータの構造
  cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ;           // BMA423の出力データレート(0_78~1600)
  cfg.range = BMA4_ACCEL_RANGE_2G;                 // BMA423の±重力範囲(2~16)
  cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4;          // BMA423の平均化サンプル数2^x x=4の時2^4=16サンプルの平均値
  cfg.perf_mode = BMA4_CONTINUOUS_MODE;            // BMA423のフィルター性能モード 平均化無し
  sensor->accelConfig(cfg);                        // BMA423で上記の設定
  sensor->enableAccel();                           // BMA423を有効
  sensor->enableFeature(BMA423_STEP_CNTR, false);  // 歩数割込機能isStepCounterを無効にする
  sensor->enableFeature(BMA423_TILT, true);        // 傾き割込機能isTiltを有効にする
  sensor->enableFeature(BMA423_WAKEUP, true);      // クリック割込機能isDoubleClickを有効にする
}

void Dsleep() {                                // 復帰はext1でdeep sleep
  ttgo->displaySleep();                        // 画面とタッチをスリープする
  power->setPowerOutPut(AXP202_LDO3, false);   // LDO3出力off 使用禁止
  power->setPowerOutPut(AXP202_LDO4, false);   // LDO4出力off MAX98357A Audio
  power->setPowerOutPut(AXP202_LDO2, false);   // LCD_VDD出力off バックライト
  power->setPowerOutPut(AXP202_EXTEN, false);  // (この電源チャンネルは不使用 使用禁止)
  power->setPowerOutPut(AXP202_DCDC2, false);  // (この電源チャンネルは不使用)
  //esp_sleep_enable_ext0_wakeup((gpio_num_t)BMA423_INT1, HIGH);        // 外部復帰はext0を使用の時
  esp_sleep_enable_ext1_wakeup(GPIO_SEL_39, ESP_EXT1_WAKEUP_ANY_HIGH);  // BMA423外部復帰はext1を使用
  esp_deep_sleep_start();                                               // deep sleep開始
}

void flashRead() {                                       // flashのデータ読込関数
  fs::File flashF = SPIFFS.open("/flashData.txt", "r");  // ファイルを読込モードで開く
  if (flashF) {                                          // ファイルが開けば
    for (uint8_t i = 0; i < sizeof(flashD); i++) {       // すべて読込む
      flashD[i] = flashF.read();                         // 読込んだデータを配列に保存
    }
    flashF.close();    // ファイルをclose
    almH = flashD[0];  // almHに代入
    almM = flashD[1];  // almMに代入
  } else {             // ファイルが開かないなら
    almH = 0;          // 0にする
    almM = 0;          // 0にする
  }
}

void flashWrite() {                                      // flashにデータ書込関数
  fs::File flashF = SPIFFS.open("/flashData.txt", "w");  // ファイルを書込モードで開く
  if (!flashF) {                                         // ファイルが開けなければ
    lcd.println("Flash 書込 Error");                     // 表示
    return;                                              // 戻る
  }                                                      // ファイルが開けば
  flashF.write(almH);                                    // almHを書込む
  flashF.write(almM);                                    // almMを書込む
  flashF.close();                                        // ファイルをclose
}

void setWifi() {                           // wifiの設定関数
  lcd.println("時刻のwifi設定");           // 表示
  wMulti.addAP(ssid1, pass1);              // wifiを初期化し設定1
  wMulti.addAP(ssid2, pass2);              // wifiを初期化し設定2
  wMulti.addAP(ssid3, pass3);              // wifiを初期化し設定3
  lcd.println("wifiに接続開始");           // 表示
  while (WiFi.status() != WL_CONNECTED) {  // 接続完まで繰返す
    wMulti.run();                          // WiFiMultiを実行
    delay(500);                            // 接続実行後は少し待つ
    lcd.println("wifiに接続中");           // 表示
  }
  lcd.print(WiFi.SSID());  // ssidを表示
  lcd.println("に接続");   // 表示
}

void touch3x3() {              // 3x3タッチ入力関数
  Mtouch = 10;                 // タッチ変数初期値
  delay(100);                  // 0.1秒待つ
  if (ttgo->getTouch(x, y)) {  // タッチしたらx,yを読取る
    ttgo->motor->onec();       // モータを振動(0.2秒程度)
    delay(250);                // 250mS待つ 連続:-200 不連続:250-
    if (y < 80) {              // 1行目なら
      if (x < 80) {            // 1行1列目なら
        Mtouch = 1;            // アイコン1をタッチ
      } else if (x < 160) {    // 1行2列目なら
        Mtouch = 2;            // アイコン2をタッチ
      } else {                 // 1行3列目なら
        Mtouch = 3;            // アイコン3をタッチ
      }
    } else if (y < 160) {    // 2行目なら
      if (x < 80) {          // 2行1列目なら
        Mtouch = 4;          // アイコン4をタッチ
      } else if (x < 160) {  // 2行2列目なら
        Mtouch = 5;          // アイコン5をタッチ
      } else {               // 2行3列目なら
        Mtouch = 6;          // アイコン6をタッチ
      }
    } else {                 // 3行目なら
      if (x < 80) {          // 3行1列目なら
        Mtouch = 7;          // アイコン7をタッチ
      } else if (x < 160) {  // 3行2列目なら
        Mtouch = 8;          // 足婚8をタッチ
      } else {               // 3行3列目なら
        Mtouch = 9;          // アイコン9をタッチ
      }
    }
  }
}

//-------------------------------------------------// 0 時計
void appWatch() {             // Mcase=0 時計表示
  Stime = millis();           // 開始時間(mS)
  lcd.fillScreen(TFT_BLACK);  // 全画面黒
  do {
    RTCread();                                // RTCデータを読み込む
    lcd.setTextColor(TFT_GREEN, TFT_BLACK);   // (字,地)
    lcd.setFont(&fonts::lgfxJapanGothic_28);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
    lcd.setTextSize(1, 1.8);                  // 文字サイズ(倍)
    lcd.setCursor(0, 66 * 0 + 43 + 5);        // カーソル位置 [AM/PM]
    uint8_t hhh;                              // hhの12時間用
    if (hh > 12) {                            // PM時
      hhh = hh - 12;                          // 12時間表示
      lcd.print("PM");                        // 表示
    } else {                                  // AM時
      hhh = hh;                               // そのまま
      lcd.print("AM");                        // 表示
    }
    lcd.setTextSize(1);  // 文字サイズ(倍)

    lcd.setCursor(60, 66 * 0 + 43);    // カーソル位置
    lcd.setFont(&fonts::Font7);        // Font 7セグ
    lcd.printf("%02d:%02d", hhh, mm);  // 時:分を表示

    lcd.setCursor(60, 66 * 1 + 43);       // カーソル位置
    lcd.printf("%02d:%02d", almH, almM);  // アラーム時:分を表示

    lcd.setFont(&fonts::lgfxJapanGothic_28);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
    lcd.setTextSize(2.3, 2);                  // 文字サイズ 倍(横,縦)
    lcd.setCursor(70, 66 * 2 + 43 - 5);       // カーソル位置
    int16_t mmm = almH * 60 + almM
                  - hh * 60 - mm;              // 残り分計算
    if (mmm < -60) mmm = 0;                    // 60分以上前は0とする
    if (mmm <= 0) {                            // 過去の設定時刻なら
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (白字,地)
    } else if (mmm <= 5) {                     // 設定時刻が5分以内なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);    // (赤字,地)
    }
    lcd.printf("%4d", mmm);                  // 残り分を表示
    lcd.setTextColor(TFT_GREEN, TFT_BLACK);  // (字,地)

    lcd.setFont(&fonts::lgfxJapanGothic_28);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
    lcd.setTextSize(0.7, 1.6);                // 文字サイズ(倍)
    lcd.setCursor(0, 66 * 1 + 43 + 5);        // カーソル位置 [アラーム時:分]
    lcd.print("設定");                        // 表示

    lcd.setCursor(0, 66 * 2 + 43 + 5);  // カーソル位置 [残り分]
    lcd.print("あと");                  // 表示

    lcd.setCursor(200, 66 * 2 + 43);  // カーソル位置 [残り分]
    lcd.print("分");                  // 表示
    lcd.setTextSize(1);               // 文字サイズ戻す

    printBT();                   // バッテリー残量表示関数へ
    if (ttgo->getTouch(x, y)) {  // タッチしたら
      ttgo->motor->onec();       // モータを振動(0.2秒程度)
      delay(250);                // 250mS待つ 連続:-200 不連続:250-
      Mcase = 10;                // メニューへ
    }

    int16_t x0 = 210, y0 = 85, dy = 4;                         // 一番下の横線の書始めx,yと線間の刻み
    if (ss < 5) {                                              // 5秒未満なら 5秒ごとに横線を引く
      lcd.fillRect(x0, y0 - dy * 11, 30, dy * 11, TFT_BLACK);  // 四角塗潰(x,y,w,h,色)
      lcd.drawFastHLine(x0, y0 - dy * 0, 30, TFT_DARKGREY);    // 水平線(X,y,W,色)
    } else if (ss < 10) {                                      // 5秒以上10秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 1, 30, TFT_DARKGREY);    // 水平線(X,y,W,色)
    } else if (ss < 15) {                                      // 10秒以上15秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 2, 30, TFT_BROWN);       // 水平線(X,y,W,色)
    } else if (ss < 20) {                                      // 15秒以上20秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 3, 30, TFT_BROWN);       // 水平線(X,y,W,色)
    } else if (ss < 25) {                                      // 20秒以上25秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 4, 30, TFT_RED);         // 水平線(X,y,W,色)
    } else if (ss < 30) {                                      // 25秒以上30秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 5, 30, TFT_RED);         // 水平線(X,y,W,色)
    } else if (ss < 35) {                                      // 30秒以上35秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 6, 30, TFT_ORANGE);      // 水平線(X,y,W,色)
    } else if (ss < 40) {                                      // 35秒以上40秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 7, 30, TFT_ORANGE);      // 水平線(X,y,W,色)
    } else if (ss < 45) {                                      // 40秒以上45秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 8, 30, TFT_YELLOW);      // 水平線(X,y,W,色)
    } else if (ss < 50) {                                      // 45秒以上50秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 9, 30, TFT_YELLOW);      // 水平線(X,y,W,色)
    } else if (ss < 55) {                                      // 50秒以上55秒未満なら
      lcd.drawFastHLine(x0, y0 - dy * 10, 30, TFT_GREEN);      // 水平線(X,y,W,色)
    } else {                                                   // 55秒以上なら
      lcd.drawFastHLine(x0, y0 - dy * 11, 30, TFT_GREEN);      // 水平線(X,y,W,色)
    }

    Ctime = millis();               // 現在時間
    if (Ctime - Stime >= period) {  // 判定時間が経過したら
      Dsleep();                     // deep sleep
    }
  } while (Mcase == 0);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 10
void appMenu() {                                  // Mcase=10 アイコンメニュー
  lcd.drawPng((std::uint8_t *)img, 34644, 7, 7);  // png表示 (配列名,サイズ,x,y)
  delay(1);                                       // 1mS待つ
  do {
    touch3x3();           // 3x3タッチ入力関数へ
    Mcase = Mtouch;       // アイコン番号へ
  } while (Mcase == 10);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 1
void appalarmSet() {                       // Mcase=1 アラーム時刻設定
  RTCread();                               // RTCデータを読込む
  lcd.setCursor(40, 0);                    // カーソル位置
  lcd.setTextColor(TFT_GREEN, TFT_BLACK);  // (字,地)
  lcd.setTextSize(0.9);                    // 文字サイズの倍数
  lcd.print("アラーム設定");               // 表示 タイトル
  lcd.setTextSize(1.6);                    // 文字サイズの倍数
  lcd.setCursor(20, 85);                   // カーソル位置 タッチ表示用
  lcd.print("+10  -10");                 // 表示
  lcd.setCursor(30, 165);                  // カーソル位置 タッチ表示用
  lcd.print("+ SET -");                  // 表示
  lcd.setTextSize(1);                      // 文字サイズの倍数
  timeSetNo = 4;                           // 時から始める

  do {
    delay(100);                              // 100mS待つ
    lcd.setTextSize(1.6);                    // 文字サイズの倍数
    lcd.setCursor(60, 30);                   // カーソル位置 時:分
    if (timeSetNo == 4) {                    // 時の変更なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%02d", hh);                  // 表示 時
    lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    lcd.print(":");                          // 表示
    if (timeSetNo == 5) {                    // 分の変更なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%02d", mm);  // 表示 分
    lcd.setTextSize(1);      // 文字サイズを戻す

    if (ttgo->getTouch(x, y)) {  // タッチしたらx,yを読取る
      delay(100);                // 100mS待つ
      if (y < 150) {             // タッチ上段なら
        if (x < 120) {           // 上段左側なら
          touchNo = 10;          // +10
        } else {                 // 上段右側なら
          touchNo = 30;          // -10
        }
      } else {                 // タッチ下段なら
        if (x < 80) {          // 下段左側なら
          touchNo = 1;         // +1
        } else if (x < 160) {  // 下段中央なら
          touchNo = 2;         // SET
        } else {               // 下段右側なら
          touchNo = 3;         // -1
        }
      }
    }
    switch (timeSetNo) {                // する動作の場所
      case 4:                           // 時なら
        if (touchNo == 1) hh++;         // +は1up
        if (touchNo == 3) hh--;         // -は1down
        if (touchNo == 10) hh += 10;    // +10は10up
        if (touchNo == 30) hh -= 10;    // -10は10down
        if (hh > 23) hh = 23;           // ~23時とする
        if (hh < 0) hh = 0;             // 0時~とする
        if (touchNo == 2) timeSetNo++;  // SETは次の設定 分へ
        break;
      case 5:                         // 分なら
        if (touchNo == 1) mm++;       // +は1up
        if (touchNo == 3) mm--;       // -は1down
        if (touchNo == 10) mm += 10;  // +10は10up
        if (touchNo == 30) mm -= 10;  // -10は10down
        if (mm > 59) mm = 59;         // ~59分とする
        if (mm < 0) mm = 0;           // 0分~とする
        if (touchNo == 2) {           // SETなら
          almH = hh;                  // アラーム時
          almM = mm;                  // アラーム分
          flashWrite();               // flashにデータ書込関数へ
          Mcase = 0;                  // 時計画面へ
        }
        break;
      default:  // それ以外
        break;
    }
    touchNo = 0;         // 勝手にループ動作しないように
  } while (Mcase == 1);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 2 時刻設定
void apptimeSet() {                        // Mcase=2 時刻合わせ 手動
  RTCread();                               // RTCデータを読込む
  lcd.setCursor(70, 0);                    // カーソル位置
  lcd.setTextColor(TFT_GREEN, TFT_BLACK);  // (字,地)
  lcd.setTextSize(0.9);                    // 文字サイズの倍数
  lcd.print("時刻設定");                   // 表示タイトル
  lcd.setTextSize(1.6);                    // 文字サイズの倍数
  lcd.setCursor(20, 165);                  // カーソル位置 タッチ表示用
  lcd.print("+ SET -");                  // 表示
  lcd.setTextSize(1);                      // 文字サイズの倍数
  timeSetNo = 1;                           // 年から始める
  do {
    delay(100);                              // 100mS待つ
    lcd.setTextSize(1.6);                    // 文字サイズの倍数
    lcd.setCursor(10, 40);                   // カーソル位置 年月日
    if (timeSetNo == 1) {                    // 変更場所が年なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%4d", yyear);                // 表示 年
    lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    lcd.print("/");                          // 表示
    if (timeSetNo == 2) {                    // 月なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%02d", mmonth);              // 表示 月
    lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    lcd.print("/");                          // 表示
    if (timeSetNo == 3) {                    // 日なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%02d", dday);                // 表示 日
    lcd.setCursor(60, 90);                   // カーソル位置 時分
    if (timeSetNo == 4) {                    // 時なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%02d", hh);                  // 表示 時
    lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    lcd.print(":");                          // 表示
    if (timeSetNo == 5) {                    // 分なら
      lcd.setTextColor(TFT_RED, TFT_BLACK);  // (字,地)
    } else {
      lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
    }
    lcd.printf("%02d", mm);  // 表示 分
    lcd.setTextSize(1);      // 文字サイズを戻す

    if (ttgo->getTouch(x, y)) {  // タッチしたらx,yを読取る
      delay(100);                // 100mS待つ
      if (x < 80) {              // 左側なら
        touchNo = 1;             // +
      } else if (x < 160) {      // 中央なら
        touchNo = 2;             // SET
      } else {                   // 右側なら
        touchNo = 3;             // -
      }
      switch (timeSetNo) {                   // する動作の場所
        case 1:                              // 年で
          if (touchNo == 1) {                // +なら
            yyear++;                         // 1up
            if (yyear > 2026) yyear = 2026;  // ~2026年とする
          } else if (touchNo == 3) {         // -なら
            yyear--;                         // 1down
            if (yyear < 2024) yyear = 2024;  // 2024年~とする
          } else {                           // SETなら
            timeSetNo++;                     // 次の設定 月へ
          }
          break;
        case 2:                            // 月で
          if (touchNo == 1) {              // +なら
            mmonth++;                      // 1up
            if (mmonth > 12) mmonth = 12;  // ~12月とする
          } else if (touchNo == 3) {       // -なら
            mmonth--;                      // 1down
            if (mmonth < 1) mmonth = 1;    // 1月~とする
          } else {                         // SETなら
            timeSetNo++;                   // 次の設定 日へ
          }
          break;
        case 3:                        // 日で
          if (touchNo == 1) {          // +なら
            dday++;                    // 1up
            if (dday > 31) dday = 31;  // ~31日とする
          } else if (touchNo == 3) {   // -なら
            dday--;                    // 1down
            if (dday < 1) dday = 1;    // 1日~とする
          } else {                     // SETなら
            timeSetNo++;               // 次の設定 時へ
          }
          break;
        case 4:                       // 時で
          if (touchNo == 1) {         // +なら
            hh++;                     // 1up
            if (hh > 23) hh = 23;     // ~23時とする
          } else if (touchNo == 3) {  // -なら
            hh--;                     // 1down
            if (hh < 0) hh = 0;       // 0時~とする
          } else {                    // SETなら
            timeSetNo++;              // 次の設定 分へ
          }
          break;
        case 5:                                                       // 分で
          if (touchNo == 1) {                                         // +なら
            mm++;                                                     // 1up
            if (mm > 59) mm = 59;                                     // ~59分とする
          } else if (touchNo == 3) {                                  // -なら
            mm--;                                                     // 1down
            if (mm < 0) mm = 0;                                       // 0分~とする
          } else {                                                    // SETなら
            ttgo->rtc->setDateTime(yyear, mmonth, dday, hh, mm, 30);  // RTCに書込む
            Mcase = 0;                                                // 時計画面へ
          }
          break;
        default:  // それ以外
          break;
      }
    }
  } while (Mcase == 2);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 3
void app3() {                              // Mcase=3 未作成
  lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
  lcd.print("メニュー3");                  // 表示
  delay(1000);                             // 1秒待つ
  do {
    delay(100);                  // 0.1秒待つ
    if (ttgo->getTouch(x, y)) {  // タッチしたら
      ttgo->motor->onec();       // モータを振動(0.2秒程度)
      delay(250);                // 250mS待つ 連続:-200 不連続:250-
      Mcase = 0;                 // 時計画面へ
    }
  } while (Mcase == 3);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 4 wifiで時刻
void apptimeAutoSet() {             // Mcase=4 wifiで時刻合わせ
  lcd.fillScreen(TFT_BLACK);        // 全画面黒 改頁
  uint8_t i, j, di1 = 75, di2 = 7;  // di1:枠の大きさ,di2:枠間
  for (i = 0; i < 3; i++) {         // x方向3回
    for (j = 0; j < 3; j++) {       // y方向3回
      lcd.drawRoundRect((di1 + di2) * i, (di1 + di2) * j,
                        di1, di1, 5, TFT_GREEN);  // 角丸枠(x,y,w,h,r,color)
    }
  }
  lcd.setFont(&fonts::lgfxJapanGothic_20);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
  lcd.setTextColor(TFT_CYAN, TFT_BLACK);    // (字,地)

  lcd.setCursor(0 + 12, 27);  // カーソル位置
  lcd.print("Japan");         // 表示 1行1列目

  lcd.setCursor(82 + 12, 27);  // カーソル位置
  lcd.print("China");          // 表示 1行2列目

  lcd.setCursor(164 + 12, 27 - 14);  // カーソル位置
  lcd.print("Spain");                // 表示 1行3列目上
  lcd.setCursor(164 + 20, 27 + 14);  // カーソル位置
  lcd.print("(夏)");                 // 表示 1行3列目下

  lcd.setCursor(0 + 5, 82 + 27 - 10);       // カーソル位置
  lcd.setFont(&fonts::lgfxJapanGothic_16);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
  lcd.print("Portugal");                    // 表示 2行1列目上 20でサイズ=0.9は字が消える
  lcd.setFont(&fonts::lgfxJapanGothic_20);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40
  lcd.setCursor(0 + 20, 82 + 27 + 14);      // カーソル位置
  lcd.print("(夏)");                        // 表示 2行1列目下

  lcd.setCursor(82 + 7, 82 + 27 - 20);   // カーソル位置
  lcd.print("Canada");                   // 表示 2行2列目上
  lcd.setCursor(82 + 2, 82 + 27);        // カーソル位置
  lcd.print("Toronto");                  // 表示 2行2列目中
  lcd.setCursor(82 + 20, 82 + 27 + 20);  // カーソル位置
  lcd.print("(夏)");                     // 表示 2行2列目下

  lcd.setCursor(164 + 17, 82 + 27);  // カーソル位置
  lcd.print("予備");                 // 表示 2行3列目

  lcd.setCursor(0 + 17, 164 + 27);  // カーソル位置
  lcd.print("予備");                // 表示 3行1列目

  lcd.setCursor(82 + 17, 164 + 27);  // カーソル位置
  lcd.print("予備");                 // 表示 3行2列目

  lcd.setCursor(164 + 17, 164 + 27);        // カーソル位置
  lcd.print("予備");                        // 表示 3行3列目
  lcd.setFont(&fonts::lgfxJapanGothic_28);  // 固定幅ゴシック体 8,12,16,20,24,28,32,36,40

  do {
    touch3x3();            // 3x3タッチ入力関数へ
  } while (Mtouch == 10);  // Mtouchが変わるまでループ

  int8_t gmt;        // GMTオフセット
  switch (Mtouch) {  // タッチした場所のGMTオフセットを得る
    case 1:          // Japan
      gmt = 9;       // +9H
      break;
    case 2:     // China
      gmt = 8;  // +8H
      break;
    case 3:     // Spain(夏)
      gmt = 2;  // +2H
      break;
    case 4:     // Portugal(夏)
      gmt = 1;  // +1H
      break;
    case 5:      // Canada Toronto(夏)
      gmt = -4;  // -4H
      break;
    case 6:     // 空き
    case 7:     // 空き
    case 8:     // 空き
    case 9:     // 空き
      gmt = 9;  // +9H Japanとする
      break;
  }

  lcd.setTextColor(TFT_WHITE, TFT_BLACK);        // (字,地)
  lcd.fillScreen(TFT_BLACK);                     // 全画面黒 改頁
  lcd.setCursor(0, 0);                           // カーソル位置
  setWifi();                                     // wifi設定関数へ
  lcd.println("NTPに接続中");                    // 表示
  configTime(gmt * 60 * 60, 0, "ntp.nict.jp");   // (GMTとの差(秒),夏時間(秒),NTPサーバ)
  struct tm timeInfo;                            // 構造体タグ名tmを変数timeinfoとする
  if (!getLocalTime(&timeInfo)) {                // 時刻を取得できなかったら
    lcd.println("時間取得失敗\n3秒後に再起動");  // 表示
    delay(3000);                                 // 3秒待つ
    esp_restart();                               // ESP32をリスタート
    while (1) {};                                // ここへは来ない
  }
  lcd.fillScreen(TFT_BLACK);                                // 全画面黒 改頁
  lcd.setCursor(0, 0);                                      // カーソル位置
  lcd.println("wifiを切断");                                // 表示
  WiFi.disconnect(true);                                    // WiFiネットワークから切断
  yyear = timeInfo.tm_year + 1900;                          // 年
  mmonth = timeInfo.tm_mon + 1;                             // 月
  dday = timeInfo.tm_mday;                                  // 日
  hh = timeInfo.tm_hour;                                    // 時
  mm = timeInfo.tm_min;                                     // 分
  ss = timeInfo.tm_sec;                                     // 秒
  ttgo->rtc->setDateTime(yyear, mmonth, dday, hh, mm, ss);  // RTCに書込む
  lcd.println("同期完");                                    // 表示
  lcd.printf("%d/%d/%d\n%d:%d:%d\n",
             yyear, mmonth, dday, hh, mm, ss);  // 表示
  delay(3000);                                  // 3秒待つ
  Mcase = 0;                                    // 時計画面へ
}

//-------------------------------------------------// 5
void app5() {                              // Mcase=5 未作成
  lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
  lcd.print("メニュー5");                  // 表示
  delay(1000);                             // 1秒待つ
  do {
    delay(100);                  // 0.1秒待つ
    if (ttgo->getTouch(x, y)) {  // タッチしたら
      ttgo->motor->onec();       // モータを振動(0.2秒程度)
      delay(250);                // 250mS待つ 連続:-200 不連続:250-
      Mcase = 0;                 // 時計画面へ
    }
  } while (Mcase == 5);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 6
void app6() {                              // Mcase=6 未作成
  lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
  lcd.print("メニュー6");                  // 表示
  delay(1000);                             // 1秒待つ
  do {
    delay(100);                  // 0.1秒待つ
    if (ttgo->getTouch(x, y)) {  // タッチしたら
      ttgo->motor->onec();       // モータを振動(0.2秒程度)
      delay(250);                // 250mS待つ 連続:-200 不連続:250-
      Mcase = 0;                 // 時計画面へ
    }
  } while (Mcase == 6);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 7
void app7() {                              // Mcase=7 未作成
  lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
  lcd.print("メニュー7");                  // 表示
  delay(1000);                             // 1秒待つ
  do {
    delay(100);                  // 0.1秒待つ
    if (ttgo->getTouch(x, y)) {  // タッチしたら
      ttgo->motor->onec();       // モータを振動(0.2秒程度)
      delay(250);                // 250mS待つ 連続:-200 不連続:250-
      Mcase = 0;                 // 時計画面へ
    }
  } while (Mcase == 7);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 8
void app8() {                              // Mcase=8 未作成
  lcd.setTextColor(TFT_WHITE, TFT_BLACK);  // (字,地)
  lcd.print("メニュー8");                  // 表示
  delay(1000);                             // 1秒待つ
  do {
    delay(100);                  // 0.1秒待つ
    if (ttgo->getTouch(x, y)) {  // タッチしたら
      ttgo->motor->onec();       // モータを振動(0.2秒程度)
      delay(250);                // 250mS待つ 連続:-200 不連続:250-
      Mcase = 0;                 // 時計画面へ
    }
  } while (Mcase == 8);  // Mcaseが変わるまでループ
}

//-------------------------------------------------// 9 時計画面へ
void appReturn() {  // Mcase=9 時計画面へ戻る
  Mcase = 0;        // 時計画面へ
}

//-------------------------------------------------//
void setup() {
  SetFont();                   // Font等初期化関数へ
  ttgo->motor_begin();         // 振動モータの初期設定
  ttgo->motor->onec();         // モータを振動(0.2秒程度)
  power = ttgo->power;         // 簡単に書けるようにオブジェクトを受取る
  sensor = ttgo->bma;          // 簡単に書けるようにオブジェクトを受取る
  SetBMA423();                 // 3軸加速度センサーの設定
  sensor->resetStepCounter();  // 割込機能のリセット
  //sensor->enableStepCountInterrupt(); // 歩数による割込を有効にする しない
  sensor->enableTiltInterrupt();    // 傾きによる割込を有効にする
  sensor->enableWakeupInterrupt();  // ダブルクリックによる割込を有効にする
  //////////////////// //////////////////// ////////////////////
  //SPIFFS.format();  // 初回のみ有効、プログラム動作はしません。次回からは注釈にする
  //////////////////// //////////////////// ////////////////////
  if (!SPIFFS.begin()) {          // SPIFFSの初期化ができなければ
    lcd.println("SPIFFS Error");  // エラー表示
  }
  flashRead();  // flashのデータ読込関数へ almH,almM
}

void loop() {
  switch (Mcase) {  // 表示状態
    case 0:
      appWatch();  // 0.時計へ
      break;
    case 1:
      appalarmSet();  // 1.アラーム時分設定
      break;
    case 2:
      apptimeSet();  // 2.時刻合わせ
      break;
    case 3:
      app3();  // 3.未作成
      break;
    case 4:
      apptimeAutoSet();  // 4.wifiで時刻合わせ
      break;
    case 5:
      app5();  // 5.未作成
      break;
    case 6:
      app6();  // 6.未作成
      break;
    case 7:
      app7();  // 7.未作成
      break;
    case 8:
      app8();  // 8.未作成
      break;
    case 9:
      appReturn();  // 9.時計画面へ戻る
      break;
    case 10:
      appMenu();  // 10.メニュー画面へ
      break;
    default:  // それ以外
      break;
  }
  delay(100);                 // 100mS待つ
  lcd.fillScreen(TFT_BLACK);  // 全画面黒
}
* flash memory(6.5Mbyte)のうち、スケッチが27%使用。RAM(4.5Mbyte)のうち、global変数が1%使用、local変数で4.5Mbyte使用可能。(1000byte=1kbyteで計算)