趣味の開発ノート

ITの学習やプログラミング・ノーコードアプリ開発のことなど。

【M5Stack】スケッチ例「TFT_Clock_Digital」を読み解く03. 時間の経過判定と時刻を表示する仕組みの理解

M5Stackで電子工作ができるようになりたくて、練習中。
一定間隔でセンサ値をデータベース(Spreadsheet)に送るような仕組みを作ることを目的に、タイマー周りの機能を調べている。

サンプルスケッチ「TFT_Clock_Digital」について読解しながら、どういうスケッチの構造になっているのかを学んでいる。
(このスケッチは、Arduino IDEのメニューから、「ファイル」>「スケッチ例」>「M5Stack」>「Advanced」>「Display」>「TFT_Clock_Digital」から開くことができる。)

f:id:massa_potato:20220219113845j:plain

前回は、グローバルで定義されている変数を一部見てみた。

nouka-it.hatenablog.com

今回は、loop()関数の中身を見ていって、スケッチの構造を理解したいと思う。

loop()関数の構造

loop関数は、このような構造になっている。

  1. 前回表示から1秒経っているかどうかをtargetTimeで判断
  2. 前回表示から1秒経っていれば、表示するための時hh・分mm・秒ssを再計算する
  3. 計算された時hh・分mm・秒ssでM5Stack画面の表示をアップデートする

それぞれのパートに分けてみていく。

(1)1秒の経過を判断

まず、1つ目のパート。

void loop() {

    // (1) 前回表示から1秒経っているかどうかをtargetTimeで判断
    if (targetTime < millis()) {
        targetTime = millis() + 1000;

        // 省略
     }
}

loop()関数が起動した時点で、targetTime変数には「前回画面表示をアップデートした時点での時刻 + 1秒」の値が入っている。
コンパイル時からの起動時間をmills()関数でミリ秒として取得して、それに1000ミリ秒(=1秒)を加算した値が入っている。)
そのtargetTime変数と現時点のmills()を比べて、前回から1秒が経過しているかどうかをif文で判断している。

1秒経っていれば、再びtrgetTimeに1000ミリ秒(=1秒)を加算して、次の処理に移る。

(2) 表示のための時・分・秒を再計算

次に、if文の中身で実行される2つ目のパート。

void loop() {

    if (targetTime < millis()) {
        // 省略
  
        // (2) 前回表示から1秒経っていれば、表示するための時hh・分mm・秒ssを再計算する 
        ss++;              // Advance second
        if (ss == 60) {    // Check for roll-over
            ss = 0;          // Reset seconds to zero
            omm = mm;        // Save last minute time for display update
            mm++;            // Advance minute
             if (mm > 59) {   // Check for roll-over
                 mm = 0;
                 hh++;          // Advance hour
                    if (hh > 23) { // Check for 24hr roll-over (could roll-over on 13)
                        hh = 0;      // 0 for 24 hour clock, set to 1 for 12 hour clock
                    }
               }
           }

   // 省略
}

ここでは、表示するための時hh・分mm・秒ssを再計算している。
まず秒の表示ssに1秒足して、60になったら値を0にして繰り上げる。
同じように分の表示mmも60で値を0にして繰り上げ、時の表示hhも24になると0に戻るというロジック。

ちなみに12時間表示にする場合は、このhh > 23の条件式をhh > 11として、次の行をhh = 1と書き換えてやればよさそうだ。

(3) 画面をアップデートする

最後にディスプレイに表示するパート。

void loop() {
    // 省略

    // (3)計算された時hh・分mm・秒ssでM5Stack画面の表示をアップデートする
    int xpos = 0;
    int ypos = 85; // Top left corner ot clock text, about half way down
    int ysecs = ypos + 24;

    if (omm != mm) { // Redraw hours and minutes time every minute
      omm = mm;
      // Draw hours and minutes
      if (hh < 10) xpos += M5.Lcd.drawChar('0', xpos, ypos, 8); // Add hours leading zero for 24 hr clock
      xpos += M5.Lcd.drawNumber(hh, xpos, ypos, 8);             // Draw hours
      xcolon = xpos; // Save colon coord for later to flash on/off later
      xpos += M5.Lcd.drawChar(':', xpos, ypos - 8, 8);
      if (mm < 10) xpos += M5.Lcd.drawChar('0', xpos, ypos, 8); // Add minutes leading zero
      xpos += M5.Lcd.drawNumber(mm, xpos, ypos, 8);             // Draw minutes
      xsecs = xpos; // Sae seconds 'x' position for later display updates
    }
    if (oss != ss) { // Redraw seconds time every second
      oss = ss;
      xpos = xsecs;

      if (ss % 2) { // Flash the colons on/off
        M5.Lcd.setTextColor(0x39C4, TFT_BLACK);        // Set colour to grey to dim colon
        M5.Lcd.drawChar(':', xcolon, ypos - 8, 8);     // Hour:minute colon
        xpos += M5.Lcd.drawChar(':', xsecs, ysecs, 6); // Seconds colon
        M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK);    // Set colour back to yellow
      }
      else {
        M5.Lcd.drawChar(':', xcolon, ypos - 8, 8);     // Hour:minute colon
        xpos += M5.Lcd.drawChar(':', xsecs, ysecs, 6); // Seconds colon
      }

      //Draw seconds
      if (ss < 10) xpos += M5.Lcd.drawChar('0', xpos, ysecs, 6); // Add leading zero
      M5.Lcd.drawNumber(ss, xpos, ysecs, 6);                     // Draw seconds
    }
  }
}

ちょっと長いのでポイントだけ。

  • hh・分mm・秒ssの数値が1桁の時は、頭を0埋めして表示
  • 変数ommは前回のアップデート時の分の数値が入っていて、もし今回のmmと異なっていたら、分の表示をアップデートする処理を記述している。
  • 変数ossも同様で、前回のアップデート時の秒の数値が入っている。
  • ssと連動してコロンの色が点滅。奇数の時にグレー、偶数の時に黄色で表示。

今回のまとめ

今回は、loop()関数の構造を見てきた。

細かいところは端折ったけど、こ子まででサンプルスケッチ「TFT_Clock_Digital」で何が行われているのかは一通り読解できたかなと思う。