ジャンプベクタ方式による疑似マルチタスク

# ジャンプベクタ方式による疑似マルチタスク
マルチタスク･マルチスレッドの無い組み込みプログラムでの疑似マルチタスクの実装
考え方としてはシンプルで、ジャンプベクタ（関数ポインタ）を定義して、このa_vectの中身を処理の進み具合に合わせて書き換えて行けば処理を進めることが出来る。　　
ポイントは各関数の中では待たないこと。行うべきことがあれば行ってジャンプベクタを書き換える。何等かの条件成立を待つところでは、条件が成り立つまでは何もせずに抜けて条件が成立したらジャンプベクタを書き換える。
ジャンプベクタ（関数ポインタ）を複数準備すれば、並行して複数の処理を行うことが出来る。
以下はTM1638ボードによるボタン入力を受けて分岐、再度ボタン入力があったらアイドルループに戻る例。
ここでは a_vectの１タスクのみであるが、複数の関数ポインタを定義してそれぞれ異なる処理を持たせることが出来る。ここでは void型引数なしを選択したが、戻り値型、引数はシステムの必要に応じて決定すればよい。
~~~C++
#include <MsTimer2.h>
#include <TM1638plus.h>
#define LED_BUILTIN (13)

#define INTERVAL  (5)	//Timer Interval
#define CHATCOUNT (10)	//チャタリング除去回数
// GPIO I/O pins on the Arduino connected to strobe, clock, data,
//pick on any I/O you want.
#define  STROBE_TM 4 // strobe = GPIO connected to strobe line of module
#define  CLOCK_TM 6  // clock = GPIO connected to clock line of module
#define  DIO_TM 7 // data = GPIO connected to data line of module
bool high_freq = false; //default false,, If using a high freq CPU > ~100 MHZ set to true.

//Constructor object (GPIO STB , GPIO CLOCK , GPIO DIO, use high freq MCU)
TM1638plus tm(STROBE_TM, CLOCK_TM , DIO_TM, high_freq);

volatile uint8_t  buttonBuf = 0;

 void (*a_vect)(void);	//Jump Vector　本稿の主題


//タイマー割りこみハンドラ
//チャタリング除去付きボタン情報更新
void buttonUpdate()
{
  static uint8_t cindex = 0;
  static uint8_t bArray[CHATCOUNT]={0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55 };
  uint8_t  btn = tm.readButtons();

  bool b = true;
  bArray[cindex]=btn;
  
  for( int i = 1; i <CHATCOUNT;i++){
      int index= (cindex+i)%CHATCOUNT;
      b &= (btn == bArray[index]); 
  }
  if( b ){
    buttonBuf = btn; 

  }
  cindex++;
  cindex %= CHATCOUNT; 
}


//表示をスペースでクリア
void clearDisplay()
{
  tm.displayText("        ");
}



//いずれかのボタンが押されるのを待つ
//ボタンが押されたら開放待ちへ
void func11(void)
{
    digitalWrite(LED_BUILTIN, (buttonBuf != 0));
    
      /* buttons contains a byte with values of button s8s7s6s5s4s3s2s1
       HEX  :  Switch no : Binary
       0x01 : S1 Pressed  0000 0001
       0x02 : S2 Pressed  0000 0010
       0x04 : S3 Pressed  0000 0100
       0x08 : S4 Pressed  0000 1000
       0x10 : S5 Pressed  0001 0000
       0x20 : S6 Pressed  0010 0000
       0x40 : S7 Pressed  0100 0000
       0x80 : S8 Pressed  1000 0000
      */
    if( buttonBuf != 0 ){
      Serial.write("func11 change vect\n");
      
     
      a_vect = func12;     //ジャンプベクタ更新
    }

    return;
   
}

//ボタン開放を待つ。
//解放されたらアイドルループへ
void func12(void)
{

  if( buttonBuf ==0){
      Serial.write("func12 change vect\n");
      a_vect = idlefunc;      //ジャンプベクタ更新

  }

}


//ボタン1押下時処理
void funcS1(void)
{
    Serial.write("funcS1\n");
    a_vect = func11; //ジャンプベクタ更新
}

//ボタン２押下時処理
void funcS2(void)
{
    Serial.write("funcS2\n");
    a_vect = func11; //ジャンプベクタ更新
}

//ボタン３押下時処理
void funcS3(void)
{
    Serial.write("funcS3\n");
    a_vect = func11; //ジャンプベクタ更新
}

//ボタン4押下時処理
void funcS4(void)
{
    Serial.write("funcS4\n");
    a_vect = func11; //ジャンプベクタ更新
}


//アイドルループ
//ボタン１～４が押されるのを待つ
void idlefunc(void)
{
      /* buttons contains a byte with values of button s8s7s6s5s4s3s2s1
       HEX  :  Switch no : Binary
       0x01 : S1 Pressed  0000 0001
       0x02 : S2 Pressed  0000 0010
       0x04 : S3 Pressed  0000 0100
       0x08 : S4 Pressed  0000 1000
       0x10 : S5 Pressed  0001 0000
       0x20 : S6 Pressed  0010 0000
       0x40 : S7 Pressed  0100 0000
       0x80 : S8 Pressed  1000 0000
      */
    
    
    if( buttonBuf&0x0f)
    {      
        char tmp[32];
        sprintf(tmp, "%02x", buttonBuf);
        Serial.write( tmp );
        Serial.write( "-idlefunc Change Vect\n" );
    }

    switch( buttonBuf)
    { //ボタン入力によってジャンプベクタ更新
        case 0x01:  a_vect = funcS1;  break;
        case 0x02:  a_vect = funcS2;  break;
        case 0x04:  a_vect = funcS3;  break;
        case 0x08:  a_vect = funcS4;  break;
    }
   
    return;
}

//Arduino Setup
void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  
  Serial.begin(115200);

  tm.displayBegin();
  clearDisplay();
  a_vect = idlefunc;
  MsTimer2::set(INTERVAL, buttonUpdate); //タイマーハンドラでボタン情報更新
  MsTimer2::start();
  delay(100);

}

//Arduino loop 
//ジャンプベクタ＝タスクが複数あれば複数記述
void loop() {
  a_vect();

}

~~~