WIN32API


WIN32APIでシリアル(RS-232C / EIA-232D)通信



WIN32APIを使ったシリアル通信の手順です。
APIの実態はC(C++ではなく)で書かれた関数群なので、最近の「クラスのインスタンスを生成してオブジェクトのメソッドを叩く」というような使い方はできません。
闇雲にやったので、これで合ってるかどうか分からないけど、Windows 7 (32bit) 上で一応送受信とも通信には成功しました。

/*
 * WIN32APIでRS-232C通信
 * COM1ポートをオープンし、2400bps,データ長8ビット,パリティなし,ストップビット長1ビット,
 * RTSフローONで5秒間受信し、アドレスrecievedDataに受信したデータを格納します。
 * その後、「dummy data」という文字列を同じポートへ送信して終了します。
 */

#include <tchar.h>
#include <windows.h>

int rs232c() {

HANDLE comPort = CreateFile(_T("COM1"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); // シリアルポートを開く

DCB dcb; // シリアルポートの構成情報が入る構造体
GetCommState(comPort, &dcb); // 現在の設定値を読み込み

dcb.BaudRate = 2400; // 速度
dcb.ByteSize = 8; // データ長
dcb.Parity = NOPARITY; // パリティ
dcb.StopBits = ONESTOPBIT; // ストップビット長
dcb.fOutxCtsFlow = FALSE; // 送信時CTSフロー
dcb.fRtsControl = RTS_CONTROL_ENABLE; // RTSフロー

SetCommState(comPort, &dcb); // 変更した設定値を書き込み

Sleep(5000); // 受信バッファにメッセージが溜まるまで待つ

DWORD errors;
COMSTAT comStat;
ClearCommError(comPort, &errors, &comStat);
int lengthOfRecieved = comStat.cbInQue; // 受信したメッセージ長を取得する

char recievedData[lengthOfRecieved];
DWORD numberOfPut;
ReadFile(comPort, recievedData, lengthOfRecieved, &numberOfPut, NULL); // バッファから取り込み

const char* sentData = "dummy data"; // 送信する文字列
DWORD lengthOfSent = 10; // 送信する文字数
WriteFile(comPort, sentData, lengthOfSent, &numberOfPut, NULL); // ポートへ送信

CloseHandle(comPort); // シリアルポートを閉じる

return 0;
}



以下、解説です。
* tchar.hとwindows.hをインクルードしておく必要があります。

1. CreateFile関数で通信リソースを作成する

HANDLE CreateFile(
LPCTSTR lpFileName, // ファイル名
DWORD dwDesiredAccess, // アクセスモード
DWORD dwShareMode, // 共有モード
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // セキュリティ記述子
DWORD dwCreationDisposition, // 作成方法
DWORD dwFlagsAndAttributes, // ファイル属性
HANDLE hTemplateFile // テンプレートファイルのハンドル
);

// 例
HANDLE comPort = CreateFile(_T("COM1"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); // シリアルポートを開く

※10番以上のCOMポート名は _T("\\\\.\\COM10") としないと認識してくれません。

2. GetCommState関数でDCB構造体にシリアルポートの現在の情報を読み込む

BOOL GetCommState(
HANDLE hFile, // 通信デバイスのハンドル
LPDCB lpDCB // DCB( デバイス制御ブロック)構造体へのポインタ
);

// 例
DCB dcb; // シリアルポートの構成情報が入る構造体
GetCommState(comPort, &dcb); // 現在の設定値を読み込み

3. DCB構造体に変更したい情報を設定する

/* DCBの中身
DWORD DCBlength; // DCBサイズ (Do not touch!!)
DWORD BaudRate; // ボーレート(通信速度)
DWORD fBinary; // バイナリーモード(Windowsでは常にTrue)
DWORD fParity; // 可能化パリティチェック
DWORD fOutxCtsFlow; // CTSアウトプットフロー制御
DWORD fOutxDsrFlow; // DSRアウトプットフロー制御
DWORD fDtrControl; // DTRフロー制御タイプ
DWORD fDsrSensitivity; // DSR敏感さ
DWORD fTXContinueOnXoff; // XOFFはTxを続ける
DWORD fOutX; // XON/XOFF外部フロー制御
DWORD fInX; // XON/XOFF内部フロー制御
DWORD fErrorChar; // エラー置換可
DWORD fNull; // NULLストリッピング可
DWORD fRtsControl; // RTSフロー制御
DWORD fAbortOnError; // リード/ライトエラーでアボート
DWORD fDummy2; // リザーブ
WORD wReserved; // 現在未使用
WORD XonLim; // 送信XONスレッショルド
WORD XoffLim; // 送信XOFFスレッショルド
BYTE ByteSize; // 1バイトのビット数、4-8
BYTE Parity; // 0,1,2,3,4=パリティなし、奇数、偶数、マーク、スペース
BYTE StopBits; // 0,1,2=1, 1.5, 2
char XonChar; // 送受信 XON文字
char XoffChar; // 送受信 XOFF文字
char ErrorChar; // エラー置換文字
char EofChar; // 入力終了文字
char EvtChar; // 受信イベント文字
WORD wReserved1; // リザーブ、使用不可
*/

// 例
dcb.BaudRate = 2400; // 速度
dcb.ByteSize = 8; // データ長
dcb.Parity = NOPARITY; // パリティ
dcb.StopBits = ONESTOPBIT; // ストップビット長
dcb.fOutxCtsFlow = FALSE; // 送信時CTSフロー
dcb.fRtsControl = RTS_CONTROL_ENABLE; // RTSフロー

4. SetCommState関数でシリアルポートの設定を書き込む

BOOL SetCommState(
HANDLE hFile, // 通信デバイスのハンドル
LPDCB lpDCB // DCB( デバイス制御ブロック)構造体へのポインタ
);

// 例
SetCommState(comPort, &dcb); // 変更した設定値を書き込み

5. 受信バッファにデータが溜まるまでウェイトする

// 例
Sleep(5000); // 受信バッファにメッセージが溜まるまで待つ

6. ClearCommError関数で受信バッファに溜まっている文字数を取得する

BOOL ClearCommError(
HANDLE hFile, // 通信デバイスのハンドル
LPDWORD lpErrors, // エラーコードを受け取る変数へのポインタ
LPCOMSTAT lpStat // 通信状態バッファへのポインタ
);

// 例
DWORD errors;
COMSTAT comStat;
ClearCommError(comPort, &errors, &comStat);
int lengthOfRecieved = comStat.cbInQue; // 受信したメッセージ長を取得する

7. ReadFile関数で受信バッファからデータを読み込む

BOOL ReadFile(
HANDLE hFile, // ファイルのハンドル
LPVOID lpBuffer, // データバッファ
DWORD nNumberOfBytesToRead, // 読み取り対象のバイト数
LPDWORD lpNumberOfBytesRead, // 読み取ったバイト数
LPOVERLAPPED lpOverlapped // オーバーラップ構造体のバッファ
);

// 例
char recievedData[lengthOfRecieved];
DWORD numberOfPut;
ReadFile(comPort, recievedData, lengthOfRecieved, &numberOfPut, NULL); // バッファから取り込み

8. WriteFile関数でデータを送信する

BOOL WriteFile(
HANDLE hFile, // ファイルのハンドル
LPCVOID lpBuffer, // データバッファ
DWORD nNumberOfBytesToWrite, // 書き込み対象のバイト数
LPDWORD lpNumberOfBytesWritten, // 書き込んだバイト数
LPOVERLAPPED lpOverlapped // オーバーラップ構造体のバッファ
);

// 例
const char* sentData = "dummy data";
DWORD numberOfPut;
WriteFile(comPort, sentData, lengthOfSent, &numberOfPut, NULL); // ポートへ送信

9. CloseHandle関数でポートを閉じる

BOOL CloseHandle(
HANDLE hObject // オブジェクトのハンドル
);

// 例
CloseHandle(comPort); // シリアルポートを閉じる

※黒坂様よりご指摘を受け、34行目を char recievedData[lengthOfRecieved]; に書き換えました。(2015/06/05)




[ 戻る ]