こんにちは、ナナです。
2つ目のタイムイベントハンドラについて紹介します。
アラームハンドラは周期ハンドラと同じタイムイベントハンドラの仲間です。周期ハンドラや割り込みについてはこちらの記事を参照してください。
本記事では次の疑問点を解消する内容となっています。
では、アラームハンドラの仕組みを学んでいきましょう。
ITRONのアラームハンドラの概要
ITRONのアラームハンドラの説明を見てみましょう。
ITRONのアラームハンドラ仕様
アラーム機能は、スマートフォンで目覚まし時計として使われている方は結構多いのではないでしょうか。
ITRONでその機能を提供してくれるのがアラームハンドラです。
使い方については次のように説明されています。
周期ハンドラと異なり、生成直後から動作を開始することはできないとされています。そのためsta_almというアラーム開始用のサービスコールを別途呼び出す必要があります。
sta_almの呼出し後から指定時刻経過後にアラームハンドラが起動するとされていますね。アラームハンドラは周期性を持たないため開始要求に対して1度だけハンドラが起動されます。
アラームハンドラの生成(CRE_ALM)
周期ハンドラと同様にアラームハンドラはオブジェクトとして存在します。
CRE_ALMの仕様
周期オブジェクトは次の静的APIにて作り出すことができます。
CRE_ALM(ID almid, {ATR almatr, VP INT exinf, FP almhdr} );
引数パラメータを解説しておきます。
ID | almid | 生成するアラームハンドラのID。整数として一意のIDを割り付ける。 |
ATR | almatr | アラームハンドラの属性。TA_HLNGを指定する。 |
VP_INT | exinf | アラームハンドラの引数に渡したい情報があれば指定。なければ0でよい。 |
FP | almhdr | アラームハンドラが実行する関数ポインタ。関数名を書く。 |
周期ハンドラと異なりかなりシンプルな構成になっています。ATRにはTA_STAといった開始用のパラメータは使えません。
CRE_ALMによるアラームハンドラの生成定義
では、皆さんにアラームハンドラの定義をsystem.cfgに追加していただきましょう。前回の周期ハンドラはそのままで、アラームハンドラの定義を1つ追加しましょう。
追加するアラームハンドラ生成情報
- IDは「ALMID_ALM1」を指定する。
- 関数ポインタは「ALM1」を指定する。
system.cfg(一部抜粋)
//------------------------------------------------
// 周期ハンドラ定義
//------------------------------------------------
CRE_CYC(CYCID_CYC1, {TA_HLNG|TA_STA, 0, CYC1, 5000, 0});
//------------------------------------------------
// アラームハンドラ定義
//------------------------------------------------
system.cfg(一部抜粋)
//------------------------------------------------
// アラームハンドラ定義
//------------------------------------------------
CRE_ALM(ALMID_ALM1, {TA_HLNG, 0, ALM1});
アラームハンドラ関数の定義
アラームハンドラには周期ハンドラと同様にアラーム発生時に起動する関数を指定する必要があります。CRE_ALMで指定したALM1関数をmain.cに追加しましょう。
この関数では、アラーム起動時にグリーンLEDを点灯する処理を記述してください。
main.c(一部抜粋)
//------------------------------------------------
// 概 要:練習用アラームハンドラ関数
//------------------------------------------------
void ALM1(VP_INT exinf)
{
}
main.c(一部抜粋)
//------------------------------------------------
// 概 要:練習用アラームハンドラ関数
//------------------------------------------------
void ALM1(VP_INT exinf)
{
Led_setLight(D_LED_KIND_GREEN, D_LED_LIGHT_ON);
}
アラームハンドラ関数はmain.hにプロトタイプ宣言を追加しておきましょう。
main.h(一部抜粋)
//------------------------------------------------
// プロトタイプ宣言(Prototype declaration)
//------------------------------------------------
void MAIN(VP_INT exinf);
void Main_init(VP_INT exinf);
void TASK1(VP_INT exinf);
void TASK2(VP_INT exinf);
void CYC1(VP_INT exinf);
void ALM1(VP_INT exinf);
タスク関数の定義
アラームハンドラの開始要求を行うTASK1関数を作り直しましょう。
今回TASK1に与えるミッションは10ミリ秒周期でスイッチ状態をチェックし、スイッチがONならグリーンLEDを消灯し、アラームを5秒後にセットして開始します。
5秒後にアラームハンドラによりグリーンLEDが点灯します。
MAIN関数とTASK2関数は特に役割がないのでdly_tsk(1000);で眠っていただきましょう。皆さんはTASK1の中のミッションを作り出してください。
sta_almサービスコールの仕様
プログラムを作る前にsta_almの仕様を確認しておきましょう。
ER sta_alm(ID almid, RELTIM almtim);
引数として開始するべきアラームIDとアラーム時間(単位:ミリ秒)が設定できるようになっています。簡単に呼び出せそうですね。
それではmain.cのTAKS1関数にミッションをプログラミングしてみてください。
main.c(一部抜粋)
//------------------------------------------------
// 概 要:MAINタスク
//------------------------------------------------
void MAIN(VP_INT exinf)
{
while(1)
{
dly_tsk(1000);
}
return;
}
//------------------------------------------------
// 概 要:練習用TASK1関数
//------------------------------------------------
void TASK1(VP_INT exinf)
{
while(1)
{
}
return;
}
//------------------------------------------------
// 概 要:練習用TASK2関数
//------------------------------------------------
void TASK2(VP_INT exinf)
{
while(1)
{
dly_tsk(1000);
}
return;
}
main.c(一部抜粋)
//------------------------------------------------
// 概 要:練習用TASK1関数
//------------------------------------------------
void TASK1(VP_INT exinf)
{
while(1)
{
if (Sw_getPressed() == D_SW_PRESSED_ON)
{
Led_setLight(D_LED_KIND_GREEN, D_LED_LIGHT_OFF);
sta_alm(ALMID_ALM1, 5000);
}
dly_tsk(10);
}
return;
}
プログラムができたら動かしてみましょう。スイッチを押してから5秒後にグリーンLEDが点灯すれば正常にアラームハンドラが起動できています。
アラームハンドラの時間延長機能
先ほど作ったプログラムでスイッチを押すとグリーンLEDが5秒後に点灯しますね。
5秒経過する前に再度スイッチを押してみてください。そうするとスイッチを押し直した時間から5秒後に点灯するのがわかるはずです。
つまり、アラーム時間の起動が延長しています。
ITRONのsta_almの仕様は次のように説明されています。
この仕様に則り、アラーム発動前にスイッチが再度押されたため、再度TASK1によりsta_almの起動時刻設定がされたということになります。