ページ

2011-12-24

[arduino]一定周期毎に処理を実行するためのフレームワーク的なもの

arduinoを使っていて、一定の周期ごとに任意の処理をしたい時がある。
しかも、色々な周期で色々やりたいときなどは、Delayなどを使って時間を調整するのは結構大変だ。

タイマ割り込みは標準だと使えない。


ということで、4種類の周期で任意の処理をするためのスケッチを描いてみた。
オシロスコープなどで確かめていない為、本当に一定の周期で実行されているかは保証できないが、LEDを光らせてみた感じではなんとなく良さそうだ。
また、micros();で時刻を取得する際に、Arduino内部のカウンタがオーバーフローした時などはおかしなタイミング生成がされる場合がある。
そのうち対策する予定です。

あと、ひとつの周期の処理は16msec以内に終わらせないと、次の周期の処理がずれていきます。


以下、スケッチ。

/*
 * 一定の周期(64msec, 128msec, 512msec, 1024msec, 4096ms)で特定の処理を
 * 行うためのフレームワーク?
 * 
 * 以下の各関数が各周期毎に実行される。
 *  execute64msTask()   -> 64msec毎に実行
 *  execute128msTask()  -> 128msec毎に実行
 *  execute512msTask()  -> 512msec毎に実行
 *  execute1024msTask() -> 1024msec毎に実行
 *  execute4096msTask() -> 4096msec毎に実行
 *
 * 各々の関数内に任意の処理を記述するだけで良い。
 * 但し、各周期の処理は16msec以内に終わるものとする。
 * 今後のバージョンアップにより、32msecに伸びる可能性有り。
 */


/* タスクID定義 */
const byte TASK_ID_64MS    = 1;
const byte TASK_ID_128MS   = 2;
const byte TASK_ID_512MS   = 3;
const byte TASK_ID_1024MS  = 4;
const byte TASK_ID_4096MS  = 5;

/* 現在のタスクインデックス 0-255を繰り返す.*/
byte taskIndex = 0;

/* 
 * タスクIDのテーブル. taskIndexから次に実行すべきタスクを決定する. 
 * 読みやすさの為、値をベタ書き.
 */
const byte taskIdTbl[] =
{
/*1        4           8          12          16 */
  1, 2, 3, 4, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 5, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 4, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 4, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 4, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 3, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,
  1, 2, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0,};

unsigned long taskStartTime = 0;     /* タスク開始時刻                */
unsigned long taskEndTime   = 0;     /* タスク終了時刻                */
int taskDelay               = 0;     /* 次の周期までの待ち時間        */
unsigned long BASE_DELAY    = 16000; /* 基本となるタスク実行周期 16ms */

unsigned int ledStat = 0;            /* LEDの状態. サンプル用. */

void setup(){
  /* LED サンプル用 */
  pinMode(13, OUTPUT);
}

void loop(){
  /* タスク実行時間計測の為、時刻をキャプチャ */
  taskStartTime = micros();
  
  /* 該当する周期のタスクを実行. */
  switch( taskIdTbl[taskIndex] ){
    case TASK_ID_64MS:
      execute64msTask();
      break;
    case TASK_ID_128MS:
      execute128msTask();
      break;
    case TASK_ID_512MS:
      execute512msTask();
      break;
    case TASK_ID_1024MS:
      execute1024msTask();
      break;
    case TASK_ID_4096MS:
      execute4096msTask();
      break;
    default:
      break;
  }
  /* タスクインデックスをインクリメント */
  taskIndex = taskIndex + 1;

  /* タスク完了時刻をキャプチャ */
  taskEndTime = micros();

  taskDelay = BASE_DELAY - (taskEndTime - taskStartTime);
  if( taskDelay >= 0 ){
    /*
     * delayMicrosecondsは16383マイクロ秒以内の値を
     * を指定したとき、正確に動作する.
     */
    delayMicroseconds(taskDelay);
  }
}

/*  64msec毎に起動する関数 */
void execute64msTask(){

}

/*  128msec毎に起動する関数 */
void execute128msTask(){

}

/*  512msec毎に起動する関数 */
void execute512msTask(){

}

/*  1024msec毎に起動する関数 */
void execute1024msTask(){

  if( getLedStat() ){
    digitalWrite(13,HIGH);
  }
  else{
    digitalWrite(13,LOW);
  }

}

/*  4096msec毎に起動する関数 */
void execute4096msTask(){

}

/* LED状態切替 サンプル用*/
boolean getLedStat(){
  boolean ret = false;

  if( ( ledStat % 2 ) == 0 ){
    ret = true;
  }
  ledStat = ledStat + 1;

  return ret;
}

0 件のコメント:

コメントを投稿