先日勢いで購入した 128×128 TFT 液晶を Arduino Nano 互換機に繋いで、万年カレンダーを作ることにした。
というわけで、とりあえず画面に時刻やカレンダーを表示できるようにはなったので、後は時間経過とともに時刻を進める実装を書かなくてはならない。電子工作のネタとして、万年カレンダーを構想中。フリスクケースに入れる。 pic.twitter.com/wSKrSQRKpj
— OBONO (@OBONO) 2020年1月18日
電力消費を抑えるため、画面更新時以外は基本的にスリープさせて、Watchdog 割り込みを利用して秒を刻む方針でコードを書いてみた。
#include <arduino.h> #include <avr/sleep.h> #include <avr/wdt.h> volatile int wdCount = 0; void setup() { wdt_reset(); cli(); MCUSR = 0; // WDRF reset WDTCSR |= 0b00011000; // WDCE WDE set WDTCSR = 0b01000000 | 0b00000110; // WDIE set | WDP set scale 1sec sei(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); } void loop() { while (wdCount--) { // do something } sleep(); } static void sleep(void) { cli(); sleep_enable(); sleep_bod_disable(); sei(); sleep_cpu(); /* wake up here */ sleep_disable(); } ISR(WDT_vect) { wdCount++; }
…が、タイマーの精度があまりにも悪く、1時間経過したころには4,5分もズレてしまう。これじゃあ、時計としては致命的。
仕方がないので、消費電力の事は気にせず、無限ループ内で適当に delay() するように方針変更。諸般の事情で、50ms 毎にループを回してる。
#include <arduino.h> #define FPS 20 #define MILLIS_PER_FRAME (1000 / (FPS)) int frames; long targetTime; void setup() { frames = 0; targetTime = millis(); } void loop() { while (frames >= FPS) { // do something frames -= FPS; } targetTime += MILLIS_PER_FRAME; long delayTime = targetTime - millis(); if (!bitRead(delayTime, 31)) delay(delayTime); frames++; }
これだと、割と良さそうな精度で時間が進んで行ってくれた。実際、精度がどの程度なのか、丸一日動かしてみて様子を見てみるか。
今日はここまで。