c++ 之 串口通信windows版

Windows API編寫串口,過程一般是這樣的:

1、 通過CreateFile(“COMx:“,…) 打開串口,創建串口句柄
串口1---9,爲comN。大於10,爲\\\\.\\COM10
2、 通過配置DCB結構體和SetCommState函數,設置串口的參數。
對串口的參數進行設置,其中比較重要的是波特率(BaudRate),數據寬度(BytesBits),奇偶校驗(Parity),停止位(StopBits),當然,重要的還有端口號(Port);

3、 然後對串口進行相應的讀寫操作,這時候用到ReadFile和WriteFile函數;

4、 讀寫結束後,要關閉串口句柄,用CloseFile;

代碼示例:

#pragma once

#include <windows.h>

class CSerial
{
public:
	CSerial(void);
	~CSerial(void);

	//打開串口
	BOOL OpenSerialPort(TCHAR* port,UINT baud_rate,BYTE date_bits,BYTE stop_bit,BYTE parity=NOPARITY);

	//發送數據
	BOOL SendData(char* data,int len);
public:
	HANDLE m_hComm;
};

#include "StdAfx.h"
#include "Serial.h"

typedef unsigned (__stdcall *PTHREAD_START) (void *);

CSerial::CSerial(void)
{
	m_hComm = INVALID_HANDLE_VALUE;
}

CSerial::~CSerial(void)
{
	if(m_hComm != INVALID_HANDLE_VALUE){
		CloseHandle(m_hComm);
	}
}

/*********************************************************************************************
 * 功能    :	讀串口線程回調函數 
 * 描述	   :	收到數據後,簡單的顯示出來
 ********************************************************************************************/
DWORD WINAPI CommProc(LPVOID lpParam){

	CSerial* pSerial = (CSerial*)lpParam;  //

	//清空串口
	PurgeComm(pSerial->m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR);

	char buf[512];
	DWORD dwRead;
	while(pSerial->m_hComm != INVALID_HANDLE_VALUE){
		BOOL bReadOK = ReadFile(pSerial->m_hComm,buf,512,&dwRead,NULL);
		if(bReadOK && (dwRead > 0)){
			buf[dwRead] = '\0';
			MessageBoxA(NULL,buf,"串口收到數據",MB_OK);
		}
	}
	return 0;
}

/*******************************************************************************************
 * 功能     :	打開串口
 * port     :	串口號, 如_T("COM1:")
 * baud_rate:	波特率
 * date_bits:	數據位(有效範圍4~8)
 * stop_bit :	停止位
 * parity   :	奇偶校驗。默認爲無校驗。NOPARITY 0; ODDPARITY 1;EVENPARITY 2;MARKPARITY 3;SPACEPARITY 4
 ********************************************************************************************/
