超簡単!標準アプリで通信相手の出力の変更や入力の状態を知る

超簡単!標準アプリのシリアルメッセージ(書式形式)を解釈し、パソコンにデータの値を出力するサンプルスケッチです。

導入手順

  1. 下記のように配線する
    親機子機
    配線図
    使用する電子部品 TWELITE DIP x 1
    Arduino Uno x 1
    タクトスイッチ x 1
    LED x 1
    抵抗 680Ω(青・灰・茶) x 1
    抵抗 2.2kΩ(赤・赤・赤) x 1
    抵抗 3.3kΩ(橙・橙・赤) x 2
    抵抗 4.7kΩ(黄・紫・赤) x 1
    抵抗 10kΩ(茶・黒・橙) x 1
    トランジスタ 2SC1815 x1
    TWELITE DIP x 1
    タクトスイッチ x 1 LED x 1
    抵抗 680Ω(青・灰・茶) x 1
    電池ボックス x 1

    ※ 親機のTWELITE DIPは必ずBPSピンをGNDに接続して使用してください。

  2. こちらのページを参考に、Arduino IDEとライブラリをインストールする。
  3. Arduino IDEを起動させ、メニューバーの ファイル -> スケッチ例 -> MONOWIRELESS Serial Format Parser -> App_Twelite を選択する。
  4. メニューバーの スケッチ -> マイコンボードに書き込む を選択する。
  5. シリアルモニタをクリックする

使用方法

Arduinoに接続されたタクトスイッチを押している間は子機に接続されたLEDが光ります。また、子機のタクトスイッチを押している間はArduinoに接続されたLEDが点灯します。

出力例

TWELITEの子機からのパケットを親機が受信したときArudino IDEのシリアルモニタに下記のように出力されます。

Logical ID = 0x78
Command ID = 0x81
LQI = 99
Serial ID = 0x810039E7
Receive ID = 0x0
Timer = 17.67
Number of Relay = 0
Power Voltage = 2809
DI = 0000
DI Mask = 1111
ADC1 = 164
ADC2 = 364
ADC3 = 576
ADC4 = 1088

スケッチの解説

下記関数がメインループとなります。
bTWELITEDataArrived() を呼ぶことで、TWELITEからシリアル電文が受信できたか判定できます。 シリアル電文が受信できたらtrueを返し、SerialInにシリアル電文が保存されます。 その後、tsParseAppUart() を呼んでSerialIn内のデータを解釈し、LEDの制御を行います。

また、本ループではタクトスイッチの状態を判定し、vSend80Commond()で無線送信のリクエストも行います。

void loop() {
    /*
     * TWELITEからのシリアルデータを読み込み、PCへシリアル出力する
     */
    if(bTWELITEDataArrived()){
        // 0x81コマンドだったら表示
        tsAppTwelite sAppTwelite;
        if(bParseAppTwelite(SerialIn, &sAppTwelite)){
          //ここにデータが読めたときの処理を記述する
        }
    }
  
    // タクトスイッチの状態を確認し、前の状態と変化していたら送信する
    static byte SwState = 0x00;
    if ( SwState != digitalRead(SW) ) {
      SwState = !SwState;
      // 無線送信をする
      uint16 PWM[] = {0,0,0,0};
      vSend80Commond( 0x78, SwState, PWM );
    }
  }  

TWELITEとArduinoをつなぐためのクラス

sercmdは書式形式を解釈し、バイト列を得るためのクラスです。
このクラスは、書式形式の解釈とは逆にバイト列から書式形式を出力することができます。本スケッチではTWELITEからの入力用とTWELITEへの出力用の二つ定義します。
TWELITEへの出力用のsercmdを宣言する際に、MWPutChar()のような1バイトシリアル出力するための関数を定義し引数として渡します。

シリアル読み込み用のオブジェクトはメインループやbTWELITEDataArrived()で使用し、シリアル書き込み用のオブジェクトはvSend80Command()で使用します。

#include <sercmd.h>         // 書式形式のパーサー

…

// Global Object
sercmd SerialIn(false, 0, NULL );            // シリアル読み込み用のオブジェクト
sercmd SerialOut(false, 0, vPutChar );      // シリアル書き込み用のオブジェクト

…

// 書式形式出力用に1バイト出力関数
void vPutChar( unsigned char chr )
{
  ser.write(chr); // 1バイトシリアル出力する関数
}

受信処理を行う関数

下記関数でTWELITEからのシリアル入力を1バイトずつ読み込み、TWELITEからのシリアル電文が終わったかどうかを判断します。

パーサからの戻り値(u8stat)がE_SERCMD_COMPLETE(0x80)であれば解釈完了を示し、trueを返します。それ以外の場合はfalseを返します。
解釈が完了すると、sercmdクラスのau8dataに読み込んだバイト列、u16lenに読み込んだバイト列のバイト数が代入されています。 このとき、sercmdクラスのau8dataのデータはヘッダやフッダ、チェックサムは取り除かれた状態で保持されています。

u8statがE_SERCMD_ERRORやE_SERCMD_CHECKSUM_ERRORの場合、読み込みが失敗を示しているため次のデータを待ちます。

bool bTWELITEDataArrived()
{
  // TWELITEからの出力を確認する。
  int c = MWSerial.read();
  if (c >= 0) {
    // 1バイトずつ解釈をしていく
    byte u8stat = SerialIn.u8Parse(c);
    // 解釈に成功したら終了
    if (u8stat == E_SERCMD_COMPLETE) {
      return true;
    } else if (u8stat == E_SERCMD_CHECKSUM_ERROR) {
      // 電文中のチェックサムと計算したチェックサムが異なっているので、おそらく正しく読み込めなかった
      Serial.print("Command checksum error\n");
    }
  }
  return false;
}

送信処理を行う関数

下記関数に送信先と出力させたいDOのビットマップ(LSBがDO1で、1にしたポートをLoにする)、各PWMのDuty(0~1024)を渡すことで、0x80コマンドを生成しTWELITEに渡します。

void vSend80Command( byte Addr, byte DO, uint16* PWMDuty )

受信後のシリアルデータの解釈を行う関数

下記関数で受信したシリアルデータをtsAppTwelite構造体に変換します。引数はシリアル読み込み用のオブジェクト(SerialIn)とtsAppTwelite構造体のアドレスを指定します。

// シリアルデータを解釈する 解釈出来たらTrue,出来なかったらFalseを返す
bool bParseAppTwelite( sercmd cmd, tsAppTwelite* sAppTwelite )

受信したデータはtsParseAppTwelite()内で下記構造体にセットされメインループで使用してください。

// 受信したデータを保持する構造体
typedef struct
{
  byte LID;               // 送信側の論理デバイスID
  byte CMD;               // コマンド
  unsigned long SID;      // 送信側のシリアルナンバー
  byte IDE;               // パケット識別子
  byte PVE;               // プロトコルバージョン
  byte LQI;               // LQI
  byte RID;               // 受信側の論理デバイスID
  byte RNM;               // 中継回数
  float TMS;              // タイムスタンプ
  unsigned short PWR;     // 電源電圧(mV)
  byte DI;                // DIの状態 (1だったらLo)
  byte DIM;               // DIのマスク(1度でも変化したら1)
  unsigned short AD[4];   // アナログ電圧
} tsAppTwelite;