Arduinoでクラスを使ったステートマシン（状態遷移）を試してみる

###概要
Arduinoで、ステートマシーンをクラス化、赤LED,緑LEDのステートマシンを継承で作成
インスタンス作成時にLEDポートを設定できるようにしてみました。
***
###動作
緑LEDは1秒周期で点滅を繰り返します。
赤LEDは1秒周期で点滅を繰り返します。位相オプション１にしているため、緑LEDから半サイクル遅れて動きます。
よって、相互点灯させています。
***
###ソースファイルについて
loop()では10ms毎にステートマシンを動かす様にしています。
ステートマシーンでは他の処理に渡せなくなってしまうのでdelay()は極力入れない作りにします。
***
```c++:LED2.ino
// OOP
// ステートマシン

#include "Arduino.h"
#include "StateMachine.h"
unsigned long gPreviousL10 = 0; //  10ms interval

//------------------------------------------------------------------
// Arduino固有の関数 setup() :初期設定
//------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  Serial.println("");
  Serial.println("class State Machine");
}

//---------------------------------------------------------------------
// Arduino main loop
//---------------------------------------------------------------------
void loop() {
  static state_machine Red(4,1000,0);   // 赤は1秒周期　（インスタンス生成）
  static state_machine Green(5,1000,1);  // 緑は1秒周期、ずらして点灯　（インスタンス生成）

  if( (millis() - gPreviousL10) >= 10){ // 10ms毎で状態遷移を稼働
    Green.StateCheck();
    Red.StateCheck();
    gPreviousL10 = millis();            // Reset task
  }
}
```

```c++:StateMachine.h
//　ステートマシンクラス
//　クラスの定義
class state_machine {
  enum {
    ST_INI = 0,
    ST_LED_ON,
    ST_WAIT1,
    ST_WAIT2,
    ST_LED_OFF,
  };

private:
  int m_state;      // クラス内で使用するメンバ変数　（m_***)
  int m_ledPin;
  int m_EventTime;
  int m_phase;
  unsigned long m_PreviousL100 = 0; //  100ms interval
  
public:
  state_machine(int pin,int et);
  void StateCheck();
};
```

```c++:StateMachine.cpp
#include "Arduino.h"
#include "StateMachine.h"

// コンストラクタ（初期化処理）
state_machine::state_machine(int pin, int et, int ph)
{
    m_ledPin = pin;             // メンバ変数 m_ledPinにpinを代入
    pinMode(m_ledPin, OUTPUT);  // ピンモードを指定
    m_EventTime = et;           // メンバ変数 m_EventTime に イベント時間を設定
    m_state = ST_NONE;          // メンバ変数 m_state に ST_NONEを代入
    m_phase = ph;               // メンバ変数 m_phase に 位相を設定
}

void state_machine::StateCheck()
{
    switch(m_state){
      case ST_NONE:
                      if(m_phase == 1)                 // phase が1だとST_WAIT1から
                        m_state = ST_WAIT1;
                      else
                        m_state = ST_LED_ON;
                      break;
      case ST_LED_ON:
                      digitalWrite(m_ledPin, HIGH);
                      m_PreviousL100 = millis();        // Reset task
                      m_state = ST_WAIT1;
                      break;
      case ST_WAIT1:
                      if( (millis() - m_PreviousL100) >= m_EventTime){
                        m_state = ST_LED_OFF;
                      }                        
                      break;
      case ST_LED_OFF:
                      digitalWrite(m_ledPin, LOW);
                      m_PreviousL100 = millis();        // Reset task
                      m_state = ST_WAIT2;
                      break;
      case ST_WAIT2:
                      if( (millis() - m_PreviousL100) >= m_EventTime){
                        m_state = ST_LED_ON;
                      }
                      break;
      default:
                      break;
    }
}
```