通过封装,将串口读写的内部操作隐藏起来,使用此C++串口读写操作类,我们只需要打开串口、关闭串口,传入数据地址和数据长度写串口、提供缓冲区地址、缓冲大小和等待时间长度,就可以读取串口数据。使用非常简单。
串口设备的读写,我们开发中可能会用到。而用C++来写,需要考虑很多细节,不能够快速上手开发。所以,基于本人开发的积累,将串口读写操作封装成一个简单的类,分享给大家使用。等熟悉了串口编程模式后,再看类的实现,来改进类。我们这里提供的类,并不是最好的类,但是使用一定是非常方便的。如果你发现了不足之处,请指正。
我们今天的分享,是为了明天的开发效率更快。C++开发同样可以快速高效,只要我们将基础技术都总结分享出来,相信明天会更好。
头文件ComAccess.h:
/*
- C++技术网(http://www.cjjjs.com) 版权所有
- 作者:codexia
- 时间:2016年6月25日
- 类别:串口操作类
- 功能描述:封装好了基础的操作:打开串口、关闭串口、读串口和写串口
*/
#pragma once
#include <windows.h>
class ComAccess
{
private:
HANDLE m_hCom; //串口通信设备句柄
OVERLAPPED m_ov; //异步IO结构体,记录着输入输出需要的信息
public:
ComAccess();
ComAccess(LPCTSTR lpszPortNum);
~ComAccess() { Close(); }
//打开串口
BOOL Open(LPCTSTR lpszPortNum,DWORD dwBaudRate = CBR_9600,BYTE byParity = NOPARITY,BYTE byStopBits = ONESTOPBIT,BYTE byByteSize = 8);
VOID Close(VOID);//关闭串口
DWORD WriteData(LPCVOID pdata, DWORD len);//写串口
DWORD ReadData(LPVOID pdest, DWORD len, DWORD dwMaxWait = 500);//读串口
};
源文件ComAccess.cpp:
/*
- C++技术网(http://www.cjjjs.com) 版权所有
- 作者:codexia
- 时间:2016年6月25日
- 类别:串口操作类
- 功能描述:封装好了基础的操作:打开串口、关闭串口、读串口和写串口
*/
#include "StdAfx.h"
#include "ComAccess.h"
#include <assert.h>
ComAccess::ComAccess()
{
m_hCom = 0;
ZeroMemory(&m_ov, sizeof(m_ov));
}
ComAccess::ComAccess(LPCTSTR lpszPortNum)
{
ComAccess::ComAccess();
ComAccess::Open(lpszPortNum);
}
BOOL ComAccess::Open(LPCTSTR lpszPortNum, DWORD dwBaudRate,BYTE byParity,BYTE byStopBits,BYTE byByteSize)
{
DCB dcb; // 串口通信设备控制参数结构体
BOOL bSuccess;
m_hCom = CreateFile(lpszPortNum,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
if ( m_hCom == INVALID_HANDLE_VALUE )
{
return FALSE;
}
bSuccess = GetCommState(m_hCom, &dcb);
if ( ! bSuccess )
{
ComAccess::Close();
return FALSE;
}
dcb.BaudRate = dwBaudRate;//波特率,默认9600
dcb.ByteSize = byByteSize;//数据位,默认8
dcb.Parity = byParity; //校验位,默认无
dcb.StopBits = byStopBits;//停止位,默认1
bSuccess = SetCommState(m_hCom, &dcb);
if ( ! bSuccess )
{
ComAccess::Close();
return FALSE;
}
SetupComm(m_hCom,6000,6000) ;
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/9600 ;
CommTimeOuts.WriteTotalTimeoutConstant = 0 ;
SetCommTimeouts(m_hCom, &CommTimeOuts ) ;
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
EscapeCommFunction(m_hCom, SETDTR ) ;
return TRUE;
}
VOID ComAccess::Close(VOID)
{
if ( m_hCom > 0 )
{
CloseHandle(m_hCom);
}
m_hCom = 0;
}
DWORD ComAccess::WriteData(LPCVOID pdata,DWORD len)
{
BOOL bSuccess;
DWORD written = 0;
if ( len < 1 )return(0);
m_ov.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
if ( m_ov.hEvent == INVALID_HANDLE_VALUE )
{
return(-1);
}
WriteFile(m_hCom,pdata,len,&written,&m_ov);
bSuccess = GetOverlappedResult(m_hCom, &m_ov, &written, TRUE);
if ( ! bSuccess )
{
CloseHandle(m_ov.hEvent);
return(-1);
}
CloseHandle(m_ov.hEvent);
return written;
}
DWORD ComAccess::ReadData(LPVOID pdest,DWORD len,DWORD dwMaxWait)
{
BOOL bSuccess;
DWORD result = 0;
DWORD read = 0; // 读取的字节数
DWORD mask = 0; // 指示发生的事件类型
if ( len < 1 ) return(0);
//创建异步IO
m_ov.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
if ( m_ov.hEvent == INVALID_HANDLE_VALUE )
{
return(-1);
}
//设置监听的事件
bSuccess = SetCommMask(m_hCom, EV_RXCHAR );
if ( ! bSuccess )
{
CloseHandle(m_ov.hEvent);
return(-1);
}
bSuccess = WaitCommEvent(m_hCom, &mask, &m_ov);
if ( ! bSuccess )
{
//事件没有触发,判断异步完成没有
int err = GetLastError();
if ( err == ERROR_IO_PENDING)
{
result = WaitForSingleObject(m_ov.hEvent, dwMaxWait); //wait dwMaxWait milli seconds before returning
if ( result == WAIT_FAILED )
{
CloseHandle(m_ov.hEvent);
return(-1);
}else
{
if (mask & EV_RXCHAR)
{
Sleep(100);//第一个字符事件触发,但是所有的数据还没有完全到来。一般30ms内能够读完普通的数据量,如果数据量很大,则需要设置更多时间
ReadFile(m_hCom,pdest,len,&read,&m_ov);
}
bSuccess = GetOverlappedResult(m_hCom, &m_ov, &read, TRUE);
if ( ! bSuccess )
{
CloseHandle(m_ov.hEvent);
return(-1);
}
}
}
}
else
{
//事件触发
assert(mask!=0);
ReadFile(m_hCom,pdest,len,&read,&m_ov);
bSuccess = GetOverlappedResult(m_hCom, &m_ov, &read, TRUE);
if ( ! bSuccess )
{
CloseHandle(m_ov.hEvent);
return(-1);
}
}
CloseHandle(m_ov.hEvent);
return read;
}
本文只提供一个好用的串口读写操作类,代码就不仔细说明了。代码中有简单的注释。本操作类不是最好的,有改进空间,有空再改进一下。如果你知道可以改进的地方,请提出来。