マイコンで比較的簡単にパソコンと通信する方法として、 シリアル通信があります。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);