夢工房(メカトロニクス・クラブ)
最終更新日2000/6/6

プログラムの流れ

プログラムの流れを初めに紹介します。

シリアルポートの制御は、基本的にファイルの入出力と同じです。したがって、CreateFile()関数でシリアルポートを開き、戻り値のファイルハンドルをReadFile()関数やWriteFile()関数の引数として、データの送受信をします。通信が終わったらCloseHandle()関数でシリアルポートを閉じます。ただし、ファイルの入出力と違うところは、シリアルポートの設定について記述することです。


シリアルポートを開く

先述したようにCrateFile()関数を使います。引数は以下の通りです。シリアルポートの制御場合、指定する引数が決まりきっているので簡単です。
HANDLE CreateFile(
        LPCSTR                  lpszComPort,            /* シリアルポート名前 */
        DWORD                   dwAccessMode,           /* アクセスモード */
        DWORD                   dwShareMode,            /* 共有モード */
        LPSECURITY_ATTRIBUTES   lpSecurityAttributes,   /* セキュリティに関する情報 */
        DWORD                   dwCreationDistribution, /* オープン時の動作 */
        DWORD                   dwFlagsAndAttributes,   /* 属性 */
        HANDLE                  hTemplateFile           /* テンプレートのハンドル */
);
lpszComPort
シリアルポートの名前を記述します。たとえば、COM1をオープンする場合、"COM1"とします。多くの場合、COM1からCOM4を指定することになります。

dwAccessMode
GENERIC_READ | GENERIC_WRITEとします。シリアルポートでデータを送受信する必要があるので、読み書き両方を指定します。

dwShareMode
0(ゼロ)を指定して、共有設定をしないようにしています。こうすることで、すでにオープンしいるポートを、再度オープンすることはなくなります(すでにオープンさているポートを開くと、CreateFile()関数は失敗します)。

lpSecurityAttributes
NULLを指定します。シリアルポートの制御に関係ないので、特に詳しくはふれません。

dwCreationDistribution
OPEN_EXISTINGを指定します。シリアルポートの場合、常にデバイスとして存在しているので、すでに存在しているファイル(シリアルポート)を開く、という指定をします。

dwCreationDistribution
FILE_ATTRIBUTE_NORMALを指定します。特に属性がないことを指定します。FILE_FLAG_OVERLAPPEDを指定することで、非同期で動作します。

hTemplateFile
NULLを指定します。シリアルポートの制御に関係ないので、特に詳しくはふれません。

シリアルポートを閉じる

シリアルポートを閉じる場合は簡単です。CreateFile()関数の戻り値であるファイルハンドルをCloseHandle()関数を使って解放するだけです。シリアルポートを使い終わったら必ずファイルハンドルは解放しましょう。関数のプロトタイプを書いておきます。
BOOL CloseHandle(HANDLE hHandle);
hHandle
CreateFile()関数の戻り値であるファイルハンドルを指定します。

データの送信

データの送信はWriteFile()関数を使います。プロトタイプは以下の通りです。
BOOL ReadFile(
        HANDLE       hFile,
        LPVOID       lpBuffer,
        DWORD        nNumberOfBytesToWrite,
        LPDWORD      lpNumberOfBytesWritten,
        LPOVERLAPPED lpOverlapped
);
hFile
CreateFile()関数の戻り値であるファイルハンドルを指定します。

lpBuffer
送信するデータが格納されているポインタを指定します。

nNumberOfBytesToRead
送信するバイト数を指定します。

lpNumberOfBytesRead
DWORD型のポインタを指定します。実際に送信したバイト数が格納されます。

lpOverlapped
NULLを指定します。シリアルポートの制御に関係ないので、特に詳しくはふれません。


データの受信

データの送信はReadFile()関数を使います。プロトタイプは以下の通りです。
BOOL ReadFile(
        HANDLE       hFile,
        LPVOID       lpBuffer,
        DWORD        nNumberOfBytesToRead,
        LPDWORD      lpNumberOfBytesRead,
        LPOVERLAPPED lpOverlapped
);
hFile
CreateFile()関数の戻り値であるファイルハンドルを指定します。

lpBuffer
受信バッファのポインタを指定します。このバッファに受信したデータが格納されます。

