はじめに
uITRON(FreeRTOSベース)Windowsシミュレータ - Qiita
https://qiita.com/imagou/items/42c687402e6e58fccddb
今回のお題は、周期ハンドラに続くタイマ機能である、アラームハンドラです。
本編
1. 環境
こちらの記事を参照ください。
2. 動かしてみる
2-1. アラームハンドラの開始
コンソールで「alarm」と入力してみましょう(入力後にEnterを押してください)。
[2020/05/01 14:19:56.131] [TimerTask]: DELAY 3000ms
alarm
[2020/05/01 14:19:59.131] [TimerTask]: DELAY 3000ms
[2020/05/01 14:20:02.131] [TimerTask]: DELAY 3000ms
[2020/05/01 14:20:02.767] [UserAlarmHandler]: Alarm Timer Expired (1)
[2020/05/01 14:20:05.132] [TimerTask]: DELAY 3000ms
[2020/05/01 14:20:08.133] [TimerTask]: DELAY 3000ms
入力してから5000msec後、UserAlarmHandler
がAlarm Timer Expired (n)
を出力します(カッコ内の数値は満了回数)。
周期ハンドラと異なり、満了は1回のみです。
2-2. アラームハンドラの停止
次は、コンソールで「alarm」を入力した後、再度「alarm」投入してみましょう。
[2020/05/01 14:26:32.239] [TimerTask]: DELAY 3000ms
alarm
[2020/05/01 14:26:35.240] [TimerTask]: DELAY 3000ms
alarm
[2020/05/01 14:26:38.241] [TimerTask]: DELAY 3000ms
[2020/05/01 14:26:41.241] [TimerTask]: DELAY 3000ms
[2020/05/01 14:26:44.241] [TimerTask]: DELAY 3000ms
この場合、前述の満了ログは出力されません。
3. 解説
3-1. 概要
アラームハンドラは、指定時間経過後、何らかの処理を実施する仕組みです。
一般的にはワンショットタイマと呼ばれるものです。
(「ワンショット」という名称からも明らかですが)周期ハンドラとの違いは、1回の満了で終了する点です。
3-2. コードによる説明
以降は、プログラムコード - main.c
を引用して説明します。
3-2-1. アラームハンドラ生成
cre_alm()
で生成します。
T_CALM calm;
calm.almatr = TA_HLNG;
calm.almhdr = UserAlarmHandler;
cre_alm(ALARM_ID(USER), &calm);
このパラメータは下表:
パラメータ番号 | 名称 | 説明 |
---|---|---|
第1パラメータ | アラームハンドラID | 単なるID。 以降はこのIDでもって開始・停止を実施。 |
第2パラメータ | T_CALM構造体変数 | 下表で説明。 |
T_CALMのメンバは下表:
名称 | 指定可能な値 | 説明 |
---|---|---|
almatr | TA_HLNG | 属性。高級言語を使用。 |
almhdr | void func(void*) | 満了時に呼び出すハンドラ関数。 |
※なお、属性はこれ以外の値も指定可能(だが、上記のみで必要十分と考える)。
3-2-2. アラームハンドラ開始・停止
それぞれsta_alm()
、stp_alm()
を使います。
/* Alarm */
else if (EQUALS_(alarm)) {
T_RALM ralm;
ref_alm(ALARM_ID(USER), &ralm);
if (!(ralm.almstat)) sta_alm(ALARM_ID(USER), 5000);
else stp_alm(ALARM_ID(USER));
}
またref_alm()
を用い、アラームハンドラが起動しているか参照していますが、こちらの説明は割愛。
3-2-3. ハンドラ関数
(しつこいですが)ハンドラは非タスクコンテキスト、すなわち割り込みから呼ばれるので、簡潔な処理に留めないといけません。
今回はあまり有用な例ではなく、単にログを吐くだけです。
static void UserAlarmHandler(void* params)
{
/* Just to remove compiler warning. */
(void)params;
static int32_t expired = 0;
DEBUG_PRINT("[%s]: Alarm Timer Expired (%d)", __func__, ++expired);
}
おわりに
経験上、周期ハンドラよりも有用と感じますので、ぜひ使い方をマスターしてください!
(というほど難しい機能でもありませんが)
参考
Micro-ITRON4.0 Specification (in Japanese)
http://www.ertl.jp/ITRON/SPEC/mitron4-j.html