BOOL CSerial::OpenSerialPort(TCHAR* port,UINT baud_rate,BYTE date_bits,BYTE stop_bit,BYTE parity){
	//打開串口
	m_hComm = CreateFile(port,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);//獨佔方式打開串口

	TCHAR err[512];

	if(m_hComm == INVALID_HANDLE_VALUE){
		_stprintf(err,_T("打開串口%s 失敗,請查看該串口是否已被佔用"),port);
		MessageBox(NULL,err,_T("提示"),MB_OK);
		return FALSE;
	}	

	//MessageBox(NULL,_T("打開成功"),_T("提示"),MB_OK);

	//獲取串口默認配置
	DCB dcb;
	if(!GetCommState(m_hComm,&dcb)){
		MessageBox(NULL,_T("獲取串口當前屬性參數失敗"),_T("提示"),MB_OK);
	}

	//配置串口參數
	dcb.BaudRate = baud_rate;	//波特率
	dcb.fBinary = TRUE;			//二進制模式。必須爲TRUE
	dcb.ByteSize = date_bits;	//數據位。範圍4-8
	dcb.StopBits = ONESTOPBIT;	//停止位

	if(parity == NOPARITY){
		dcb.fParity = FALSE;	//奇偶校驗。無奇偶校驗
		dcb.Parity = parity;	//校驗模式。無奇偶校驗
	}else{
		dcb.fParity = TRUE;		//奇偶校驗。
		dcb.Parity = parity;	//校驗模式。無奇偶校驗
	}

	dcb.fOutxCtsFlow = FALSE;	//CTS線上的硬件握手
	dcb.fOutxDsrFlow = FALSE;	//DST線上的硬件握手
	dcb.fDtrControl = DTR_CONTROL_ENABLE; //DTR控制
	dcb.fDsrSensitivity = FALSE;
	dcb.fTXContinueOnXoff = FALSE;//
	dcb.fOutX = FALSE;			//是否使用XON/XOFF協議
	dcb.fInX = FALSE;			//是否使用XON/XOFF協議
	dcb.fErrorChar = FALSE;		//是否使用發送錯誤協議
	dcb.fNull = FALSE;			//停用null stripping
	dcb.fRtsControl = RTS_CONTROL_ENABLE;//
	dcb.fAbortOnError = FALSE;	//串口發送錯誤,並不終止串口讀寫

	//設置串口參數
	if (!SetCommState(m_hComm,&dcb)){
		MessageBox(NULL,_T("設置串口參數失敗"),_T("提示"),MB_OK);
		return FALSE;
	}

	//設置串口事件
	SetCommMask(m_hComm,EV_RXCHAR); //在緩存中有字符時產生事件
	SetupComm(m_hComm,16384,16384);

	//設置串口讀寫時間
	COMMTIMEOUTS CommTimeOuts;
	GetCommTimeouts(m_hComm,&CommTimeOuts);
	CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
	CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
	CommTimeOuts.ReadTotalTimeoutConstant = 0;
	CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
	CommTimeOuts.WriteTotalTimeoutConstant = 1000;
/*若總共讀取8個字節。 間隔設置爲8ms, 總超時係數爲3ms,總超時常數爲3ms。 則總的超時時間爲3*8+3=27ms。若每個字符讀取的間隔爲7ms, 則這次操作總共能讀取4個字符。 就結束了。因爲讀取第5個字符時, 已經需要35ms, 超過總超時時間了。*/
	if(!SetCommTimeouts(m_hComm,&CommTimeOuts)){
		MessageBox(NULL,_T("設置串口時間失敗"),_T("提示"),MB_OK);
		return FALSE;
	}

	//創建線程,讀取數據
	HANDLE hReadCommThread = (HANDLE) _beginthreadex(NULL,0,(PTHREAD_START) CommProc,(LPVOID) this,0,NULL);

	return TRUE;
}

/********************************************************************************************
 * 功能    :	通過串口發送一條數據
 ********************************************************************************************/
BOOL CSerial::SendData(char* data,int len){
	if(m_hComm == INVALID_HANDLE_VALUE){
		MessageBox(NULL,_T("串口未打開"),_T("提示"),MB_OK);
		return FALSE;
	}

	//清空串口
	PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR);

	//寫串口
	DWORD dwWrite = 0;
	DWORD dwRet = WriteFile(m_hComm,data,len,&dwWrite,NULL);

	//清空串口
	PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR);

	if(!dwRet){
		MessageBox(NULL,_T("發送數據失敗"),_T("提示"),MB_OK);
		return FALSE;
	}
	return TRUE;
}

串口通訊中的DCB結構

