2019年12月28日土曜日

ArduinoでMTSプロトコルでデータを送信してみる

InnovateのMTSプロトコルをArduinoで出力してみた。といっても本家MTSのようにデイジーチェーンまでは実装していないけど…
とりあえずLogWorks3で認識してくれるようなレベルなSSI-4互換機的なものを作ってみた。
応用すればPLX SM-AFRのiMFDプロトコルをMTSプロトコルに変換したりとかできるかも?
一応プロトコルの仕様書とかSDKは公開されているのでそいつらを参考にした。
実機はRS-232CでコネクタはMicro-Fit 3.0もしくは2.5mmジャック。
白がRX、赤がTX、黒はGNDで青をGNDに落とすと接続検知になってる。
Baudrate 19200bpsで81.92ms間隔でのデータストリームになっているっぽい。
とりあえずSSI-4として振る舞い、Aux1~4にADCのデータを突っ込むサンプル。
MAX31855を使って熱電対の情報を入れたり、BMP388を使って圧力ログったりできるかも。

volatile unsigned long ofc = 0;
volatile boolean ovf = false;
volatile int res = 0;
volatile unsigned int aux[4]={0,0,0,0};


//Timer2 overflow interrupt vector handler
ISR(TIMER2_OVF_vect) {
  ofc++;
  //256(8bit)x1024(Prescaler)/16000000(Clock)*5 = 81.92ms
  if(!ovf && ofc >= 5){
    ofc = 0;
    ovf = true;
    mts_send();
    ovf = false;
  }
};

void mts_send(){
  switch (res){
    case 0:
      //Header Word
      //1011 0010 1000 0100
      //0xB2 0x84
      Serial.write(0xB2);
      Serial.write(0x84);
      
      //Aux Channels
      //0000 D10D9D8D7 0D6D5D4 D3D2D1D0
      for (int i = 0; i <= 3; ++i){
        byte auxword[2];
        auxword[1] = lowByte(aux[i]) & 0x7F;
        auxword[0] = ((highByte(aux[i]) & 0x07) << 1) | ((lowByte(aux[i]) & 0x80) >> 7);
        Serial.write(auxword,2);
      }

      break;
    case 1://0xCE
      //Header Word
      //1010 0010 1000 0101
      //0xA2 0x85
      Serial.write(0xA2);
      Serial.write(0x85);

      //0xCE
      //0000 0001 0100 1110
      //0x01 0x4E
      Serial.write(0x01);
      Serial.write(0x4E);

      //Device Name
      Serial.write(0x53);//S
      Serial.write(0x53);//S
      Serial.write(0x49);//I
      Serial.write(0x34);//4
      Serial.write(0x00);
      Serial.write(0x00);
      Serial.write(0x00);
      Serial.write(0x00);
      res = 0;
      digitalWrite(LED_BUILTIN, LOW);//debug
      break;
     case 2://0xF3
      //Header Word
      //1010 0010 1000 0101
      //0xA2 0x85
      Serial.write(0xA2);
      Serial.write(0x85);

      //0xF3
      //0000 0001 0111 0011
      //0x01 0x73
      Serial.write(0x01);
      Serial.write(0x73);
      //Firmware Version
      Serial.write(0x12);
      Serial.write(0x3A);
      //Identifier
      Serial.write(0x53);
      Serial.write(0x53);
      Serial.write(0x49);
      Serial.write(0x34);
      //CPU
      Serial.write(0x01);
      //Channnel/Flags
      Serial.write(0x04);

      res = 0;
      digitalWrite(LED_BUILTIN, LOW);//debug
      break;
  }
}


void setup() {
  //Timer2 Settings: Timer Prescaler /1024, WGM mode 0
  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;

  //Timer2 Overflow Interrupt Enable  
  TIMSK2 = 1<<TOIE2;

  //reset timer
  TCNT2 = 0;

  Serial.begin(19200);
  pinMode(LED_BUILTIN, OUTPUT);//debug

}

void loop() {
  aux[0] = analogRead(A0);
  aux[1] = analogRead(A1);
  aux[2] = analogRead(A2);
  aux[3] = analogRead(A3);
}

void serialEvent() {
  while (Serial.available()) {
    switch (Serial.read()) {
      digitalWrite(LED_BUILTIN, HIGH);//debug
      case 0xCE:
        res = 1;//obtain device names
        break;
      case 0xF3:
        res = 2;//obtain device types
        break;
      case 'H':
        TCNT2 = 0;
        break;
    }
  }
}

こんなもんでLogWorks3で認識されてる。

今回は81.92ms間隔でデータを送信するのに8bitタイマーを5回オーバーフローさせて使ってるけど(本家は16bitタイマーっぽい表記があるけど)そこらへんの精度の問題とかもよくわからん…
あとADのデータを割り込み内で取り込むべきかどうかとかとかも悩む。

こいつを応用すればArduino 1台で複数のMTS対応デバイスをエミュレートできるかも。
Arduino一つでSSI-4を2台分とか。

0 件のコメント:

コメントを投稿