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