nNumberOfBytesToRead
受信するバイト数を指定します。ClearCommError()関数で受信バッファのバイト数が取得できます。詳しくは以下参照。

lpNumberOfBytesRead
DWORD型のポインタを指定します。実際に受信したバイト数が格納されます。

lpOverlapped
NULLを指定します。シリアルポートの制御に関係ないので、特に詳しくはふれません。

ClearCommError()関数でポートのエラーをクリアして、ポートの状態を取得することができます。この関数を使って、受信バッファのバイト数を取得して、ReadFile()関数のnNumberOfBytesToReadに指定します。この関数のプロトタイプは以下の通りです。
BOOL ClearCommError(
        HANDLE hFile,
        LPDWORD lpErrors,
        LPCOMSTAT lpStat
);
hFile
CreateFile()関数の戻り値であるファイルハンドルを指定します。

lpErrors
DWORD型のポインタを指定します。エラーマスクが格納されます。

lpStat
COMSTAT構造体へのポインタを指定します。この構造体にポートの状態が格納されます。この構造体のメンバは以下の通りです。

typedef _COMSTAT {
        DWORD fCtsHold;
        DWORD fDsrHold;
        DWORD fRlsdHold;
        DWORD fXoffHold;
        DWORD fXoffSend;
        DWORD fEof;
        DWORD fTxim;
        DWORD fReserved;
        DWORD cbInQue;
        DWORD cbOutQue;
} COMSTAT;
fCtsHolde
CTSの送信待ちで、送信が停止しているかどうかの情報が格納されています。この値がTRUEのとき、CTSの送信待ちで、送信が停止しています。

fDsrHold
DSRの送信待ちで、送信が停止しているかどうかの情報が格納されています。この値がTRUEのとき、DSRの送信待ちで、送信が停止しています。

fRlsdHold
RLSDの送信待ちで、送信が停止しているかどうかの情報が格納されています。この値がTRUEのとき、RLSDの送信待ちで、送信が停止しています。

fXoffHold
XOFFを受信して、送信が停止しているかどうかの情報が格納されています。この値がTRUEのとき、XOFFを受信したため、送信が停止しています。

fXoffSend
XOFFを送信して、送信が停止しているかどうかの情報が格納されています。この値がTRUEのとき、XOFFを送信したため、送信が停止しています。

fEof
EOFを受信したかどうかの情報が格納されています。この値がTRUEのとき、EOFを受信しています。

fTxim
受信バッファにデータが残っているかどうかの情報が格納されています。この値がTRUEのとき、送信バッファにデータが残っています。

fReserved
予約されています。使うことができません。

cbInQue
受信バッファのバイト数が格納されます。

cbOutQue
送信バッファのバイト数が格納されます。


DCB構造体とSetComSmtate()関数でシリアルポートの設定をする

CreateFile()関数ではシリアルポートの設定らしい設定をしませんでした。ファイル処理と共通する設定だけでしたが、シリアルポートでは通信速度やパリティ、フロー制御などの設定が必要です。DCB構造体とSetComSmtate()関数を使ってそれらの設定をします。まず、以下にDCB構造体のメンバを示します。

なお、わたし自身、シリアルポートの規格に詳しくないので、各種設定の意味をすべて把握しきれていません。加えて、MSDN Liblaryの英文をわたしが訳したということもあって、内容の正確さを保証できません。訂正などはメールでお願いします。

