必修技術:タスク制御とチャタリング対策:T-Engineプログラミング入門(3)(3/5 ページ)
今回は基本中の基本であるタスク制御と、「チャタリング」という組み込みならではの問題への対処法を解説する
スロットマシンプログラムの詳細
ではリスト1を詳しく見ていきましょう。
タスクの生成/起動、スリープ/起床
main関数では、前回と同じようにtk_def_intで割り込みハンドラを定義しているほか、「左ドラムの処理タスク」と「右ドラムの処理タスク」を別々に生成、起動しています。タスクの生成がtk_cre_tsk(意味:T-Kernel Create Task)、起動がtk_sta_tsk(意味:Start Task)です。この例では、タスクの優先度を130、スタックサイズを4096bytesにしています。
T_CTSK ct_left = { NULL, TA_HLNG | TA_RNG0, task_left, 130, 4096 }; (中略) /* 左ドラムの処理タスクを生成, 起動 */ tid_left = tk_cre_tsk( &ct_left ); tk_sta_tsk( tid_left, 0 );
こうして起動されたタスクは「実行可能状態」になり、優先度の高いものから実行されていきます。
タスクは自分でtk_slp_tsk(意味:Sleep Task)を発行することで、引数で指定した時間だけ待ち状態に入ることができます。例えば、tk_slp_tsk( 30 )で30ミリ秒だけ待ち状態に入ります。タスクが待ち状態に入ると、次に優先度の高い別の実行可能なタスクが実行されます。
スリープによる待ち状態は、次の場合に解除されます。
いずれにせよ、タスクの待ちが解除されると実行可能状態に戻ります。
なお、tk_slp_tskの引数として「無限大の時間(TMO_FEVR)」を指定することもできます。この場合は、ほかのハンドラやタスクから起床されるまで永久に待ち続けます(図5)。
ドラムの回転と停止の処理
リスト1のドラムの処理タスクは、tk_slp_tskで通常は30を指定して、30ミリ秒だけ待ち状態に入るようにしています。30ミリ秒経過してタイムアウトしたら、ドラムのパターンを1つ進めて、次のパターンを7セグメントLEDに表示します。これを繰り返すことで、ドラムの回転を表します。
/* 左ドラムの処理タスク */ void task_left( INT stacd, VP exinf ) { ER er; int count_left; time_left = 30; count_left = 0; for (;;) { /* スリープ */ er = tk_slp_tsk( time_left ); /* タイムアウトの場合 */ if (er == E_TMOUT) { /* 左ドラムを次へ進める */ count_left++; if (count_left >= 6) count_left = 0; /* 左7セグメントLEDに表示する */ out_h( 0x16100002, p[count_left] ); /* 割り込みハンドラから起床された場合 */ } else if (er == E_OK) { /* 左ドラムを止める */ if (time_left == 30) time_left = TMO_FEVR; /* 左ドラムの回転を再スタートさせる */ else if (time_left == TMO_FEVR) time_left = 30; } } }
ここでストップボタンを押して割り込みを発生させると、割り込みハンドラの中で、対応するドラムの処理タスクをtk_wup_tskで起床させます。起こされたタスクは、待ち時間を30ミリ秒から無限大の時間(TMO_FEVR)に変えて、永久にスリープするようにします。これで、ドラムの回転が完全に停止するわけです。
/* 左ボタンに対する割り込みハンドラ */ void int_left( UINT dintno ) { /* 割り込み要求クリア */ ClearInt( dintno ); /* 左ドラムの処理タスクを起床 */ if (time_left == 30) tk_wup_tsk( tid_left ); }
トグルスイッチによって割り込みが発生すると、割り込みハンドラの中で、左右両方のドラムの処理タスクをtk_wup_tskで起床させます。起こされたタスクは、待ち時間をTMO_FEVRから30ミリ秒に戻して、ドラムの回転を再スタートさせます。
/* トグルスイッチ(SW7)に対する割り込みハンドラ */ void int_toggle( UINT dintno ) { /* 割り込み要求クリア */ ClearInt( dintno ); /* 左ドラムの処理タスクを起床 */ if (time_left == TMO_FEVR) tk_wup_tsk( tid_left ); /* 右ドラムの処理タスクを起床 */ if (time_right == TMO_FEVR) tk_wup_tsk( tid_right ); }
volatile int time_left;
int time_left;
Copyright © ITmedia, Inc. All Rights Reserved.