ESP-WROOM-02のTickerを使った割り込み実行
Table of Contents
ESP-WROOM-02(ESP8266)では、Ticker
という簡易なタイマー割り込みのライブラリがあります。
これは、timer0
やtimer1
を使う実装よりも設定できることが少ないですが、実装がかんたんです。
ストップウォッチのような時間計測や、定期的なセンシングやフェッチ処理などに使いやすいです。
詳細な実装例は、ライブラリのExampleから見ることができます。
基本的な使い方 #
基本的な実装の流れは以下のとおりです。
#include "Ticker.h"
Ticker ticker;
void printFromTicker() {
Serial.println(String("ticker: ") + millis());
}
void setup() {
Serial.begin(115200);
Serial.println("Program Start.");
ticker.attach(1.0, printFromTicker); // 割り込み間隔(float 秒), コールバック関数
}
void loop() {
Serial.println(String("loop: ") + millis());
delay(1000);
}
このように、Tickerのインスタンスを宣言したあとは、attach
メソッドで割り込み間隔(秒)とコールバック関数をセットしてあげるだけで使うことができます。
割り込み間隔の精度 #
上記の実装のmillis()
部分をmicros()
に変えると、割り込みの精度がよくわかります。
マイクロ秒の下6桁のレベルで(=1.0秒ぴったりのクロックで)、一定間隔に割り込まれていることがよくわかります。
たまに割り込んだときのmicros()
がずれることもありますが、すぐもとに戻るようです。
ということは、現実世界の正確な1.0秒との差は、発振器の精度に依存することになるでしょう。 発振器は26MHz±10ppmで動くものだそうです。 Real Time Clockや一般家庭の時計で使われる発振器が32.768kHzと考えると、実用レベルでは十分な精度だろうと思います。
試しに30分連続して割り込みをさせてみると、シリアルモニターは、以下のようなログになりました。 30分経っても、ほとんどずれていないことがわかります。 「ticker: xxx」の部分は、「秒」にしてあります。左側のタイムスタンプは、ホスト側PCの時刻です。
22:47:01.263 -> ticker: 1
22:48:00.290 -> ticker: 60
22:49:00.301 -> ticker: 120
22:50:00.277 -> ticker: 180
22:51:00.283 -> ticker: 240
22:52:00.283 -> ticker: 300
22:53:00.290 -> ticker: 360
22:54:00.260 -> ticker: 420
22:55:00.269 -> ticker: 480
22:56:00.288 -> ticker: 540
22:57:00.294 -> ticker: 600
22:58:00.273 -> ticker: 660
22:59:00.274 -> ticker: 720
23:00:00.299 -> ticker: 780
23:01:00.286 -> ticker: 840
23:02:00.307 -> ticker: 900
23:03:00.286 -> ticker: 960
23:04:00.261 -> ticker: 1020
23:05:00.270 -> ticker: 1080
23:06:00.267 -> ticker: 1140
23:07:00.281 -> ticker: 1200
23:08:00.289 -> ticker: 1260
23:09:00.288 -> ticker: 1320
23:10:00.274 -> ticker: 1380
23:11:00.287 -> ticker: 1440
23:12:00.298 -> ticker: 1500
23:13:00.304 -> ticker: 1560
23:14:00.305 -> ticker: 1620
23:15:00.307 -> ticker: 1680
23:16:00.292 -> ticker: 1740
23:17:00.290 -> ticker: 1800
23:18:00.291 -> ticker: 1860
23:19:00.278 -> ticker: 1920
23:20:00.292 -> ticker: 1980
23:21:00.281 -> ticker: 2040
ストップウォッチとしても十分使えそうですね。
使えるメソッド #
GitHubにあるTicker.hのソースを見ながら、パブリックメソッドを覗いてみます。
void attach_scheduled(float seconds, callback_function_t callback)
void attach(float seconds, callback_function_t callback)
void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_function_t callback)
void attach_ms(uint32_t milliseconds, callback_function_t callback)
void attach(float seconds, void (*callback)(TArg), TArg arg)
void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
void once_scheduled(float seconds, callback_function_t callback)
void once(float seconds, callback_function_t callback)
void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
void once_ms(uint32_t milliseconds, callback_function_t callback)
void once(float seconds, void (*callback)(TArg), TArg arg)
void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
こうしてみると、いくつかのパターンに分かれているようです。
attach | once | |
---|---|---|
サフィックスなし | 即実行 | 一度限り、即実行 |
_ms | 即実行(ミリ秒指定) | 一度限り、即実行(ミリ秒指定) |
_scheduled | loop()終了後に実行 | 一度限り、loop()終了後に実行 |
_ms_scheduled | loop()終了後に実行(ミリ秒指定) | 一度限り、loop()終了後に実行(ミリ秒指定) |
_ms_scheduled_accurate | delay()やyield()の後で実行(ミリ秒指定)かな? | (なし) |
attach と once #
attach
を使うと繰り返しの割り込みonce
を使うと、1回限りのタイマー
「msなし」と「ms」あり #
msなし
のメソッドは、引数で渡す割り込み間隔を秒で指定するms
ありのメソッドは、割り込み間隔をミリ秒で指定する
「scheduledなし」と「scheduled」と「scheduled_accurate」 #
scheduledなし
の方は、割り込みイベントが発生したらすぐに実行scheduled
ありの方は、割り込みイベントが発生後、loop()
の後で実行scheduled_accurate
は、割り込みイベント発生後、yield()
の後で実行とのこと
scheduled
の挙動 #
loop()
内にあるdelay(1000)
を、3回にしてみます。
#include "Ticker.h"
void printFromTicker() {
Serial.println(String("ticker fired.") + millis());
}
Ticker ticker;
void setup() {
Serial.begin(115200);
Serial.println("Program Start.");
ticker.attach_scheduled(1.0, printFromTicker);
}
void loop() {
Serial.println("--- loop start ---");
delay(1000);
delay(1000);
delay(1000);
Serial.println("--- loop end ---");
}
すると、割り込みの実行が、3秒に1度、3回まとめて実行されるようになりました。
「loop end」から「loop start」の間に実行されていることがわかります。
23:30:55.608 -> --- loop end ---
23:30:55.608 -> ticker fired.3070
23:30:55.608 -> ticker fired.3070
23:30:55.608 -> ticker fired.3070
23:30:55.608 -> --- loop start ---
23:30:58.596 -> --- loop end ---
23:30:58.596 -> ticker fired.6070
23:30:58.596 -> ticker fired.6070
23:30:58.596 -> ticker fired.6070
23:30:58.596 -> --- loop start ---
23:31:01.608 -> --- loop end ---
23:31:01.608 -> ticker fired.9071
23:31:01.608 -> ticker fired.9071
23:31:01.608 -> ticker fired.9071
23:31:01.608 -> --- loop start ---
23:31:04.584 -> --- loop end ---
23:31:04.584 -> ticker fired.12071
23:31:04.584 -> ticker fired.12071
23:31:04.584 -> ticker fired.12071
23:31:04.621 -> --- loop start ---
23:31:07.592 -> --- loop end ---
23:31:07.592 -> ticker fired.15071
23:31:07.592 -> ticker fired.15071
23:31:07.592 -> ticker fired.15072
23:31:07.592 -> --- loop start ---
ms_scheduled_accurate
の挙動 #
scheduled
のときと少し変えて、delay(1500)
を2回実行してみます。
#include "Ticker.h"
void printFromTicker() {
Serial.println(String("ticker fired.") + millis());
}
Ticker ticker;
void setup() {
Serial.begin(115200);
Serial.println("Program Start.");
ticker.attach_ms_scheduled_accurate(1000, printFromTicker);
}
void loop() {
Serial.println("--- loop start ---");
delay(1500);
delay(1500);
Serial.println("--- loop end ---");
}
すると、1回目のdelay(1500)
のあとに1回と、
2回目のdelay(1500)
のあとに2回まとめて実行されていることがわかります。
実行タイミングは、loop()
の途中でも実行されている点が、scheduled
と異なります。
また、delay
が終わるのを待っている点は、サフィックスなしの「attach」や「once」とは異なります。
_ms_scheduled_accurate
は、即時実行ではない点scheduled
ですが、よりaccurate
(正確)ということなのでしょう。
00:07:19.510 -> ticker fired.12071
00:07:19.510 -> ticker fired.12071
00:07:19.510 -> --- loop end ---
00:07:19.510 -> --- loop start ---
00:07:21.012 -> ticker fired.13571
00:07:22.524 -> ticker fired.15072
00:07:22.524 -> ticker fired.15072
00:07:22.524 -> --- loop end ---
00:07:22.524 -> --- loop start ---
00:07:24.008 -> ticker fired.16572
00:07:25.540 -> ticker fired.18072
00:07:25.540 -> ticker fired.18072
00:07:25.540 -> --- loop end ---
00:07:25.540 -> --- loop start ---
00:07:27.038 -> ticker fired.19572
00:07:28.509 -> ticker fired.21072
00:07:28.509 -> ticker fired.21072
00:07:28.509 -> --- loop end ---
00:07:28.509 -> --- loop start ---
00:07:30.035 -> ticker fired.22573
00:07:31.510 -> ticker fired.24073
00:07:31.510 -> ticker fired.24073
00:07:31.510 -> --- loop end ---
00:07:31.510 -> --- loop start ---
1.5秒に1度になりました。
Tickerを止めるには #
detach()
を呼びます。
ticker.detach();
ウォッチドッグタイマーを作りたい場合は、detach
したあとにattach
・once
を再セットしてあげると良さそうです。
timer0
やtimer1
のようなwrite()
メソッドがないので、こうするしかなさそうです。
まとめ #
ESP-WROOM-02(ESP8266)のタイマー割り込みで使えるTicker
ライブラリの動きを見てみました。
ほんの数行の実装で、定期的な処理を、シンプル・かんたんに実装することができます。
分周などを計算しなくても良いので、直感的に読み書きできるところも良かったです。