シリアル通信(RS-232C)で送信・受信を行うプログラム
SerialCommunication.h
#pragma once
#include "IReceiveEvent.h"
class CSerialCommunication
{
private:
HANDLE m_hComm; // COMポートのハンドル
CWinThread *m_receiveThread; // RS232C受信スレッド
public:
bool m_isReceiving; // RS232C受信を続けるかを示すフラグ
IReceiveEvent *m_receiveEvent; // 受信イベント発生時に呼び出すクラス
public:
/** コンストラクタ
* @param receiveEvent データ受信時に呼び出すメソッドを実装したインスタンスのポインタ
*/
CSerialCommunication(IReceiveEvent *receiveEvent);
/** デストラクタ */
~CSerialCommunication(void);
// シリアルポートを開いて,送受信をできるようにする
bool Open(LPCSTR strPort);
// シリアルポートを閉じる.受信も停止する.
void Close();
// シリアル通信で文字列を送る
void Send(LPCSTR str);
private:
// 受信時のイベントを投げる
void FireOnReceive(LPCSTR str);
private:
// シリアル受信スレッド
static UINT ReceiveRs232cFunc(LPVOID pParam);
};
SerialCommunication.cpp
#include "StdAfx.h"
#include "serialcommunication.h"
CSerialCommunication::CSerialCommunication(IReceiveEvent *receiveEvent)
{
m_hComm = NULL;
m_receiveThread = NULL;
m_receiveEvent = receiveEvent;
}
CSerialCommunication::~CSerialCommunication(void)
{
// シリアルポートを閉じる.受信も停止する.
Close();
}
// シリアルポートを開いて,送受信をできるようにする
bool CSerialCommunication::Open(LPCSTR strPort)
{
// 受信スレッドを終了する
m_isReceiving = false;
if (m_receiveThread != NULL) {
WaitForSingleObject(m_receiveThread, 4000);
m_receiveThread = NULL;
}
// 以前にポートをオープンしていたらクローズする
if (m_hComm != NULL) {
CloseHandle(m_hComm);
}
// シリアルポートのオープン
m_hComm = CreateFile(strPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(m_hComm == INVALID_HANDLE_VALUE){
AfxMessageBox("シリアルポートのオープンに失敗しました。\n" );
return false;
}
// シリアルポートの設定
DCB dcb;
GetCommState(m_hComm, &dcb); // DCB を取得
dcb.BaudRate = 9600; // baudrate
dcb.ByteSize = 8; // バイトサイズ
dcb.Parity = NOPARITY; // パリティ(使用しない,他にはEVENPARITY,ODDPARITY)
dcb.fParity = FALSE; // パリティを使用するか
dcb.StopBits = ONESTOPBIT; // ストップビット
dcb.fOutxCtsFlow = FALSE; // 送信時に、CTS を監視するかどうかを
dcb.fOutxDsrFlow = FALSE; // 送信時に、DSR を監視するかどうかを
dcb.fDsrSensitivity = FALSE;// DSR がOFFの間は受信データを無視するか
SetCommState(m_hComm, &dcb); // DCB を設定
// 受信スレッド開始
m_isReceiving = true;
m_receiveThread = AfxBeginThread(ReceiveRs232cFunc, this);
return true;
}
// シリアルポートを閉じる.受信も停止する.
void CSerialCommunication::Close()
{
// 受信スレッドを終了させる
m_isReceiving = false;
if (m_receiveThread != NULL) {
WaitForSingleObject(m_receiveThread, 4000);
m_receiveThread = NULL;
}
// シリアルポートのハンドルを閉じる
if(m_hComm != NULL){
CloseHandle(m_hComm);
m_hComm = NULL;
}
}
// シリアル通信で文字列を送る
void CSerialCommunication::Send(LPCSTR str)
{
// COMポートを開いているかチェック
if (m_hComm == NULL) {
AfxMessageBox("COMポートが開かれていません");
return;
}
// ** 送信! **
DWORD dwWrite; // COMポートに送ったバイト数
::WriteFile(m_hComm, str, (DWORD) strlen(str), &dwWrite, NULL);
}
// 受信時のイベントを投げる
void CSerialCommunication::FireOnReceive(LPCSTR str)
{
// イベント発生
if (m_receiveEvent != NULL) {
m_receiveEvent->OnReceive(str);
}
}
////////////////////////////////////////////////////////////////////////////
// static関数
// シリアル受信スレッド
UINT CSerialCommunication::ReceiveRs232cFunc(LPVOID pParam)
{
CSerialCommunication *pInst = (CSerialCommunication *) pParam; // Dlgインスタンス
CString str; // 受信した文字列
DWORD dwErrors; // エラー情報
COMSTAT ComStat; // デバイスの状態
DWORD dwCount; // 受信データのバイト数
char pszBuf[256];// 読み出しデータバッファ
DWORD dwRead; // ポートから読み出したバイト数
// メインループ
while (pInst->m_isReceiving) {
// 受信バッファにたまったデータサイズを得る
ClearCommError(pInst->m_hComm, &dwErrors, &ComStat);
dwCount = ComStat.cbInQue;
if (dwCount != 0) {
if (dwCount >= 256) {
dwCount = 255;
}
ZeroMemory(pszBuf, 256);
ReadFile(pInst->m_hComm, pszBuf, dwCount, &dwRead, NULL); // 受信
pszBuf[dwRead] = '\0'; // 文字列の最後にふたをする.
if (dwRead != 0) {
// temp文字列を文字列変数に追加
str.Append(pszBuf);
} else {
Sleep(10);
continue;
}
} else { // データが来てなければまつ
Sleep(10);
continue;
}
// テキストをセット
pInst->FireOnReceive(str);
str = "";
}
return 0;
}
イベント用インタフェース(IReceiveEvent.h)
#pragma once
// イベントを受信する場合,
// このクラスを継承して
// OnReceive()をオーバーライド実装してください.
class IReceiveEvent
{
public:
IReceiveEvent()
{
}
virtual ~IReceiveEvent()
{
}
// シリアル通信(RS-232C)のデータを受信したときに呼ばれる
virtual void OnReceive(LPCSTR str) = 0;
};
呼び出す側(Serial2Dlg.h)
#pragma once
#include "SerialCommunication.h"
#include "IReceiveEvent.h"
// CSerial2Dlg ダイアログ
class CSerial2Dlg : public CDialog, public IReceiveEvent
{
// シリアル通信用
CSerialCommunication *m_serial;
public:
// COMポートを入力するコンボボックス
CComboBox m_comboComPort;
// 送信する文字列を入れるエディットボックス
CEdit m_editSend;
// 受信した文字列を入れるエディットボックス
CEdit m_editReceived;
////////
// ※途中省略
////////
public:
// IReceiveEvent::OnReceive(LPCSTR str)の実装
void OnReceive(LPCSTR str);
呼び出す側(Serial2Dlg.cpp)
#include "serial2dlg.h"
// コンストラクタ
CSerial2Dlg::CSerial2Dlg(CWnd* pParent /*=NULL*/)
: CDialog(CSerial2Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
// シリアル通信用インスタンス作成
m_serial = new CSerialCommunication(this);
}
// シリアル通信開始
void CSerial2Dlg::OnBnClickedButtonStart()
{
CString strPort;
m_comboComPort.GetWindowText(strPort); // ポート名を取得
// COMポートオープン
m_serial->Open(strPort);
}
// シリアル通信停止
void CSerial2Dlg::OnBnClickedButtonStop()
{
// COMポートクローズ
m_serial->Close();
}
// シリアル通信で送る
void CSerial2Dlg::OnBnClickedButtonSend()
{
CString strSend;
m_editSend.GetWindowText(strSend); // ポート名を取得
m_serial->Send(strSend);
}
// IReceiveEvent::OnReceive(LPCSTR str)の実装
// データを受信したときに呼ばれる
void CSerial2Dlg::OnReceive(LPCSTR str)
{
// ** テキストをエディットボックスに追加 **
CString text;
// 現在のテキストを取得
m_editReceived.GetWindowText(text);
// テキストの最大長を超えていたらカットする
if (text.GetLength() > 10000) {
text = text.Right(10000);
}
// テキストを追加
text.Append(str);
m_editReceived.SetWindowText(text);
// フォーカスを最後に移動
m_editReceived.SetSel(text.GetLength(), text.GetLength(), false); // スクロールする
}
ソースコード(VC++版)のダウンロード(DL)
Serial2.zip
作成日: 2004年11月05日15時49日30秒
Serial2.zip
![[トップページ]](../lib/img//top.gif)
![[一覧]](../lib/img//list.gif)
![[検索]](../lib/img//search.gif)
![[ヘルプ]](../lib/img//help.gif)
![[ログイン]](../lib/img//login.gif)