マイコンで比較的簡単にパソコンと通信する方法として、 シリアル通信があります。TeraTermとかハイパーターミナルを使えば、 簡単にデバッグすることができます。 とはいえ、バイナリデータをやりとりしたり、 本格的に通信を利用するアプリケーションを作るとなると、 プログラムを自作する必要があります。
TurboC++には、スレッドを簡単に扱うためのTThreadというコンポーネントが用意されています。 今回は、TThreadを継承して非同期のシリアル通信クラスを作成します。 けっこう適当にできているのでバグがあるかもしれないです。 以下にソースを置いておきます。
まずは、シリアル通信クラスの構造を示します。 バッファにはSTLのvectorを使いました。非同期書き込み中のバッファを操作するのは、 非常にアレなのでダブルバッファにしました。また、今回はRTSやDTSといった信号の制御や、 CTS変化などのイベントも受信できるようにしています。
//---------------------------------------------------------------------------
#ifndef CommPortH
#define CommPortH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <vector.h>
//---------------------------------------------------------------------------
//
// シリアルポート非同期通信クラス
//
//---------------------------------------------------------------------------
#define WAIT_COMM WAIT_OBJECT_0
#define WAIT_ESC (WAIT_OBJECT_0+1)
const int COMM_EVENT = 0;
const int ESC_FUNC = 1;
typedef void __fastcall (__closure *TRecvEvent)(char *RxData, int size);
typedef void __fastcall (__closure *TErrorEvent)(DWORD fEvent);
class TCommPort : public TThread
{
private:
//イベントオブジェクト
HANDLE hEventObjects[2];
OVERLAPPED fOverLapped;
OVERLAPPED fReadDummy;
OVERLAPPED fWriteDummy;
DWORD fEventMask;
DWORD fEvent;
//通信ポート
HANDLE hCom;
DCB comDcb;
COMSTAT comStat;
DWORD comError;
//通信バッファ
vector<char> RxBuff;
vector<char> TxBuff;
vector<char> TxData;
//プロパティ
int FEnabled;
int FChPort;
DWORD FEscFunc;
DWORD FBaudRate;
TRecvEvent FOnRecvEvent;
TErrorEvent FOnErrorEvent;
//内部メソッド
void __fastcall comm_event();
void __fastcall esc_func();
void create_dcb();
protected:
void __fastcall Execute();
public:
//コンストラクタとデストラクタ
__fastcall TCommPort(bool CreateSuspended=false);
virtual __fastcall ~TCommPort();
//オープンクローズ
bool Open();
void Close();
void EscapeFunction(DWORD dwFunc);
void SetEventMask(DWORD mask);
void ResetEventMask(DWORD mask);
//送信メソッド
void write(const char* data, int size);
void write(const char* buff);
//プロパティ
__property int Enabled
= { read=FEnabled };
__property int ChPort
= { read=FChPort, write=writeChPort };
__property DWORD BaudRate
= { read=FBaudRate, write=writeBaudRate };
__property TRecvEvent OnRecvEvent
= { read=FOnRecvEvent, write=FOnRecvEvent };
__property TErrorEvent OnErrorEvent
= { read=FOnErrorEvent, write=FOnErrorEvent };
private:
//プロパティ用アクセスメソッド
void writeChPort(int port);
void writeBaudRate(DWORD baud);
};
//---------------------------------------------------------------------------
#endif
| 値 | 意味 |
|---|---|
| CLRDTR | DTR信号をクリアします。 |
| CLRRTS | RTS信号をクリアします。 |
| SETDTR | DTR信号をセットします。 |
| SETRTS | RTS信号をセットします。 |
| SETXOFF | XOFF 文字を受信したときのように送信を行います。 |
| SETXON | XON 文字を受信したときのように送信を行います。 |
| 値 | 意味 |
|---|---|
| EV_CTS | CTS(送信可)信号の状態が変わったとき。 |
| EV_DSR | DSR(データセットレディ)信号の状態が変わったとき。 |
| EV_ERR | 回線状態エラーが発生したとき。回線状態エラーには、CE_FRAME、CE_OVERRUN、CE_RXPARITY があります |
__property int ChPort
= { read=FChPort, write=writeChPort };
のように宣言すれば、以下のようにChPortに代入したときに、
writeChPort(1)が呼び出されるというものです。
TCommPort comm; comm.ChPort = 1; //ここでwriteChPort(1);が呼び出される。
void hoge(char *RxData, int size);
void fuga(DWORD fEvent);