目次

応用例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の点滅を制御するタスクを各々用意して
 対応します。

 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文字コマンドの仕様を以下としました。

 実際にコマンドを利用すると、次のようになります。



 タスク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が設計通りに
 動いているのかを確認できます。


目次

inserted by FC2 system