目次
前
次
タスク定義の定石
USOは、ノンプリテンプティブなRTOS(Real Time Operating System)なので
タスクを実現する関数内部で、無限ループ処理をすると、そのタスクがCPU
を使い続けることになります。
タスク処理では、無限ループは禁止です。
無限ループなしで、タスク処理を作成します。
タスクは、動作により3種類に統合できます。
- Standard(スタンダード)
- One Shot(ワンショット)
- Cycle(サイクル)
この3種類のいずれかでタスクを記述します。
具体的なタスク定義を説明します。
イベント処理タスク
USOでは、1イベントに1機能を実現するようにタスクを
定義すると、見通しがよくなります。
イベントを補足するタスクを定義しておき、そのタスクから
機能を実現するタスクを起動するようにします。
マスタ、スレーブのイメージでタスクを定義すると楽です。
次の例は、タスク0でタスク2を起動し、タスク1でタスク2を
停止します。
またタスク1は、タスク3を起動して、後処理を一任しています。
void tsk0_proc(void)
{
/* イベント補足 */
if ( event == ON ) {
rsm_tsk( TSK_ID2 );
}
/* 周期指定 1000ms */
wai_tsk( 100 ) ;
}
void tsk1_proc(void)
{
/* イベント補足 */
if ( event == OFF ) {
sus_tsk( TSK_ID2 );
rsm_tsk( TSK_ID3 );
}
/* 周期指定 1000ms */
wai_tsk( 100 ) ;
}
void tsk2_proc(void)
{
/* 何か処理 */
}
void tsk3_proc(void)
{
/* 何か処理 */
slp_tsk();
}
タスクの個数は、なるべく少ない方がよいので、次のように
記述しても同じことを実現できます。
void tsk0_proc(void)
{
/* イベント補足 */
if ( event == ON ) {
rsm_tsk( TSK_ID2 );
} else {
sus_tsk( TSK_ID2 );
rsm_tsk( TSK_ID3 );
}
/* 周期指定 1000ms */
wai_tsk( 100 ) ;
}
void tsk2_proc(void)
{
/* 何か処理 */
}
void tsk3_proc(void)
{
/* 何か処理 */
slp_tsk();
}
時間シーケンス処理
システムによっては、動作が決められていることがあります。
このように動作が決められている場合は、シーケンス処理が
できるようにします。
最も身近にあるシーケンス処理は、交通信号でしょう。
シーケンス処理は、時間と順序を管理するタスクを用意して
そのタスクが、他のタスクの面倒をみるようにします。
交通信号機が「赤→黄→緑→黄→赤」と繰返すとして
タスクを定義してみます。
unsigned char state ;
void tsk0_proc(void)
{
switch ( state ) {
/* 赤のみ点灯 */
case 0 : rsm_tsk( TSK_ID1 ); break ;
/* 黄のみ点灯 */
case 1 : rsm_tsk( TSK_ID2 ); break ;
/* 緑のみ点灯 */
case 2 : rsm_tsk( TSK_ID3 ); break ;
/* 黄のみ点灯 */
case 3 : rsm_tsk( TSK_ID2 ); break ;
/* 安全処理 */
default : rsm_tsk( TSK_ID1 ); break ;
}
/* カウンタ更新 */
state++ ;
state %= 4 ;
/* 周期処理 */
wai_tsk( 1000 );
}
void tsk1_proc(void)
{
/* 赤のみ点灯 */
LED_RED = LED_ON ;
LED_YELLOW = LED_OFF ;
LED_GREEN = LED_OFF ;
/* 終了 */
slp_tsk()
}
void tsk2_proc(void)
{
/* 黄のみ点灯 */
LED_RED = LED_OFF ;
LED_YELLOW = LED_ON ;
LED_GREEN = LED_OFF ;
/* 終了 */
slp_tsk()
}
void tsk2_proc(void)
{
/* 緑のみ点灯 */
LED_RED = LED_OFF ;
LED_YELLOW = LED_OFF ;
LED_GREEN = LED_ON ;
/* 終了 */
slp_tsk()
}
イベントシーケンス処理
時間ではないイベントを利用するシーケンス処理もあります。
このようなイベントの処理タスク記述にも定石があります。
最も身近にあるイベントシーケンス処理の例は、自動ドアです。
シーケンス動作を考えます。
- 物体が、ドアの前にあれば、ドアを開けます
- 指定時間ドアを開けます
- ドアを横切るかドアの前に物体がなければ、ドアを閉じます
安全のためには、さらに処理が必要ですが、根幹となる
シーケンス動作は、これで充分です。
必要となるイベントをリストします。
- ドアの前に物体があると検出
- ドアを横切る物体があると検出
- 指定時間経過した
これらのイベントをOBJECT_EXIST、OBJECT_CROSS、TIME_OUTの
3つのフラグで表現して、タスクを記述していきます。
(定義しようと考えるタスク以外は、存在すると仮定し
記述するのがコツです。)
物体がドアの前にあったことを判断して、ドアを開けるタスク
void tsk0_proc(void)
{
if ( OBJECT_EXIST == ON ) {
rsm_tsk( TSK_ID1 );
slp_tsk();
}
}
ドアを開けるタスク
void tsk1_proc(void)
{
/* ドアを開ける信号出力 */
/* 待ち時間指定 */
time_count = TIME_INTERVAL ;
/* 時間待ちタスクを起動 */
rsm_tsk( TSK_ID2 );
slp_tsk();
}
指定時間経過させるタスク
void tsk2_proc(void)
{
/* 判定 */
if ( time_count == 0 ) {
TIME_OUT = ON ;
rsm_tsk( TSK_ID3 );
slp_tsk();
} else
/* 時間待ち */
{
time_count-- ;
wai_tsk( 100 );
}
}
指定時間経過を確認するタスク
void ts3_proc(void)
{
if ( TIME_OUT == ON ) {
TIME_OUT = OFF ;
rsm_tsk( TSK_ID4 );
slp_tsk();
}
}
ドアを横切るかドアの前に物体がなければ、ドアを閉じるタスク
void tsk4_proc(void)
{
if ( OBJECT_EXIST == OFF && OBJECT_CROSS == OFF ) {
/* ドアを閉じる信号出力 */
/* 最初のタスクを起動する */
rsm_tsk( TSK_ID0 );
slp_tsk();
}
}
他のタスクを起動する条件を考えて、ドミノ倒しのようにタスク
を動かすようにすると、自然にシーケンス処理を実行できます。
最初に実行するタスクだけをREADYにして、他はSUSPENDで起動します。
sta_tsk(TSK_ID0,TTS_READY) ;
sta_tsk(TSK_ID1,TTS_SUSPEND);
sta_tsk(TSK_ID2,TTS_SUSPEND);
sta_tsk(TSK_ID3,TTS_SUSPEND);
sta_tsk(TSK_ID4,TTS_SUSPEND);
目次
前
次