Visual C++下超简单串口类

2018-02-05 10:37:48来源:oschina作者:arlen7772gg人点击

分享
1 概述

简单易用,使我们编写的软件代码能够在时间长久之后,仍然能够一眼就明白其中的含义和使用过程,因此,简单易用是我们编写软件的目标。反之,如果你写的代码复杂晦涩难懂,就算功能是正常的,但是交由第三方使用的时候的,第三方回感到无比的痛苦,那种感受谁用谁知道。


本着简单易懂的原则,编写了WIN32下的C++串口类,并提供的了简单使用实例,该类能够满足没有特殊要求的用户使用。


2 超简单串口类介绍

该类对接收串口数据,采用一个单独的线程对接收串口数据进行了封装,当然也保留了最原始的接收数据方法,使用者可以自己编写接收串口数据方法。


类中用到的枚举常量:


///

流控制标志


enum EComPortHandshake


{


None = 0,


Software = 1,


Hardware = 2


};

///

奇偶检验位标志


enum EComPortParity


{


NoParity = 0, // No parity (default)


OddParity = 1,// Odd parity


EvenParity = 2, // Even parity


MarkParity = 3, // Mark parity


SpaceParity = 4 // Space parity


};

///

停止位标志


enum EComPortStopBits


{


OneStopBits = 0, // 1 stopbit (default)


One5StopBits = 1, // 1.5 stopbit


TwoStopBits = 2 // 2 stopbits


};

///

事件掩码标志


enum EComPortEvtMask {


EV_RXCHAR_ = 0x0001, // Any Character received


EV_RXFLAG_ = 0x0002, // Received certain character


EV_TXEMPTY_ = 0x0004, // Transmitt Queue Empty


EV_CTS_ = 0x0008, // CTS changed state


EV_DSR_ = 0x0010, // DSR changed state


EV_RLSD_ = 0x0020, // RLSD changed state


EV_BREAK_ = 0x0040, // BREAK received


EV_ERR_ = 0x0080, // Line status error occurred


EV_RING_ = 0x0100, // Ring signal detected


EV_PERR_ = 0x0200, // Printer error occured


EV_RX80FULL_ = 0x0400, // Receive buffer is 80 percent full


EV_EVENT1_ = 0x0800, // Provider specific event 1


EV_EVENT2_ = 0x1000 // Provider specific event 2


};

///

串口清理标志


enum EComPortPurgeFlags {


PURGE_TXABORT_ = 0x0001, // Kill the pending/current writes to the comm port.


PURGE_RXABORT_ = 0x0002, // Kill the pending/current reads to the comm port.


PURGE_TXCLEAR_ = 0x0004, // Kill the transmit queue if there.


PURGE_RXCLEAR_ = 0x0008 // Kill the typeahead buffer if there.


};

enum EComPortBaudRate {


CBR_110_ = 110,


CBR_300_ = 300,


CBR_600_ = 600,


CBR_1200_ = 1200,


CBR_2400_ = 2400,


CBR_4800_ = 4800,


CBR_9600_ = 9600,


CBR_14400_ = 14400,


CBR_19200_ = 19200,


CBR_38400_ = 38400,


CBR_56000_ = 56000,


CBR_57600_ = 57600,


CBR_115200_ = 115200,


CBR_128000_ = 128000,


CBR_256000_ = 256000


};


串口类的接口形式如下:


class IAsyncComPort


