シリアル通信アプリでLチカをする

シリアル通信アプリを使用して離れたArduinoのLEDを点灯/消灯させるサンプルスケッチです。

導入手順

  1. TWELITE DIPにシリアル通信アプリを書き込む。
  2. 下記のように配線する
    親機子機
    配線図
    使用する電子部品 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
    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は必ずBPSピンをGNDに接続して使用してください。

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

使用方法

Arduinoに接続されたタクトスイッチを押すと通信相手側のLEDが点灯します。

スケッチの解説

下記関数がメインループとなります

bTWELITEDataArrived() を呼ぶことで、TWELITEからシリアル電文が受信できたか判定できます。シリアル電文が受信できたらtrueを返し、SerialInにシリアル電文が保存されます。

その後、tsParseAppUart() を呼んでSerialIn内のデータを解釈し、LEDの制御や無線送信の成否の判定を行います。

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

void loop() {

    ...
    
    // 解釈に成功したら終了
    if (bTWELITEDataArrived()) {
      // 系列を読み出せたので構造体に代入する
      tsAppUart sAppUart = tsParseAppUart( SerialIn );

      // ここに TWELITE から来たシリアルメッセージを解釈し処理するコードを入れる。
      ...

    }

  // タクトスイッチの状態を確認し、前の状態と変化していたら電波を送信する
  static byte bSwState = 0x00;
  if ( bSwState != digitalRead(SW) ) {
    bSwState = !bSwState;
    // 無線送信をする
    vSendMessage( &bSwState, 1 );
  }

  ...

}

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

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

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

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

…

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

…

// 書式形式出力用に1バイト出力関数
void vPutChar( unsigned char chr )
{
  MWSerial.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;
}

送信処理を行う関数

下記関数に送信するデータの先頭アドレスとデータ長を渡すことで、TWELITEでMAC ACK付きの無線送信するためのシリアルデータを生成し、TWELITEに渡します。

シリアル通信アプリでは、シリアルデータを1度に80バイトまで送信できるので、本関数に渡すデータは80バイト以内にしてください。

void vSendMessage( byte* OutputData, byte Length )

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

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

tsAppUart tsParseAppUart( sercmd SerialData )

受信したデータはtsParseAppUart()内で下記構造体にセットされメインループに返戻値として戻ってきます。 tsAppUart内のDataに送信されてきたデータがビッグエンディアンで入っておりますので、そちらを読み込み、所望の処理を記述してください。

// 受信したデータを保管する構造体
typedef struct {
bool ExPacket;      // 拡張形式か否か
byte LID;           // 送信元の論理デバイスID
byte RspID;         // 応答ID
uint16 Length;      // データの長さ
byte Data[255];     // データ
/* 拡張形式でない場合は以下の変数は0xFFFFFFFFになる */
uint32 DistExAddr;  // 送信元のシリアルID
uint32 RcvExAddr;   // 送信先のシリアルID(論理デバイスIDを指定して送信している場合は0xFFFFFFFF)
byte LQI;           // 通信品質(高いほど良い)
/* ここまで */
} tsAppUart;// 受信したデータを保持する構造体