M5Stackで電子工作ができるようになりたくて、練習中。
一定間隔でセンサ値をデータベース(Spreadsheet)に送るような仕組みを作ることを目的に、タイマー周りの機能を調べている。
サンプルスケッチ「TFT_Clock_Digital」について読解しながら、どういうスケッチの構造になっているのかを学んでいる。
(このスケッチは、Arduino IDEのメニューから、「ファイル」>「スケッチ例」>「M5Stack」>「Advanced」>「Display」>「TFT_Clock_Digital」から開くことができる。)
前回は、setup()
関数の中身を見てみた。
今回はloop()
関数の中身を見ていきたいんだけど、その前にグローバルで定義されている変数と関数を理解する必要がありそうなので、そちらを見ていく。
グローバル定義
▼サンプルスケッチ TFT_Clock_Digitalのグローバル定義
#include <M5Stack.h> #define TFT_GREY 0x5AEB uint32_t targetTime = 0; // for next 1 second timeout static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time byte omm = 99, oss = 99; byte xcolon = 0, xsecs = 0; unsigned int colour = 0;
この中で、今回見ていきたいのが以下の3種類の変数。
- uint32_t型 変数 targetTime
- uint8_t型 関数 conv2d
- uint8_t型 変数 hh, mm, ss
uint32_t, uint8_t型について
まず、uint32_t, uint8_t型については、C99(C言語の規格)から使える比較的新しい(?)整数型らしい。
旧来のchar, short, intとそれぞれの型の符号無しバージョンunsigned char, unsigned short, unsigned intなどの型の代わりに使えて、一目でわかりやすい型名になっているのが利点らしい。
例としてuint32_tについてみてみると、
uint
とuがついているので符号無しの整数型(int
だと符号有りの整数型)- 数字
32
はビット数を表す
という意味。つまり、
uint32_t
は32ビット(4バイト)の符号無し整数型 = 旧来のint
型を表しているuint8_t
は8ビット(1バイト)の符号無し整数型 = 旧来のchar
型を表している
変数targetTime
▼サンプルスケッチより
uint32_t targetTime = 0; // for next 1 second timeout
「for next 1 second timeout」・・・直訳すると「次の1秒間のタイムアウト」?
おそらくなんだけど、loop関数での使われ方を見ると「前回の時計表示から1秒経っているかどうかを判断して、もし1秒経っていたら表示秒数を進める」という処理をするために使われているように見える。
関数conv2dと変数hh, mm, ss
▼サンプルスケッチより
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
conv2d
はコンパイルされた時刻を取得するための関数、だそう。
▼conv2dの中身
// Function to extract numbers from compile time string static uint8_t conv2d(const char* p) { uint8_t v = 0; if ('0' <= *p && *p <= '9') v = *p - '0'; return 10 * v + *++p - '0'; }
そして、この関数と何やら__TIME__
という値を使って、コンパイルされた時間、分、秒をそれぞれ変数hh
, mm
, ss
に格納している。
となると、この__TIME__
というものの中に時刻が入っていたりするのかな?
TIME定数でコンパイル時刻を取得できる
ということで、時刻表示している仕組みを理解。
まず、C/C++ではコンパイル時に__TIME__
という定数にコンパイル時間が格納される。
そしてコンパイルからの経過時間mills()
を加算することで、現在時刻を出すことができる。
というような理屈かな?
確かに、これなら通信を使わずに時刻表示が実現できる。毎時00分に処理する、という動作もできそうだ。
(正確な時刻ではないけど、まあ運用上問題はなさそう。)
実際の__TIME__
定数には1061159211
のような数値の文字列が入っている。
どういうルールかイマイチわかんないけど、これをconv2d
関数で時間、分、秒に変換しているらしい。
▼画面上にコンパイル時間を表示するスケッチ
#include <M5Stack.h> void setup() { M5.begin(); // M5初期化 M5.Power.begin(); // M5の電源の初期化 // 画面の設定 M5.Lcd.fillScreen(TFT_BLACK); M5.Lcd.setTextSize(3); M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK); } void loop() { // 画面の表示 M5.Lcd.clear(); M5.Lcd.setCursor(0, 0); M5.Lcd.printf("__TIME__:\n"); M5.Lcd.printf("%u", __TIME__); delay(10000); }
今日のまとめ
サンプルスケッチ「TFT_Clock_Digital」のグローバルで定義されている変数と関数を見てみた。
コンパイラ時刻が__TIME__
で数値文字列として取得できて、それをconv2d
関数で時刻表示に変換することができることがわかった。
次こそはloop()関数の中身を見ていこう。