#pragma once
#include
/*
SerialPort.h
封装了串口通讯的WindowsAPI,支持异步操作串口
*/
class CSerialPort
{
public:
CSerialPort(void);
~CSerialPort(void);
bool Open(int nPort = 2, int nBaud = 115200);
bool Close(void);
// 从串口读数据
int ReadData(void *, int);
// 向串口写数据
bool WriteCommByte(unsigned char*, int);
// 查询缓冲区是否有未读取的数据
int ReadDataWaiting(void);
inline bool IsOpen(void) { return m_bOpened; }
protected:
// 内部实现,向串口写数据
bool WriteCommByte(unsigned char);
HANDLE m_hIDComDev;
OVERLAPPED m_OverLappedRead;
OVERLAPPED m_OverLappedWrite;
bool m_bOpened;
};
#include "SerialPort.h"
#define BUFFER_INPUT_RECOMMENT 10240
#define BUFFER_OUTPUT_RECOMMENT 10240
// 不使用读超时
#define TIMEOUT_READ_INTERVAL 0xFFFFFFFF
// 读超时
#define TIMEOUT_READ_TOTAL_MULTIPLIER 0
#define TIMEOUT_READ_TOTAL_CONSTANT 0
// 写超时为秒
#define TIMEOUT_WRITE_TOTAL_MULTIPLIER 0
#define TIMEOUT_WRITE_TOTAL_CONSTANT 5000
// 异步读取/写入操作时等待事件的超时时间
#define TIMEOUT_READCOMM_EVENT 4000
#define TIMEOUT_WRITECOMM_EVENT 2000
// 一些通讯协议使用的宏
#define FC_DTRDSR 0x01
#define FC_RTSCTS 0x02
#define FC_XONXOFF 0x04
#define ASSII_BEL 0x07
#define ASSII_BS 0x08
#define ASSII_LF 0x0A
#define ASSII_CR 0x0D
#define ASSII_XON 0x11
#define ASSII_XOFF 0x13
CSerialPort::CSerialPort(void) : m_hIDComDev(NULL), m_bOpened(false)
{
memset(&m_OverLappedRead, 0x00, sizeof(OVERLAPPED));
memset(&m_OverLappedWrite, 0x00, sizeof(OVERLAPPED));
}
CSerialPort::~CSerialPort(void)
{
Close();
}
// 打开串口
bool CSerialPort::Open(int nPort, int nBaud)
{
if (m_bOpened)
{
return true;
}
char szPort[50] = { 0 };
char szComParams[50] = { 0 };
DCB dcb;
sprintf_s(szPort, 50, "COM%d", nPort);
// API:建立文件,Windows中将串口设备当做文件对待
m_hIDComDev = CreateFile(
szPort,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 异步读写
NULL);
if (m_hIDComDev == NULL)
{
return false;
}
memset(&m_OverLappedRead, 0x00, sizeof(OVERLAPPED));
memset(&m_OverLappedWrite, 0x00, sizeof(OVERLAPPED));
// 设置超时
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = TIMEOUT_READ_INTERVAL;
CommTimeOuts.ReadTotalTimeoutMultiplier = TIMEOUT_READ_TOTAL_MULTIPLIER;
CommTimeOuts.ReadTotalTimeoutConstant = TIMEOUT_READ_TOTAL_CONSTANT;
CommTimeOuts.WriteTotalTimeoutMultiplier = TIMEOUT_WRITE_TOTAL_MULTIPLIER;
CommTimeOuts.WriteTotalTimeoutConstant = TIMEOUT_WRITE_TOTAL_CONSTANT;
SetCommTimeouts(m_hIDComDev, &CommTimeOuts);
sprintf_s(szComParams, 50, "COM%d:%d, n, 8, 1", nPort, nBaud);
// 设置异步读取/写入监视事件
m_OverLappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_OverLappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// 读取/设置串口设备参数
dcb.DCBlength = sizeof(DCB);
GetCommState(m_hIDComDev, &dcb);
dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
unsigned char ucSet;
ucSet = (unsigned char)((FC_RTSCTS & FC_DTRDSR) != 0);
ucSet = (unsigned char)((FC_RTSCTS & FC_RTSCTS) != 0);
ucSet = (unsigned char)((FC_RTSCTS & FC_XONXOFF) != 0);
if (!SetCommState(m_hIDComDev, &dcb)
|| !SetupComm(m_hIDComDev, BUFFER_INPUT_RECOMMENT, BUFFER_OUTPUT_RECOMMENT)
|| m_OverLappedRead.hEvent == NULL
|| m_OverLappedWrite.hEvent == NULL)
{
DWORD dwError = GetLastError();
if (m_OverLappedRead.hEvent != NULL)
{
CloseHandle(m_OverLappedRead.hEvent);
}
if(m_OverLappedWrite.hEvent != NULL)
{
CloseHandle(m_OverLappedWrite.hEvent);
}
CloseHandle(m_hIDComDev);
return false;
}
m_bOpened = true;
return m_bOpened;
}
// 关闭串口
bool CSerialPort::Close(void)
{
if (!m_bOpened || m_hIDComDev == NULL)
{
return true;
}
if (m_OverLappedRead.hEvent != NULL)
{
CloseHandle(m_OverLappedRead.hEvent);
}
if(m_OverLappedWrite.hEvent != NULL)
{
CloseHandle(m_OverLappedWrite.hEvent);
}
CloseHandle(m_hIDComDev);
m_bOpened = false;
m_hIDComDev = NULL;
return true;
}
// 向串口写数据,类内部使用
bool CSerialPort::WriteCommByte(unsigned char ucData)
{
BOOL bWriteStat;
DWORD dwBytesWritten;
bWriteStat = WriteFile(m_hIDComDev, (unsigned char*)&ucData, 1, &dwBytesWritten, &m_OverLappedWrite);
// 查询异步写入是否完成,未完成则挂起等待
if (!bWriteStat && (GetLastError() == ERROR_IO_PENDING))
{
if (WaitForSingleObject(m_OverLappedWrite.hEvent, TIMEOUT_WRITECOMM_EVENT))
{
dwBytesWritten = 0;
}
else
{
GetOverlappedResult(m_hIDComDev, &m_OverLappedWrite, &dwBytesWritten, false);
m_OverLappedWrite.Offset += dwBytesWritten;
}
}
return true;
}
// 向串口写数据
bool CSerialPort::WriteCommByte(unsigned char * pData, int nLen)
{
BOOL bWriteStat;
DWORD dwBytesWritten;
CLogFile::WriteLog(pData, nLen);
bWriteStat = WriteFile(m_hIDComDev, pData, nLen, &dwBytesWritten, &m_OverLappedWrite);
// 查询异步写入是否完成,未完成则挂起等待
if (!bWriteStat && (GetLastError() == ERROR_IO_PENDING))
{
if (WaitForSingleObject(m_OverLappedWrite.hEvent, TIMEOUT_WRITECOMM_EVENT))
{
dwBytesWritten = 0;
}
else
{
GetOverlappedResult(m_hIDComDev, &m_OverLappedWrite, &dwBytesWritten, false);
m_OverLappedWrite.Offset += dwBytesWritten;
}
}
return true;
}
// 查询接受缓冲区内是否有数据(只查询,不读取)
int CSerialPort::ReadDataWaiting(void)
{
if (!m_bOpened || m_hIDComDev == NULL)
{
return 0;
}
DWORD dwErrorFlags;
COMSTAT ComStat;
ClearCommError(m_hIDComDev, &dwErrorFlags, &ComStat);
return (int)ComStat.cbInQue;
}
// 读取来自串口的数据
int CSerialPort::ReadData(void* buffer, int limit)
{
if (!m_bOpened || m_hIDComDev == NULL)
{
return 0;
}
BOOL bReadStatus;
DWORD dwBytesRead, dwErrorFlags;
COMSTAT ComStat;
// 读取之前必须清楚错误信息
ClearCommError(m_hIDComDev, &dwErrorFlags, &ComStat);
if (!ComStat.cbInQue)
{
return 0;
}
dwBytesRead = (DWORD) ComStat.cbInQue;
if (limit < (int)dwBytesRead)
{
dwBytesRead = (DWORD)limit;
}
bReadStatus = ReadFile(m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverLappedRead);
// 查询异步读取是否完成,未完成则挂起等待
if (!bReadStatus)
{
if (GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_OverLappedRead.hEvent, TIMEOUT_READCOMM_EVENT);
return (int)dwBytesRead;
}
return 0;
}
DealReceiveData((unsigned char*)buffer, nCount);
return (int)nCount;
}
void CSerialPort::DealReceiveData(unsigned char* szData, int nLen)
{
// 处理数据
}
#include "SerialPort.h"
#include
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
CSerialPort SerialPort;
SerialPort.Open(6);
unsigned char szBuffer[MAX_PATH] = { 0 };
while (1)
{
int nLen = SerialPort.ReadData(szBuffer, MAX_PATH);
if (nLen)
{
for (int i = 0; i < nLen; i++)
{
printf("0x%02x ", szBuffer[i]);
}
printf("\n", szBuffer);
unsigned char* p = szBuffer;
do
{
unsigned short usCmdType = 0;
unsigned short usLen = 0;
memcpy(&usCmdType, p + 7, 2);
memcpy(&usLen, p + 4, 2);
printf("%04x\n", usCmdType);
switch(usCmdType)
{
case 0x000A:
{
unsigned char szData[] = { 0x00, 0x00, 0x0c, 0x00, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3};
SerialPort.WriteCommByte(szData, 12);
}
break;
case 0x0002:
{
unsigned char szData[] = { 0x00, 0x00, 0x0c, 0x00, 0x0d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb};
SerialPort.WriteCommByte(szData, 12);
}
break;
}
p += usLen + 4;
nLen -= usLen + 4;
} while (nLen);
memset(szBuffer, 0x00, MAX_PATH);
}
}
SerialPort.Close();
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD threadID;
HANDLE hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread); // 关闭内核对象
return 0;
}
该示例是之前一个项目的Demo程序,但是已经包含串口发送和接收数据了。