目次
前
応用例F イルミネーション制御
ArduinoMega2560を利用して、8種のLEDを制御してみます。
8種のLEDを利用するので、USO2の最大タスク数16を扱えるように
システムコールを次のように定義して対応。
#include "usop.h"
UWORD readyx ;
UWORD suspend ;
UWORD waitq ;
UBYTE run_tsk ;
TCBP tcb[RUN_TSK_SIZE];
void init_os(void)
{
readyx = 0 ;
suspend = 0 ;
waitq = 0 ;
}
void cre_tsk(UBYTE tid,void (*tsk)(void))
{
tcb[tid].tsk = tsk ;
tcb[tid].wcount = 0 ;
}
void rsm_tsk(UBYTE tid)
{
UWORD tmp ;
tmp = (1 << tid);
readyx |= tmp;
suspend &= ~tmp ;
waitq &= ~tmp;
}
void sta_tsk(UBYTE tid,UBYTE sta)
{
UWORD tmp ;
tmp = (1 << tid);
if ( sta == TTS_READY ) { readyx |= tmp; }
if ( sta == TTS_SUSPEND ) { suspend |= tmp; }
if ( sta == TTS_WAIT ) { waitq |= tmp; }
}
void sus_tsk(UBYTE tid)
{
UWORD tmp ;
tmp = (1 << tid);
readyx &= ~tmp;
suspend |= tmp;
waitq &= ~tmp;
}
void slp_tsk(void)
{
sus_tsk(run_tsk);
}
void wai_tsk(UWORD x)
{
UWORD tmp ;
tmp = (1 << run_tsk);
readyx &= ~tmp;
suspend &= ~tmp;
waitq |= tmp;
tcb[run_tsk].wcount = x ;
}
void dec_tsk_cnt(UBYTE tid)
{
tcb[tid].wcount-- ;
}
UWORD get_tsk_cnt(UBYTE tid)
{
return( tcb[tid].wcount );
}
UWORD is_tsk_ready(UBYTE tid)
{
return( readyx & (1 << tid) ) ;
}
UWORD is_tsk_wait(UBYTE tid)
{
return( waitq & (1 << tid) ) ;
}
UWORD get_ready()
{
return( readyx );
}
UWORD get_suspend()
{
return( suspend );
}
UWORD get_waitq()
{
return( waitq );
}
ヘッダファイルは、次のように定義しておきます。
#ifndef USOP_H
#define USOP_H
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef signed char SBYTE ;
typedef signed short SWORD ;
typedef struct {
void (*tsk)(void);
UWORD wcount ;
} TCBP ;
#define TTS_SUSPEND 0
#define TTS_WAIT TTS_SUSPEND+1
#define TTS_READY TTS_SUSPEND+2
#define MASKFFFF 0xffff
#define RUN_TSK_SIZE 16
#define TSK_ID0 0
#define TSK_ID1 TSK_ID0+1
#define TSK_ID2 TSK_ID0+2
#define TSK_ID3 TSK_ID0+3
#define TSK_ID4 TSK_ID0+4
#define TSK_ID5 TSK_ID0+5
#define TSK_ID6 TSK_ID0+6
#define TSK_ID7 TSK_ID0+7
#define TSK_ID8 TSK_ID0+8
#define TSK_ID9 TSK_ID0+9
#define TSK_ID10 TSK_ID0+10
#define TSK_ID11 TSK_ID0+11
#define TSK_ID12 TSK_ID0+12
#define TSK_ID13 TSK_ID0+13
#define TSK_ID14 TSK_ID0+14
#define TSK_ID14 TSK_ID0+14
extern UBYTE run_tsk ;
extern TCBP tcb[RUN_TSK_SIZE];
/* function prototypte */
void init_os(void);
//*** system call ***
void cre_tsk(UBYTE tid,void (*tsk)(void));
void sta_tsk(UBYTE tid,UBYTE sta);
void rsm_tsk(UBYTE tid);
void sus_tsk(UBYTE tid);
void slp_tsk(void);
void wai_tsk(UWORD x);
//*** handling function ***
void dec_tsk_cnt(UBYTE tid);
UWORD get_tsk_cnt(UBYTE tid);
UWORD is_tsk_ready(UBYTE tid);
UWORD is_tsk_wait(UBYTE tid);
UWORD get_ready();
UWORD get_suspend();
UWORD get_waitq();
#endif
C/C++のソースコードファイル、ヘッダファイル、Arduinoスケッチ
ソースコードは、ディレクトリの中に、次のように格納してあり
ます。
タスクは、各タスクの状態更新のために専用タスクを
用意し、各LEDの点滅を制御するタスクを各々用意して
対応します。
- TASK0 各タスクの状態設定と通信制御
- TASK1 LED1の点滅制御
- TASK2 LED2の点滅制御
- TASK3 LED3の点滅制御
- TASK4 LED4の点滅制御
- TASK5 LED5の点滅制御
- TASK6 LED6の点滅制御
- TASK7 LED7の点滅制御
- TASK8 LED8の点滅制御
LEDの点滅制御を担当するタスクは、システムコール
wai_tskを利用して定義。
void tsk1_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+1) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+1, xb );
/* increment */
xcnt[1]++ ;
/* delay 1100ms */
wai_tsk(110);
}
void tsk2_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+2) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+2 , xb );
/* increment */
xcnt[2]++ ;
/* delay 1200ms */
wai_tsk(120);
}
void tsk3_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+3) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+3 , xb );
#ifdef DEBUG_C
rs_puts("* 3 +");
if ( xb ) { rs_putchar('1'); }
else { rs_putchar('0'); }
crlf();
#endif
/* increment */
xcnt[3]++ ;
/* delay 1300ms */
wai_tsk(130);
}
void tsk4_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+4) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+4 , xb );
/* increment */
xcnt[4]++ ;
/* delay 1400ms */
wai_tsk(140);
}
void tsk5_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+5) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+5 , xb );
/* increment */
xcnt[5]++ ;
/* delay 1500ms */
wai_tsk(150);
}
void tsk6_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+6) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+6 , xb );
/* increment */
xcnt[6]++ ;
/* delay 1600ms */
wai_tsk(160);
}
void tsk7_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( xcnt[7] & ON ) { xb = ON ; }
/* impress */
digitalWrite( LEDP , xb );
#ifdef DEBUG_C
rs_puts("* 7 +");
if ( xb ) { rs_putchar('1'); }
else { rs_putchar('0'); }
crlf();
#endif
/* increment */
xcnt[7]++ ;
/* delay 5000ms */
wai_tsk(50);
}
void tsk8_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+8) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+8 , xb );
/* increment */
xcnt[8]++ ;
}
タスク7のLED点滅は、Arduino基板で用意されている
LEDの点滅を担当。このタスクだけ、外部にあるLEDの
点滅処理から独立。
タスク0では、通信により特定のタスクをREADY、SUSPENDに
できるように、コマンド'T'、't'を用意。
コマンドの次にタスク番号1から8のいずれかを連ねると
対応タスクの状態を変更します。
また、'a'を指定すると、タスク番号1から8すべてのタスク
の状態を変更。
これらを考えて、1文字コマンドの仕様を以下としました。
- ? コマンド一覧を表示
- T 番号で指定したタスクをREADYに設定
- t 番号で指定したタスクをSUSPENDに設定
- S 各タスクの状態を表示
実際にコマンドを利用すると、次のようになります。
タスク0は、以下のように定義。
void tsk0_proc(void)
{
byte ii ;
char tmp ;
word xtmp ;
/* command interpreter (debug) */
if ( uflag ) {
/* clear flag */
uflag = OFF ;
/* command interpreter */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* set target task ready */
if ( cmd == 'T' ) {
/* get parameter */
tmp = *(sbuf+1) ;
/* all */
if ( tmp == 'a' ) {
for ( ii = 1 ; ii < 7 ; ii++ ) {
rsm_tsk( ii ) ;
}
rsm_tsk( 8 ) ;
} else {
/* get task number */
ii = tmp - '0' ;
/* judge and set */
if ( 0 < ii && ii < TSK_ID_MAX ) { rsm_tsk( ii ) ; }
}
}
/* set target task suspend */
if ( cmd == 't' ) {
/* get parameter */
tmp = *(sbuf+1) ;
/* all */
if ( tmp == 'a' ) {
for ( ii = 1 ; ii < 7 ; ii++ ) {
sus_tsk( ii ) ;
digitalWrite( PENTRY + ii , OFF );
}
sus_tsk( 8 ) ; digitalWrite( PENTRY + 8 , OFF );
} else {
/* get task number */
ii = tmp - '0' ;
/* judge and set */
if ( 0 < ii && ii < TSK_ID_MAX ) {
sus_tsk( ii ) ;
digitalWrite( PENTRY + ii , OFF );
}
}
}
/* show task status */
if ( cmd == 'S' ) { show_task_status(); }
}
}
USO2では、時間待ちを10msの倍数で扱うため、システムタイマーを使い
時間間隔を制御します。時間間隔を制御する処理は、以下。
void sys_tim_hnd()
{
byte ii ;
word xtmp ;
word diffx ;
boolean eflag ;
/* get current system counter */
curv = millis() ;
/* calculate difference */
diffx = curv - prev ;
/* ? time out */
eflag = OFF ;
if ( diffx >= DIFFX_MAX ) {
/* update counter */
prev = curv ;
/* set flag */
eflag = ON ;
}
if ( eflag == OFF ) return ;
/* timer handling */
xtmp = get_waitq() ;
for ( ii = 0 ; ii < TSK_ID_MAX ; ii++ ) {
/* judge WAIT */
if ( xtmp & 1 ) {
#ifdef DEBUG_C
rs_puts("TASK ");
Serial.print( ii );
Serial.println(" Decrement ");
#endif
dec_tsk_cnt(ii);
if ( get_tsk_cnt(ii) == 0 ) { rsm_tsk(ii); }
}
/* get next TASK state */
xtmp >>= 1 ;
}
#ifdef DEBUG_C
Serial.println(" timer ");
show_queue();
#endif
}
現在の時刻に相当するカウンタ値を入力し、前回のカウンタ値と
差分を求めて10msを超えていたなら、該当タスクがWAITかを確認
し、カウンタをデクリメント。
該当タスクのカウンタが0であれば、状態をWAITからREADYに遷移
させます。
タイマー割込みを使うと時間間隔の揺らぎが大きいので、関数loop()の
中で上の関数を呼び出すようにします。
この仕様で関数loop()は、次のように2関数を呼び出すだけになります。
void loop()
{
/* system timer handling */
sys_tim_hnd();
/* task handling */
task_dispatch();
}
タスクの状態を切り替えるための関数task_dispatch()は、次の
ように定義。
void task_dispatch()
{
/* get run_tsk value */
pcur_tsk = tcb[run_tsk] ;
#ifdef DEBUG_C
Serial.println(" dispatch in ");
#endif
if ( is_tsk_ready( run_tsk ) ) {
#ifdef DEBUG_C
rs_puts( " Perform " );
Serial.println( run_tsk );
#endif
(*(pcur_tsk.tsk))();
}
run_tsk++;
if ( run_tsk == TSK_ID_MAX ) { run_tsk = TSK_ID0 ; }
#ifdef DEBUG_C
Serial.println(" dispatch out ");
show_queue();
crlf();
#endif
}
変数run_tskを利用して、タスク0からタスク(TSK_ID_MAX-1)の
状態を調べて、READYであればRUNに遷移させて実行。
該当タスクがCPUを使い終われば、次のタスクの状態を調べに行きます。
関数loop()は、Arduinoでは無限ループとなるので
関数sys_tim_hnd()と関数task_dispatch()は、交互に
電源が落ちるまで実行されます。
Arduinoで必要になる関数setup()は、次のように定義。
void setup()
{
/* initialize serial port */
Serial.begin(115200);
rs_puts("Hello !");
crlf();
show_help();
sindex = 0 ;
/* clear flags */
uflag = OFF ;
/* default */
sys_tim_int();
/* initialize pin mode */
init_pin();
/* initialize */
init_os();
task_create();
task_start();
}
通信条件の設定、端末へのメッセージ出力、時間間隔の初期化
ピンの入出力方向設定、ピンの出力論理値指定、RTOSの初期化
タスク生成と初期状態設定等を関数にまとめてあるので、呼び
出しているだけ。
通信に関係する関数は、次のように定義。
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("T task ready") ; crlf();
rs_puts("t task suspend") ; crlf();
rs_puts("S show task status") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
時間間隔を初期化する処理は、以下。
void sys_tim_int()
{
/* get system counter */
prev = millis();
curv = prev ;
}
LEDの点滅を制御するために、ピンモードを指定する
処理は、次のように定義。
#define PENTRY 22
#define LEDP 13
void init_pin()
{
byte ii ;
for ( ii = 0 ; ii < TSK_ID_MAX ; ii++ ) {
pinMode(PENTRY+ii,OUTPUT);
digitalWrite(PENTRY+ii,LOW);
xcnt[ii] = 0 ; //xcnt[ii] = 1 ;
}
/* debug */
pinMode(LEDP,OUTPUT);
digitalWrite(LEDP,LOW);
}
配列変数xcntは、各LEDの状態を1か0のどちらに
するかの情報を格納してます。
タスクの初期化と状態指定は、次のようにまとめて
あります。
void task_create()
{
run_tsk = TSK_ID0 ;
cre_tsk(TSK_ID0,tsk0_proc);
cre_tsk(TSK_ID1,tsk1_proc);
cre_tsk(TSK_ID2,tsk2_proc);
cre_tsk(TSK_ID3,tsk3_proc);
cre_tsk(TSK_ID4,tsk4_proc);
cre_tsk(TSK_ID5,tsk5_proc);
cre_tsk(TSK_ID6,tsk6_proc);
cre_tsk(TSK_ID7,tsk7_proc);
cre_tsk(TSK_ID8,tsk8_proc);
}
void task_start()
{
sta_tsk(TSK_ID0,TTS_READY);
sta_tsk(TSK_ID1,TTS_SUSPEND);
sta_tsk(TSK_ID2,TTS_SUSPEND);
sta_tsk(TSK_ID3,TTS_READY);
sta_tsk(TSK_ID4,TTS_SUSPEND);
sta_tsk(TSK_ID5,TTS_SUSPEND);
sta_tsk(TSK_ID6,TTS_SUSPEND);
sta_tsk(TSK_ID7,TTS_READY);
sta_tsk(TSK_ID8,TTS_SUSPEND);
/* debug */
#ifdef DEBUG_C
Serial.println(" Initialize ");
show_queue();
#endif
}
Arduinoのソースコードは、以下。
#include "usop.h"
#define OFF 0
#define ON OFF+1
#define PENTRY 22
#define LEDP 13
#define DIFFX_MAX 10
#define TSK_ID_MAX 9
#ifndef DEBUG_C
#define DEBUG_C 1
#endif
/* function prototype serial inteferace */
void sys_tim_int();
void sys_tim_hnd();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();
void init_pin();
void task_create();
void task_start();
void task_dispatch();
void tsk0_proc(void);
void tsk1_proc(void);
void tsk2_proc(void);
void tsk3_proc(void);
void tsk4_proc(void);
void tsk5_proc(void);
void tsk6_proc(void);
void tsk7_proc(void);
void tsk8_proc(void);
void binary_display_word(word x);
void show_queue();
void show_task_status();
unsigned long curv ;
unsigned long prev ;
char sbuf[16] ;
byte sindex ;
char cmd ;
boolean uflag ;
byte xcnt[TSK_ID_MAX] ;
TCBP pcur_tsk ;
void setup()
{
/* initialize serial port */
Serial.begin(115200);
rs_puts("Hello !");
crlf();
show_help();
sindex = 0 ;
/* clear flags */
uflag = OFF ;
/* default */
sys_tim_int();
/* */
init_pin();
/* initialize */
init_os();
task_create();
task_start();
}
void loop()
{
/* system timer handling */
sys_tim_hnd();
/* task handling */
task_dispatch();
}
void sys_tim_int()
{
/* get system counter */
prev = millis();
curv = prev ;
}
void sys_tim_hnd()
{
byte ii ;
word xtmp ;
word diffx ;
boolean eflag ;
/* get current system counter */
curv = millis() ;
/* calculate difference */
diffx = curv - prev ;
/* ? time out */
eflag = OFF ;
if ( diffx >= DIFFX_MAX ) {
/* update counter */
prev = curv ;
/* set flag */
eflag = ON ;
}
if ( eflag == OFF ) return ;
/* timer handling */
xtmp = get_waitq() ;
for ( ii = 0 ; ii < TSK_ID_MAX ; ii++ ) {
/* judge WAIT */
if ( xtmp & 1 ) {
#ifdef DEBUG_C
rs_puts("TASK ");
Serial.print( ii );
Serial.println(" Decrement ");
#endif
dec_tsk_cnt(ii);
if ( get_tsk_cnt(ii) == 0 ) { rsm_tsk(ii); }
}
/* get next TASK state */
xtmp >>= 1 ;
}
#ifdef DEBUG_C
Serial.println(" timer ");
show_queue();
#endif
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("T task ready") ; crlf();
rs_puts("t task suspend") ; crlf();
rs_puts("S show task status") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void init_pin()
{
byte ii ;
for ( ii = 0 ; ii < TSK_ID_MAX ; ii++ ) {
pinMode(PENTRY+ii,OUTPUT);
digitalWrite(PENTRY+ii,LOW);
xcnt[ii] = 0 ; //xcnt[ii] = 1 ;
}
/* debug */
pinMode(LEDP,OUTPUT);
digitalWrite(LEDP,LOW);
}
void task_create()
{
run_tsk = TSK_ID0 ;
cre_tsk(TSK_ID0,tsk0_proc);
cre_tsk(TSK_ID1,tsk1_proc);
cre_tsk(TSK_ID2,tsk2_proc);
cre_tsk(TSK_ID3,tsk3_proc);
cre_tsk(TSK_ID4,tsk4_proc);
cre_tsk(TSK_ID5,tsk5_proc);
cre_tsk(TSK_ID6,tsk6_proc);
cre_tsk(TSK_ID7,tsk7_proc);
cre_tsk(TSK_ID8,tsk8_proc);
}
void task_start()
{
sta_tsk(TSK_ID0,TTS_READY);
sta_tsk(TSK_ID1,TTS_SUSPEND);
sta_tsk(TSK_ID2,TTS_SUSPEND);
sta_tsk(TSK_ID3,TTS_READY);
sta_tsk(TSK_ID4,TTS_SUSPEND);
sta_tsk(TSK_ID5,TTS_SUSPEND);
sta_tsk(TSK_ID6,TTS_SUSPEND);
sta_tsk(TSK_ID7,TTS_READY);
sta_tsk(TSK_ID8,TTS_SUSPEND);
/* debug */
#ifdef DEBUG_C
Serial.println(" Initialize ");
show_queue();
#endif
}
void task_dispatch()
{
/* get run_tsk value */
pcur_tsk = tcb[run_tsk] ;
#ifdef DEBUG_C
Serial.println(" dispatch in ");
#endif
if ( is_tsk_ready( run_tsk ) ) {
#ifdef DEBUG_C
rs_puts( " Perform " );
Serial.println( run_tsk );
#endif
(*(pcur_tsk.tsk))();
}
run_tsk++;
if ( run_tsk == TSK_ID_MAX ) { run_tsk = TSK_ID0 ; }
#ifdef DEBUG_C
Serial.println(" dispatch out ");
show_queue();
crlf();
#endif
}
void tsk0_proc(void)
{
byte ii ;
char tmp ;
word xtmp ;
/* command interpreter (debug) */
if ( uflag ) {
/* clear flag */
uflag = OFF ;
/* command interpreter */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* set target task ready */
if ( cmd == 'T' ) {
/* get parameter */
tmp = *(sbuf+1) ;
/* all */
if ( tmp == 'a' ) {
for ( ii = 1 ; ii < 7 ; ii++ ) {
rsm_tsk( ii ) ;
}
rsm_tsk( 8 ) ;
} else {
/* get task number */
ii = tmp - '0' ;
/* judge and set */
if ( 0 < ii && ii < TSK_ID_MAX ) { rsm_tsk( ii ) ; }
}
}
/* set target task suspend */
if ( cmd == 't' ) {
/* get parameter */
tmp = *(sbuf+1) ;
/* all */
if ( tmp == 'a' ) {
for ( ii = 1 ; ii < 7 ; ii++ ) {
sus_tsk( ii ) ;
digitalWrite( PENTRY + ii , OFF );
}
sus_tsk( 8 ) ; digitalWrite( PENTRY + 8 , OFF );
} else {
/* get task number */
ii = tmp - '0' ;
/* judge and set */
if ( 0 < ii && ii < TSK_ID_MAX ) {
sus_tsk( ii ) ;
digitalWrite( PENTRY + ii , OFF );
}
}
}
/* show task status */
if ( cmd == 'S' ) { show_task_status(); }
}
}
void tsk1_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+1) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+1, xb );
/* increment */
xcnt[1]++ ;
/* delay 1100ms */
wai_tsk(110);
}
void tsk2_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+2) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+2 , xb );
/* increment */
xcnt[2]++ ;
/* delay 1200ms */
wai_tsk(120);
}
void tsk3_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+3) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+3 , xb );
#ifdef DEBUG_C
rs_puts("* 3 +");
if ( xb ) { rs_putchar('1'); }
else { rs_putchar('0'); }
crlf();
#endif
/* increment */
xcnt[3]++ ;
/* delay 1300ms */
wai_tsk(130);
}
void tsk4_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+4) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+4 , xb );
/* increment */
xcnt[4]++ ;
/* delay 1400ms */
wai_tsk(140);
}
void tsk5_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+5) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+5 , xb );
/* increment */
xcnt[5]++ ;
/* delay 1500ms */
wai_tsk(150);
}
void tsk6_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+6) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+6 , xb );
/* increment */
xcnt[6]++ ;
/* delay 1600ms */
wai_tsk(160);
}
void tsk7_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( xcnt[7] & ON ) { xb = ON ; }
/* impress */
digitalWrite( LEDP , xb );
#ifdef DEBUG_C
rs_puts("* 7 +");
if ( xb ) { rs_putchar('1'); }
else { rs_putchar('0'); }
crlf();
#endif
/* increment */
xcnt[7]++ ;
/* delay 5000ms */
wai_tsk(50);
}
void tsk8_proc(void)
{
boolean xb ;
/* get value */
xb = OFF ;
if ( *(xcnt+8) & ON ) { xb = ON ; }
/* impress */
digitalWrite( PENTRY+8 , xb );
/* increment */
xcnt[8]++ ;
}
void binary_display_word(word x)
{
int ii ;
for ( ii = 15 ; ii > -1 ; ii-- ) {
rs_putchar( ((x >> ii) & ON) + '0' );
}
crlf();
}
void show_queue()
{
binary_display_word( get_ready() );
binary_display_word( get_suspend() );
binary_display_word( get_waitq() );
}
void show_task_status()
{
byte ii ;
byte jj ;
word xtmp ;
/* queue */
show_queue();
/* */
for ( jj = 0 ; jj < 3 ; jj++ ) {
/* READY , SUSPEND ,WAIT */
xtmp = get_ready();
if ( jj == 1 ) { xtmp = get_suspend(); }
if ( jj == 2 ) { xtmp = get_waitq(); }
/* display */
for ( ii = 0 ; ii < TSK_ID_MAX ; ii++ ) {
/* judge */
if ( xtmp & ON ) {
rs_puts("TASK ");
Serial.print( ii );
if ( jj == 0 ) { rs_puts(" is READY."); }
if ( jj == 1 ) { rs_puts(" is SUSPEND."); }
if ( jj == 2 ) { rs_puts(" is WAIT."); }
crlf();
}
/* shift */
xtmp >>= 1 ;
}
}
}
/* receive interrupt (debug) */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
このソースコードで、動作を確認すると、次のように
なります。
コマンド'S'は、各タスクの状態を表示します。
USO2では、各タスクの状態を16ビットの変数に
1か0で格納しています。
READY、SUSPEND、WAITの3状態のどれになって
いるのかは、該当変数のビット値を1か0で
判断できるようにしてあります。
3変数の状態を、コマンド'S'で確認できるように
関数を定義しておいたので、1と0の組み合わせで
タスクの状態を判断できます。
Arudinoで使うソースコードは、拡張子「.ino」ですが
プリプロセッサを利用して、デバッグしやすいように
してあります。
端末ソフトで、Arduinoスケッチの動作をテキストファイル
に格納して、デバッグしました。
テキストファイルの内容は、次のようになっています。
? help
A active
a disactive
D set delay
d show delay
Initialize
0000000010001001
0000000001110110
0000000000000000
dispach in
Perform 0
dispach out
0000000010001001
0000000001110110
0000000000000000
:
timer
0000000010001001
0000000001110110
0000000000000000
dispach in
Perform 3
* 3 +0
dispach out
0000000010000001
0000000001110110
0000000000001000
:
TASK 3 Decrement
timer
0000000010000001
0000000001110110
0000000000001000
:
TASK 3 Decrement
timer
0000000010000001
0000000001110110
0000000000001000
:
TASK 3 Decrement
timer
0000000010000001
0000000001110110
0000000000001000
:
TASK 3 Decrement
timer
0000000010000001
0000000001110110
0000000000001000
dispach in
Perform 7
* 7 +0
dispach out
0000000000000001
0000000001110110
0000000010001000
TASK 3 Decrement
TASK 7 Decrement
timer
0000000000000001
0000000001110110
0000000010001000
dispach in
Perform 0
dispach out
0000000000000001
0000000001110110
0000000010001000
:
時間間隔を扱う処理とタスクの切り替え担当を
交互に動かして、リアルタイムOSが設計通りに
動いているのかを確認できます。
目次
前