C++简单好用的串口读写操作类源码分享

9435 人浏览 | 时间: 2016-06-25 15:20:00 | 作者: codexia 会员文章,禁止转载

    通过封装,将串口读写的内部操作隐藏起来,使用此C++串口读写操作类,我们只需要打开串口、关闭串口,传入数据地址和数据长度写串口、提供缓冲区地址、缓冲大小和等待时间长度,就可以读取串口数据。使用非常简单。

    串口设备的读写,我们开发中可能会用到。而用C++来写,需要考虑很多细节,不能够快速上手开发。所以,基于本人开发的积累,将串口读写操作封装成一个简单的类,分享给大家使用。等熟悉了串口编程模式后,再看类的实现,来改进类。我们这里提供的类,并不是最好的类,但是使用一定是非常方便的。如果你发现了不足之处,请指正。

    我们今天的分享,是为了明天的开发效率更快。C++开发同样可以快速高效,只要我们将基础技术都总结分享出来,相信明天会更好。

/*
- 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);//读串口
};
/*
- 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;
}
     本文只提供一个好用的串口读写操作类,代码就不仔细说明了。代码中有简单的注释。本操作类不是最好的,有改进空间,有空再改进一下。如果你知道可以改进的地方,请提出来。
当前文章为会员文章,请前往[用户中心]开通会员后继续阅读。

相关阅读