typedef struct _DCB {
        DWORD   DCBlength;              /* DCB構造体のサイズ */
        DWORD   BaudRate;               /* 通信速度 */
        DWORD   fBinary;                /* バイナリモードの設定 */
        DWORD   fParity;                /* パリティの設定 */
        DWORD   fOutxCtsFlow;           /* CTS出力フローコントロールの設定 */
        DWORD   fOutxDsrFlow;           /* DSR出力フローコントロールの設定 */
        DWORD   fDtrControl;            /* DTRフローコントロールの種類 */
        DWORD   fDsrSensitivity;        /* DSR信号処理の設定 */
        DWORD   fTXContinueOnXoff;      /* XOFF送信後の処理の設定 */
        DWORD   fOutX;                  /* XON/XOFF出力フローコントロールの設定 */
        DWORD   fInX;                   /* XON/XOFF入力フローコントロールの設定 */
        DWORD   fErrorChar;             /* パリティエラーの代替文字の設定 */
        DWORD   fNull;                  /* NULLバイトの破棄 */
        DWORD   fRtsControl;            /* RTSフローコントロールの設定 */
        DWORD   fAbortOnError1;         /* エラー時の動作 */
        DWORD   fDummy2;                /* 予約 */
        WORD    wReserved;              /* 予約 */
        WORD    XonLim;                 /* XON文字送信の最小値バイト数 */
        WORD    XoffLim;                /* XOFF文字送信の最小値バイト数 */
        BYTE    ByteSize;               /* 1バイトのサイズ */
        BYTE    Parity;                 /* パリティの種類 */
        BYTE    StopBits;               /* ストップビットの種類 */
        char    XonChar;                /* XON文字 */
        char    XoffChar;               /* XOFF文字 */
        char    ErrorChar;              /* パリティエラーの代替文字 */
        char    EofChar;                /* EOF文字 */
        char    EvtChar;                /* イベント通知文字 */
        WORD    wReserved1;             /* 予約 */
} DCB;
DCBlength
DCB構造体のサイズを指定します。

BaudRate
シリアルポートの通信速度を指定します。そのまま、速度の整数値(9600bpsであれば9600とする)を指定します。

fBinary
バイナリモードの有効無効を指定します。1で有効、0で無効になります。この設定を無効にすることはできません(Win32APIがバイナリモードしかサポートしてないため)。

fParity
パリティモードの有効無効を指定します。1で有効、0で無効になります。

fOutxCtsFlow
出力フローコントロールとして、CTS信号をモニタするかどうかの有効無効を指定します。1で有効、0で無効になります。有効にすることで、CTS信号が再び送信されるまで、データ出力を中断します。

fOutxDsrFlow
出力フローコントロールとして、DSR信号をモニタするかどうかの有効無効を指定します。1で有効、0で無効になります。有効にすることで、DSR信号が再び送信されるまで、データ出力を中断します。

fDtrControl
DTRフローコントロールの種類を指定します。

DTR_CONTROL_DISABLEDTR =フローコントロール有効
DTR_CONTROL_ENABLEDTR =フローコントロール無効
DTR_CONTROL_HANDSHAKEDTR =ハンドシェイク有効

fDsrSensitivity
DSRフローコントロールが無効の間、受信データを無視するかどうかの有効無効を指定します。1で有効、0で無効になります。

fTXContinueOnXoff
XoffCharを送信ししたときに、データ送信を中断するかどうかの有効無効を指定します。1で有効、0で無効になります。なお、この設定を有効にすると、XoffCharが送信されたときにも、データの送信は続けられます。

fOutX
データが送信されている間、XON/XOFF出力フローコントロールをするかどうかの有効無効を指定します。1で有効、0で無効になります。なお、有効にすることで、XoffCharを受信したときにデータの送信が中断され、XonCharを受信したときにデータの送信を再開します。

fInX
データを受信している間、XON/XOFF入力フローコントロールをするかどうかの有効無効を指定します。1で有効、0で無効になります。なお、有効にすることで、受信バッファの空き容量がXoffLim以下なったときにXoffCharを送信し、受信バッファのデータがXonLim以下になったときにXonCharを送信します。

fErrorChar
パリティエラー時に代替文字を使用するかどうかの有効無効を指定します。1で有効、0で無効になります。

fNull
NULLバイトを破棄するかどうかの有効無効を指定します。1で有効、0で無効になります。

fRtsControl
RTSフローコントロールの種類を指定します。RTSハンドシェイクを指定すると、受信バッファが1/2になるとRTSフローコントロールが有効になり、3/4になると無効になります。また、RTSトグルを指定すると、受信バッファにデータがある場合にRTSフローコントロールが有効になり、データがない場合に無効になります。

RTS_CONTROL_ENABLE =RTSフローコントロール有効
RTS_CONTROL_DISABLE =RTSフローコントロール無効
RTS_CONTROL_HANDSHAKE =RTSハンドシェイク有効
RTS_CONTROL_TOGGLE =RTSトグル有効

