目次

タスク定義の定石

 USOは、ノンプリテンプティブなRTOS(Real Time Operating System)なので
 タスクを実現する関数内部で、無限ループ処理をすると、そのタスクがCPU
 を使い続けることになります。

 タスク処理では、無限ループは禁止です。
 無限ループなしで、タスク処理を作成します。

 タスクは、動作により3種類に統合できます。
  1. Standard(スタンダード)
  2. One Shot(ワンショット)
  3. 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() }

イベントシーケンス処理

 時間ではないイベントを利用するシーケンス処理もあります。  このようなイベントの処理タスク記述にも定石があります。  最も身近にあるイベントシーケンス処理の例は、自動ドアです。  シーケンス動作を考えます。
  1. 物体が、ドアの前にあれば、ドアを開けます
  2. 指定時間ドアを開けます
  3. ドアを横切るかドアの前に物体がなければ、ドアを閉じます
 安全のためには、さらに処理が必要ですが、根幹となる  シーケンス動作は、これで充分です。  必要となるイベントをリストします。
  1. ドアの前に物体があると検出
  2. ドアを横切る物体があると検出
  3. 指定時間経過した
 これらのイベントを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);
目次

inserted by FC2 system