この図で「計測待ち」「計測中」「表示中」はプログラムの動作状態を表すもので、状態=ステート(state)と言います。 この状態はボタン押下という外部イベントによって切り替わります(変化します)。
この状態を定義して、それによって処理を切り替えるような構造をステートマシーン(state machine)と呼びます。 状態を切り替える方法としては、複数のif文を使って行う方法と、switch case 文を使う方法とがあります。
ステートマシンを実装する場合は上の図の(a)のif 文を使うより、(b) switch case 文を使うのが 一般的です。
if文を使う方法では1回ループで全ての条件判断を行う必要がありますが、switch csee 文では、条件判断を行う部分は一ヶ所だけ なので、その分オーバーヘッドは小さくなります。 しかし、if文を複数並べるのではなく if else 文を連らねれば必ずしも全ての条件判断を行う必要はありません。switch case 文も内部の処理は if else を連ねたものと同じなので、その場合にはオーバーヘッドは変わりません。 ステートマシンの実装で if (else ) より switch case 文が使われる理由は、プログラムの処理構造がより可視化されたものとなるためです。
タイマー割り込みで全ての処理を駆動する場合には、このループを毎ループ回ることになります。その場合一般に、 各状態で行う処理を、その状態に 入った際に行う処理(ENTRY処理)、毎回行う処理(DO処理)、状態から抜ける際に行う処理(EXIT処理)を分ける必要が あります。このうち ENTRY処理とEXIT処理は、状態が遷移した先か元のどちらかで行えばよいので、どちかを省略できます(通常はEXIT処理を省略します)。
例えば、次のようなプログラムになります。
#include "kernel.h" #include "kernel_id.h" #include "ecrobot_interface.h" #define NXT_PORT_TOUCH NXT_PORT_S1 //タッチセンサポートの指定 DeclareCounter(SysTimerCnt); /* SysTimerCntを宣言 */ DeclareTask(Task1); /* Task1を宣言 */ void ecrobot_device_initialize(){} /* OSEK起動時の処理(何もしない)*/ void ecrobot_device_terminate(){} /* OSEK終了時の処理(何もしない)*/ void user_1ms_isr_type2(void) /* タイマ割り込み用フック関数 */ { SignalCounter(SysTimerCnt); /* カウンタをIncrementする */ } TASK(Task1) { static int time=0; // 変数timeの定義と初期化 static enum{WAIT,RUN,STOP} state = WAIT; static enum{ENTRY,DO,EXIT} eod= ENTRY; switch (state){ case WAIT: if(eod==ENTRY){ time=0; display_clear(0); display_goto_xy(0,1); display_string("READY"); display_update(); eod=DO; } if(eod==DO){ if(ecrobot_get_touch_sensor(NXT_PORT_TOUCH)==1){ state=RUN; eod=ENTRY; } } break; case RUN: if(eod==ENTRY){ eod=DO; } if(eod==DO){ time++; display_clear(0); display_goto_xy(0,1); display_string("RUNNING"); //現在のタイムを表示 display_update(); if(ecrobot_get_touch_sensor(NXT_PORT_TOUCH)==1){ state=STOP; eod=ENTRY; } } break; case STOP: if(eod==ENTRY){ display_clear(0); display_goto_xy(0,1); display_string("RESULT_TIME"); //最終タイムを表示 display_update(); eod=DO; } if(eod==DO){ if(ecrobot_get_touch_sensor(NXT_PORT_TOUCH)==1){ state=WAIT; eod=ENTRY; } } break; } TerminateTask(); /* 処理終了 */ } |
・このプログラムをコンパイルするためには、OILファイルを実践編の「4.oilファイル」のalarm_test.oilに変更する必要がある。
- 上記の説明のようにタッチセンサで、計測待ち、計測中、表示中を切り替える。
- LCDへの表示は秒とミリ秒を分けて行うようにすること。(表示例 「 5s 11 」)
- 3.タッチセンサの使用の「3.連続動作の回避方法」を参考に、タッチセンサ押下の連続動作を 回避するようにせよ。
- 10msec の時間分解能を持つように、alarm_test.oil の CYCLETIME の値を適切に変更すること。
- 計測待ち、計測中、表示中のほかに、待機中の状態を定義し、プログラム起動後は待機中となり、タッチセンサ押下で
計測待ちに移動する。
- 計測待ちの状態で、RUNボタンが押されるか5秒間タッチセンサ入力ないと待機中に移動する。 (RUNボタンの使用方法については、6.ボタンの使用を参照のこと)
- 上記以外の仕様と動作(状態遷移とイベントの関係)は変更なし。