fAbortOnError1
エラーが発生した場合に、データの送受信を行うかどうかの有効無効を指定します。1で有効、0で無効になります。

fDummy2
予約済みです。使用できません。

wReserved
常に0(ゼロ)を指定します。

XonLim
XonCharを送信するまでの受信バッファのデータ容量を指定します。受信バッファの容量がXonLim以下なれば、XonCharを送信します。

XoffLim
XoffCharを送信するまでの受信バッファの空き容量を指定します。受信バッファの空き容量がXoffLim以下になれば、XoffCharを送信します。

ByteSize
1ビットのバイト数を指定します。4〜8バイトの間で指定できます。

Parity
パリティの種類を指定します。

EVENPARITY =偶数パリティ
MARKPARITY =マークパリティ
NOPARITY =パリティなし
ODDPARITY =奇数パリティ
SPACEPARITY =空白パリティ

StopBits
ストップビットの種類を指定します。

ONESTOPBIT =1ストップビット
ONE5STOPBITS =1.5ストップビット
TWOSTOPBITS =2ストップビット

XonChar
XON文字を指定します。

XoffChar
XOFF文字を指定します。

ErrorChar
パリティエラーの代替文字を指定します。

EofChar
EOF文字を指定します。

EvtChar
イベント通知文字を指定します。

wReserved1
予約済みです。使用できません。

つぎに、DCB構造体に値を代入した後に、SetCommState()関数でDCB構造体の情報を(OSに)登録します。SetCommState()関数のプロトタイプを示します。
BOOL SetCommState(
	Handle hHandle,
	LPDCB lpDCB
	);
hHandle
CreateFile()関数の戻り値であるファイルハンドルを指定します。

lpDCB
DCB構造体へのポインタを指定します。


COMMTIMEOUTS構造体とSetComTimeouts()関数でシリアルポートのタイムアウトを設定する

タイムアウトは絶対指定するものではありませんが、プログラムの処理上必要になる場合もあります。
typedef struct _COMMTIMEOUTS {  
        DWORD ReadIntervalTimeout;
        DWORD ReadTotalTimeoutMultiplier;
        DWORD ReadTotalTimeoutConstant;
        DWORD WriteTotalTimeoutMultiplier;
        DWORD WriteTotalTimeoutConstant;
};
ReadIntervalTimeout
(連続して)2文字を受信するときに、はじめの文字(1文字目)を受信してから、次の文字(2文字目)を受信するまでの最大の許容時間をミリ秒で指定します。つまり、はじめの文字を受信してから、ReadIntervalTimeoutで指定しただけ時間が経過してしまうと、受信操作が終了します(タイムアウトとなります)。このタイムアウトを無効にするには、0(ゼロ)を指定します。

ReadTotalTimeoutMultiplier
受信タイムアウトの計算に使われる倍数をミリ秒で指定します。くわしくは、下記参照。

ReadTotalTimeoutConstant
受信タイムアウトの計算に使われる定数をミリ秒で指定します。くわしくは、下記参照。

WriteTotalTimeoutMultiplier
送信タイムアウトの計算に使われる倍数をミリ秒で指定します。くわしくは、下記参照。

WriteTotalTimeoutConstant
送信タイムアウトの計算に使われる定数をミリ秒で指定します。くわしくは、下記参照。

送受信タイムアウトで各メンバは次式の計算要素になります(ReadIntervalTimeout以外)。次式を使って、処理に必要なタイムアウト時間を決定してください。

(受信タイムアウト) = ReadTotalTimeoutMultiplier * (受信バイト数) + ReadTotalTimeoutConstant
(送信タイムアウト) = WriteTotalTimeoutMultiplier * (送信バイト数) + WriteTotalTimeoutConstant

次に、COMMTIEOUTS構造体に値を代入した後に、SetCommTimeouts()関数でCOMMTIEOUTS構造体の情報を(OS)に登録します。SetCommTimeouts()関数のプロトタイプを示します。

BOOL SetCommTimeouts(
        HANDLE hHandle,
        LPCOMMTIMEOUTS lpCommTimeouts
);
hHandle
CreateFile()関数の戻り値であるファイルハンドルを指定します。

lpCommTimeouts
COMMTIEOUTS構造体へのポインタを指定します。


前のページに戻る