M5Stackでの電子工作の学習中。
こちらの続きで、一定間隔でセンサ値をデータベース(Spreadsheet)に送るような仕組みを作っていく。
具体的には「30分おきに定期的に処理を行う」ようにしていきたい。
単純に経過時間を使うのではなく「xx:00、xx:30きっかりに処理を行う」というように、時刻に合わせた処理を行いたい。
時刻と連動させるにはNTPサーバを使うという方法があるが、通信を使わず簡単に実現できる方法はないのかな?と思って探していた。
そしておそらく、この辺りのロジックを組み合わせたらできそうだな、というのがわかってきた。
実行確認のしやすい形でロジックを考える
ちょっと複雑なのでミニマムに実装していこう。
まずは実行確認がしやすいように 「毎分00秒きっかりに1回だけ「Send data!」を表示させる」 というスケッチを作成することにする。
時間の経過をどうやってとるか?
ここでは__TIME__
からコンパイル時点での時hh
、分mm
、秒ss
を算出して、1秒ずつ加算しながらこれらの変数hh
, mm
, ss
で時間を管理する。
簡単に考えてloop()
関数の中でdelay(1000)
で1秒ずつ進めて、都度時間合わせをするようにした。
ただ、おそらくこれだと実行に1秒ちょいかかって少しずつ時間がずれていく気がするけど・・・ひとまず良しとする。
分が変わった時に1回だけ処理をするのはどうしたら良いか?
別の変数omm
に現在の分を記録しておいて、if文でその変数omm
と変化後の分mm
を使って切り替わりタイミングを検知するようにした。
(ちょっと説明が上手くできない。)
作成したスケッチ
ともあれ、このようなスケッチを作成した。
▼毎分00秒の時に1回だけ「Send data!」を表示させる
#include <M5Stack.h> static uint8_t conv2d(const char* p); // タイムスタンプを時、分、秒に変換する関数 uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // コンパイル時刻 uint8_t omm = mm; void setup() { // M5の初期化 M5.begin(); M5.Power.begin(); // 画面の初期設定 M5.Lcd.fillScreen(TFT_BLACK); M5.Lcd.setTextSize(3); M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK); } void loop() { // 画面の初期化 M5.Lcd.clear(); // 1秒進めて時間合わせ ss++; // if(ss == 60){ ss = 0; mm++; if(mm > 59){ mm = 0; hh++; if(hh > 23){ hh = 0; } } } if(mm != omm){ // 分の切り替わりを検知してこの中身を実行 omm = mm; // 現在の分を記録 // 1回だけ実行される処理 M5.Lcd.setCursor(0, 180); M5.Lcd.printf("Send data!\n"); } // 画面の表示テスト M5.Lcd.setCursor(0, 0); M5.Lcd.printf("compile time\n"); M5.Lcd.setCursor(0, 30); M5.Lcd.printf("%u", __TIME__); M5.Lcd.setCursor(0, 90); M5.Lcd.printf("hh, mm, ss\n"); M5.Lcd.setCursor(0, 120); M5.Lcd.printf("%u, %u, %u", hh, mm, ss); delay(1000); } // 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'; }
これで動画のように、分が切り替わって秒数が00きっかりになった時に「Send data!」が1回だけ表示されて、1秒後には表示されないような実装ができた。
良い感じ。
手直しして実際のロジックに当てはめる
先程のスケッチを踏まえて 「毎時00分、30分の時に処理を行う」 ための骨組みを書いた。
作成したスケッチ
先程のスケッチからディスプレイへの表示の処理を省いたので、現段階ではこれをM5Stackに書き込んでも何も起こらない。
あとは(※)に定期実行したい処理(データを送信する処理)を入れ込むことで、定期実行ができる。
▼毎時00分、30分の時に処理を行うスケッチ
#include <M5Stack.h> static uint8_t conv2d(const char* p); uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time uint8_t omm = mm; void setup() { // M5の初期化 M5.begin(); M5.Power.begin(); // 画面の初期設定 M5.Lcd.fillScreen(TFT_BLACK); M5.Lcd.setTextSize(3); M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK); } void loop() { // 1秒進めて時間合わせ ss++; // if(ss == 60){ ss = 0; mm++; if(mm > 59){ mm = 0; hh++; if(hh > 23){ hh = 0; } } } if(mm == 0 || mm == 30) { // 毎時00分、30分の時に実行 if(mm != omm){ // 分の切り替わりを検知して一回だけこの中身が実行される omm = mm; // 現在の分を保管 /* (※) ここでデータ送信処理を行う */ } } delay(1000); } // 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'; }
今回のまとめ
良さそうなスケッチができた!
前回のセンサーデータをSpreadsheetへ送る処理と組み合わせて、いける気がする。