厳密に時間を守ってその処理を実行させた場合、すなわちリアルタイム制御を行いたい場合には、 wait による周期実行ではなく、OSのタイマ割り込みを使ってそれを実現します。 nxtOSEKでのタイマ割り込みを使った周期実行のさせ方は、III.実践編の4.oilファイルを参考にして下さい。
この図で「計測待ち」「計測中」「表示中」はプログラムの動作状態を表すもので、状態=ステート(state)と言います。 この状態はボタン押下という外部イベントによって切り替わります(変化します)。
この状態を定義して、それによって処理を切り替えるような構造をステートマシーン(state machine)と呼びます。 状態を切り替える方法としては、複数のif文を使って行う方法と、switch case 文を使う方法とがあります。
if文を使う方法では全ての条件判断を行う必要がありますが、switch csee 文では、条件判断を行う部分は一ヶ所だけ なので、その分オーバーヘッドは小さくなります。そのため、ステートマシンを実装する場合は 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 の値を適切に変更すること。
| 8.タスク間の排他制御 | TOPへ |