{


public:


IAsyncComPort() {}

///


/// 打开串口


///


/// 串口号


/// 波特率


/// 数据位, Number of bits/byte, 4-8


/// 奇偶校验, 0-4=None,Odd,Even,Mark,Space


/// 停止位, 0,1,2 -- 1, 1.5, 2


/// 流控制, 0-无, 1-软件, 2-硬件


/// 0-正常, 其它-错误代码


virtual unsigned long Open(unsigned short portNum, EComPortBaudRate baudRate, unsigned char dataBits, EComPortParity parity, EComPortStopBits stopBits, EComPortHandshake handshake = EComPortHandshake::None) = 0;

virtual void SetComPortReceiveOneCharCallbackFunc(std::function func) = 0;

virtual void SetComPortReceiveFullOneMsgCallbackFunc(std::function func) = 0;

///


/// 设置波特率


///


/// 波特率


/// 0-正常, 其它-错误代码


virtual unsigned long SetBaudRate(unsigned long baudRate) = 0;

///


/// 设置停止位


///


/// 停止位, 0,1,2 = 1, 1.5, 2


/// 0-正常, 其它-错误代码


virtual unsigned long SetStopBits(EComPortStopBits stopBits) = 0;

///


/// 设置数据位


///


/// 数据位, 4-8


/// 0-正常, 其它-错误代码


virtual unsigned long SetDataBits(unsigned char dataBits) = 0;

///


/// 设置奇偶校验


///


/// 奇偶校验, 0-4=None,Odd,Even,Mark,Space


/// 0-正常, 其它-错误代码


virtual unsigned long SetParity(EComPortParity parity) = 0;

///


/// 设置流控制


///


/// 流控制, 0-无, 1-软件, 2-硬件


/// 0-正常, 其它-错误代码


virtual unsigned long SetHandShake(EComPortHandshake handshake) = 0;

///


/// 向串口写入数据


///


/// 要写入的字节数组


/// 返回值, true Or false


virtual bool Write(unsigned char *pBuffer, long bufferLen) = 0;

///


/// 向串口写入1个字节


///


/// 要写入的字节


/// 返回值, true Or false


virtual bool Write(unsigned char data) = 0;

///


/// 从串口读出数据


///


/// 用于存放数据的缓冲数组


/// 从穿口中读取到的字节数


/// 返回值, TRUE Or FALSE


virtual bool Read(unsigned char *pBuffer, long bufferLen, unsigned long *pNumberOfBytesRead) = 0;

///


/// 从串口读出1个字节的数据


///


/// 用于存放数据的缓冲数组


/// 返回值, TRUE Or FALSE


virtual bool Read(unsigned char *pBuffer) = 0;

///


/// 关闭串口


///


virtual void Close() = 0;

///


/// 设置串口掩码


///


/// 掩码值


/// 返回值, TRUE Or FALSE


virtual bool SetPortMask(EComPortEvtMask dwEvtMask) = 0;

///


/// 获取或设置接收线程的是否启动或已经启动


///


virtual void EnableReceiveThread(bool bEnable) = 0;

///


/// 设置消息的长度(字节数), 同步头信息.(如果 msgLen小于0 且syncHeader为null, 则默认50个字节为一条消息.syncHeader=null, 则认为没有同步头)


///


/// 一条完整消息的长度, 字节数(含同步头数组的字节数)


/// 同步头字节数组


virtual bool SetRecvMsgLengthAndSyncHeader(long msgLen, unsigned char *pSyncHeader, long syncHeaderLen) = 0;

virtual unsigned short GetPortNum() const = 0;

virtual unsigned long GetBaudRate() const = 0;


virtual unsigned char GetDataBits() const = 0;


virtual unsigned char GetParity() const = 0;


virtual unsigned char GetStopBits() const = 0;


virtual unsigned long GetHandShake() const = 0;

virtual void Release() = 0;

public:


virtual ~IAsyncComPort() { OutputDebugString(_T("~IAsyncComPort Destructor./n")); }


};

#if defined(__cplusplus)


extern "C"


{


#endif

IAsyncComPort *CreateAsyncComPortObject();


void ReleaseAsyncComPortObject(IAsyncComPort **p);

#if defined(__cplusplus)


}


#endif


其中CreateAsyncComPortObject用于创建串口类对象的指针,而ReleaseAsyncComPortObject则用于释放串口类的指针。


也可以stl中的智能指针对指针对象进行管理。


3 串口类的特点

该串口类的一个非常大的特点:简单易用。采用异步读写的方式,接收串口数据采用单独一个线程进行封装,可以让该类自动完成同步头的对比,当接收到1条完整的消息后,调用回调函数通知用户;也可以设置回调函数,自己完成同步头和校验和的对比工作。


其使用步骤如下:


IAsyncComPort *port = CreateAsyncComPortObject();


port->SetRecvMsgLengthAndSyncHeader(4, nullptr, 0);


port->SetComPortReceiveFullOneMsgCallbackFunc( … );


port->Open(…);


然后就可以在循环中发送数据,在设置的回调函数中处理接收到的串口数据。


在软件退出时,调用如下过程:


port->EnableReceiveThread(false);


ReleaseAsyncComPortObject(&port); // 如果采用了智能指针管理该指针,则可以不用调用该函数。


4 使用实例

下面时使用实例中的主要代码段(详细过多,就不粘贴了):



生成指针对象,并由智能指针管理。



初始化,设置接收消息的回调函数,打开串口,开始工作。



退出软件时,关闭接收串口数据的线程,完成串口资源的清理工作。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台