typedef struct _DCB { // dcb 
	DWORD DCBlength;           // sizeof(DCB) 
	DWORD BaudRate;            // current baud rate 指定當前的波特率
	DWORD fBinary: 1;          // binary mode, no EOF check 指定是否允許二進制模式,WINDOWS 95中必須爲TRUE
	DWORD fParity: 1;          // enable parity checking 指定奇偶校驗是否允許
	DWORD fOutxCtsFlow:1;      // CTS output flow control 指定CTS是否用於檢測發送控制.當爲TRUE是CTS爲OFF,發送將被掛起
	DWORD fOutxDsrFlow:1;      // DSR output flow control 指定DSR是否用於檢測發送控制.當爲TRUE是DSR爲OFF,發送將被掛起
	DWORD fDtrControl:2;       // DTR flow control type DTR_CONTROL_DISABLE值將DTR置爲OFF, DTR_CONTROL_ENABLE值將DTR置爲ON, DTR_CONTROL_HANDSHAKE允許DTR"握手",
	DWORD fDsrSensitivity:1;   // DSR sensitivity 當該值爲TRUE時DSR爲OFF時接收的字節被忽略
	DWORD fTXContinueOnXoff:1; // XOFF continues Tx 指定當接收緩衝區已滿,並且驅動程序已經發送出XoffChar字符時發送是否停止.TRUE時,在接收緩衝區接收到緩衝區已滿的字節XoffLim且驅動程序已經發送出XoffChar字符中止接收字節之後,發送繼續進行。FALSE時,在接收緩衝區接收到代表緩衝區已空的字節XonChar且驅動程序已經發送出恢復發送的XonChar之後,發送繼續進行。
	DWORD fOutX: 1;            // XON/XOFF out flow control TRUE時,接收到XoffChar之後便停止發送.接收到XonChar之後將重新開始
	DWORD fInX: 1;             // XON/XOFF in flow control TRUE時,接收緩衝區接收到代表緩衝區滿的XoffLim之後,XoffChar發送出去.接收緩衝區接收到代表緩衝區空的XonLim之後,XonChar發送出去
	DWORD fErrorChar: 1;       // enable error replacement 該值爲TRUE且fParity爲TRUE時,用ErrorChar 成員指定的字符代替奇偶校驗錯誤的接收字符
	DWORD fNull: 1;            // enable null stripping TRUE時,接收時去掉空(0值)字節
	DWORD fRtsControl:2;       // RTS flow control RTS_CONTROL_DISABLE時,RTS置爲OFF RTS_CONTROL_ENABLE時, RTS置爲ON RTS_CONTROL_HANDSHAKE時,當接收緩衝區小於半滿時RTS爲ON 當接收緩衝區超過四分之三滿時RTS爲OFF RTS_CONTROL_TOGGLE時,當接收緩衝區仍有剩餘字節時RTS爲ON ,否則缺省爲OFF
	DWORD fAbortOnError:1;     // abort reads/writes on error TRUE時,有錯誤發生時中止讀和寫操作
	DWORD fDummy2:17;          // reserved 未使用
	WORD wReserved;            // not currently used 未使用,必須爲0
	WORD XonLim;               // transmit XON threshold 指定在XON字符發送這前接收緩衝區中可允許的最小字節數
	WORD XoffLim;              // transmit XOFF threshold 指定在XOFF字符發送這前接收緩衝區中可允許的最小字節數
	BYTE ByteSize;             // number of bits/byte, 4-8 指定端口當前使用的數據位
	BYTE Parity;               // 0-4=no,odd,even,mark,space 指定端口當前使用的奇偶校驗方法,可能爲:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY
	BYTE StopBits;             // 0,1,2 = 1, 1.5, 2 指定端口當前使用的停止位數,可能爲:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS
	char XonChar;              // Tx and Rx XON character 指定用於發送和接收字符XON的值
	char XoffChar;             // Tx and Rx XOFF character 指定用於發送和接收字符XOFF值
	char ErrorChar;            // error replacement character 本字符用來代替接收到的奇偶校驗發生錯誤時的值
	char EofChar;              // end of input character 當沒有使用二進制模式時,本字符可用來指示數據的結束
	char EvtChar;              // received event character 當接收到此字符時,會產生一個事件
	WORD wReserved1;           // reserved; do not use 未使用
} DCB; 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章