青島のしま〜Blue Islands〜


シリアル通信(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秒
markSerial2.zip
更新履歴
2008年07月22日 2008年02月08日 2008年02月06日 2008年02月05日 2007年10月25日 2006年12月20日 2006年12月19日 2006年12月05日 2006年09月20日 2006年06月18日 2006年06月12日 2006年04月22日 2006年03月30日 2006年02月28日 2006年02月23日 2006年02月18日 2006年01月13日 2005年12月21日