C++实现跨平台串口通信代码

C++实现跨平台串口通信代码

串口通信在设备通信使用的还比较多,自己在几个项目都使用过,已经很稳定(哈哈,自吹一下)。

头文件serialport.h

//定义串口波特率
#define  SBR_0	     0
#define  SBR_50	     50
#define  SBR_75	     75
#define  SBR_110	 110
#define  SBR_134	 134
#define  SBR_150	 150
#define  SBR_200	 200
#define  SBR_300	 300
#define  SBR_600	 600
#define  SBR_1200	 1200
#define  SBR_1800	 1800
#define  SBR_2400	 2400
#define  SBR_4800	 4800
#define  SBR_9600	 9600
#define  SBR_19200	 19200
#define  SBR_38400	 38400

#define  SBR_OTHER   0010000
#define  SBR_57600   57600
#define  SBR_115200  115200 
#define  SBR_230400  230400
#define  SBR_460800  460800
#define  SBR_500000  500000
#define  SBR_576000  576000
#define  SBR_921600  921600
#define  SBR_1000000 1000000
#define  SBR_1152000 1152000
#define  SBR_1500000 1500000
#define  SBR_2000000 2000000
#define  SBR_2500000 2500000
#define  SBR_3000000 3000000
#define  SBR_3500000 3500000
#define  SBR_4000000 4000000

#define SEV_RXCHAR           0x0001  // Any Character received
#define SEV_RXFLAG           0x0002  // Received certain character
#define SEV_TXEMPTY          0x0004  // Transmitt Queue Empty
#define SEV_CTS              0x0008  // CTS changed state
#define SEV_DSR              0x0010  // DSR changed state
#define SEV_RLSD             0x0020  // RLSD changed state
#define SEV_BREAK            0x0040  // BREAK received
#define SEV_ERR              0x0080  // Line status error occurred
#define SEV_RING             0x0100  // Ring signal detected
#define SEV_PERR             0x0200  // Printer error occured
#define SEV_RX80FULL         0x0400  // Receive buffer is 80 percent full
#define SEV_EVENT1           0x0800  // Provider specific event 1
#define SEV_EVENT2           0x1000  // Provider specific event 2

typedef struct  SerialPortParam_Stru
{
	char         m_PortName[16];           //端口名
	SInt32       m_BaudRate;               //波特率
	SInt32       m_DataBit;                //数据位的个数,默认值为8个数据位
	char         m_Parity;                 //奇偶校验
	SInt32       m_StopBit;                //停止位
	UInt64       m_CommEvents;             //通信时间

	SerialPortParam_Stru()
	{
		memset(m_PortName, 0, sizeof(m_PortName));
		m_BaudRate   = 9600;
		m_DataBit    = 8;
		m_Parity     = 'N';
		m_StopBit    = 1;
		m_CommEvents = SEV_RXCHAR;
	}

	SerialPortParam_Stru(const SerialPortParam_Stru &other)
	{
		memcpy(m_PortName, other.m_PortName, sizeof(m_PortName));
		m_BaudRate   = other.m_BaudRate;
		m_DataBit    = other.m_DataBit;
		m_Parity     = other.m_Parity;
		m_StopBit    = other.m_StopBit;
		m_CommEvents = other.m_CommEvents;
	}

	SerialPortParam_Stru &operator= (const SerialPortParam_Stru &other)
	{
		if (this == &other)
		{
			return *this;
		}

		memcpy(m_PortName, other.m_PortName, sizeof(m_PortName));
		m_BaudRate   = other.m_BaudRate;
		m_DataBit    = other.m_DataBit;
		m_Parity     = other.m_Parity;
		m_StopBit    = other.m_StopBit;
		m_CommEvents = other.m_CommEvents;

		return *this;
	}
}SerialPortParam;
 
 
class LIBSGWUTIL_EXPORT CSerialPort
{  
public:  
    CSerialPort();

    ~CSerialPort();  
  
    /** 初始化串口函数 
    * 
    *  @param:  UINT portNo 串口编号,默认值为1,即COM1,注意,尽量不要大于9 
    *  @param:  UINT baud   波特率,默认为9600 
    *  @param:  char parity windows:是否进行奇偶校验,'Y'表示需要奇偶校验,'N'表示不需要奇偶校验 
	                        linux: O 奇校验  E 偶校验 N 表示不需要奇偶校验 
    *  @param:  UINT nBits 数据位的个数,默认值为8个数据位 
    *  @param:  UINT nStop 停止位使用格式,默认值为1 
    *  @param:  DWORD dwCommEvents 默认为EV_RXCHAR,即只要收发任意一个字符,则产生一个事件 
    *  @return: SInt32  初始化是否成功,0标示成功,非0标示失败,返回错误码
    *  @note:   在使用其他本类提供的函数前,请先调用本函数进行串口的初始化 
    *        /n本函数提供了一些常用的串口参数设置,若需要自行设置详细的DCB参数,可使用重载函数 
    *           /n本串口类析构时会自动关闭串口,无需额外执行关闭串口 
    *  @see: 
    */  
    SInt32 Open(const char *portname = "COM1", UInt32  baud = SBR_9600, UInt8  parity = 'N', 
				    UInt32 nBits = 8, UInt32 nStop = 1, UInt64 dwCommEvents = SEV_RXCHAR);  

	SInt32 Open(SerialPortParam seriaport);  

	/** 关闭串口
    * 
    * 
    *  @param:  
    *  @return: 
    *  @note: 
    *  @see: 
    */  
   void Close(); 

	/** 判断串口是否打开
    * 
    * 
    *  @param:  
    *  @return: 打开返回TRUE 关闭返回FALSE
    *  @note: 
    *  @see: 
    */  
    Bool IsOpen(const char *portname);  

    /** 向串口写数据 
    * 
    *  将缓冲区中的数据写入到串口 
    *  @param:  unsigned char * pData 指向需要写入串口的数据缓冲区 
    *  @param:  unsigned int length 需要写入的数据长度 
    *  @return: UInt32  返回写入的字节长度
    *  @note:   length不要大于pData所指向缓冲区的大小 
    *  @see: 
    */  
    UInt32 Write(UChar *pData, UInt32 length);  

	/** 读取串口接收缓冲区中len长度字节的数据 
    * 
    * 
    *  @param:  char & cRecved 存放读取数据的字符变量 
    *  @return: SInt32 返回读取字节数 
    *  @note: 
    *  @see: 
    */  
    SInt32 Read(UChar *cRecved, const SInt32 len); 
  
    /** 获取串口缓冲区中的字节数 
    * 
    * 
    *  @return: UInt32  操作是否成功 
    *  @note:   当串口缓冲区中无数据时,返回0 
    *  @see: 
    */  
    UInt32 GetBytesInCOM();  

    /** 获取打开串口参数
    * 
    * 
    *  @param:  char & cRecved 存放读取数据的字符变量 
    *  @return: 
    *  @note: 
    *  @see: 
    */  
	SerialPortParam GetSerialPortParam() {return m_SeriaPortParam;}
  
private:  
  
    /** 打开串口 
    * 
    * 
    *  @param:  UInt32 portNo 串口设备号 
    *  @return: SInt32  打开是否成功,0标示成功,非0失败 
    *  @note: 
    *  @see: 
    */  
    SInt32 OpenPort(const char *portname);  
  
    /** 关闭串口 
    * 
    * 
    *  @return: void  操作是否成功 
    *  @note: 
    *  @see: 
    */  
    void ClosePort();  

	/** 设置串口参数 
    * 
    * 
    *  @return: void  操作是否成功 
    *  @note: 
    *  @see: 
    */ 
	SInt32 SetComOpt(UInt32 nSpeed, UInt32 nBits, UInt8 parity, UInt32 nStop, UInt64 dwCommEvents);

	/** 获取波特率 
    * 
    * 
    *  @return: void  操作是否成功 
    *  @note: 
    *  @see: 
    */ 
	UInt32 GetBaudRate(UInt32 baud = SBR_9600);

private:  

#ifdef WIN32
	/** 串口句柄 */  
	HANDLE            m_hComm; 
#else
	//暂不实现
	SInt32            m_ComFd;
#endif

	SerialPortParam   m_SeriaPortParam;

	SInt32            m_WRErrTimes;  
};  

实现文件serialport.cpp

#include "serialport.h"

/* 
 * Decription for TIMEOUT_SEC(buflen,baud);
 * baud bits per second, buflen bytes to send.
 * buflen*32 (32 means sending an octect-bit data by use of the maxim bits 20)
 * eg. 9600bps baudrate, buflen=1024B, then TIMEOUT_SEC = 1024*32/9600+1 = 3 
 * don't change the two lines below unless you do know what you are doing.
*/
#define TIMEOUT_USEC(buflen,baud) ((buflen*32*1000000)/(baud*1000000)+50000)
/*******************************************************************************
*  Function   : CSerialPort
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/  
CSerialPort::CSerialPort()  
{ 
#ifdef WIN32
	/** 串口句柄 */  
	m_hComm = INVALID_HANDLE_VALUE;  
#else
	m_ComFd = -1;
#endif

	m_WRErrTimes = 0;
}  
/*******************************************************************************
*  Function   : ~CSerialPort
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/    
CSerialPort::~CSerialPort()  
{   
    Close();  

	m_WRErrTimes = 0;
}  
/*******************************************************************************
*  Function   : Open
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/  
SInt32 CSerialPort::Open(const char *portname, UInt32 baud, UInt8 parity, UInt32 nBits, 
	                         UInt32 nStop, UInt64 dwCommEvents)  
{  
   /** 打开指定串口,该函数内部已经有临界区保护,上面请不要加保护 */  
	SInt32 ret = OpenPort(portname);
   if ( ret != 0)  
   {  
	   LOG_WARN("open "<<portname<<" fail.ret:"<<ret);
       return -1;  
   }  

   //设置参数
   ret = SetComOpt(baud, nBits, parity, nStop, dwCommEvents);
   if ( ret != 0)  
   {  
	   LOG_WARN("set "<<portname<<" fail.ret:"<<ret);
	   return -2;  
   }  

   memcpy(m_SeriaPortParam.m_PortName, portname, strlen(portname));
   m_SeriaPortParam.m_BaudRate   = baud;
   m_SeriaPortParam.m_Parity     = parity;
   m_SeriaPortParam.m_DataBit    = nBits;
   m_SeriaPortParam.m_StopBit    = nStop;
   m_SeriaPortParam.m_CommEvents = dwCommEvents;

   m_WRErrTimes = 0;

   return 0;  
}
/*******************************************************************************
*  Function   : Open
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/  
SInt32 CSerialPort::Open(SerialPortParam seriaport)
{
	return Open(seriaport.m_PortName, seriaport.m_BaudRate, seriaport.m_Parity, 
		        seriaport.m_DataBit, seriaport.m_StopBit, seriaport.m_CommEvents);
}
/*******************************************************************************
*  Function   : Close
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/  
void CSerialPort::Close()
{
	return ClosePort();
}
/*******************************************************************************
*  Function   : IsOpen
*  Description: 判断串口是否打开
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 打开返回TRUE 关闭返回FALSE
*******************************************************************************/
Bool CSerialPort::IsOpen(const char *portname)
{  
	//读写错误次数大于10次就需要重新打开
	if (m_WRErrTimes > 10)
	{
		return FALSE;
	}
#ifdef WIN32

	/** 打开指定的串口 */  
	HANDLE hComm = CreateFileA(portname,  /** 设备名,COM1,COM2等 */  
		GENERIC_READ|GENERIC_WRITE, /** 访问模式,可同时读写 */  
		0,                            /** 共享模式,0表示不共享 */  
		NULL,                         /** 安全性设置,一般使用NULL */  
		OPEN_EXISTING,                /** 该参数表示设备必须存在,否则创建失败 */  
		0,  
		0);  

	//打开失败,并且错误码是拒绝访问,表示串口已经打开
	if (ERROR_ACCESS_DENIED == OS::ErrorNo())  
	{    
		return TRUE;  
	} 
	else
	{
		if (hComm != INVALID_HANDLE_VALUE)
		{
			CloseHandle(hComm);  
			hComm = INVALID_HANDLE_VALUE;  
		}

		return FALSE;
	}
#else
	SInt32 ComFd = open(portname, O_RDWR|O_NOCTTY|O_NDELAY);  
	if (-1 == ComFd)  
	{  
		printf("Can't Open Serial Port.%d\n", OS::ErrorNo());
		return TRUE;  
	}  
	else
	{
		close(ComFd);
		ComFd = -1;
		return FALSE;
	}
#endif
}
/*******************************************************************************
*  Function   : ClosePort
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/
void CSerialPort::ClosePort()  
{  
#ifdef WIN32
	/** 如果有串口被打开,关闭它 */  
	if (m_hComm != INVALID_HANDLE_VALUE)  
	{  
		CloseHandle(m_hComm);  
		m_hComm = INVALID_HANDLE_VALUE;  
	}
#else
	//暂不实现
	if (m_ComFd != -1)
	{
		close(m_ComFd);
		m_ComFd = -1;
	}
#endif

	return;
}  
/*******************************************************************************
*  Function   : OpenPort
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/  
SInt32 CSerialPort::OpenPort(const char *portname)  
{  
	SInt32 ret = 0;
#ifdef WIN32
	if (m_hComm != INVALID_HANDLE_VALUE)
	{
		return -1;
	}

	/** 打开指定的串口 */  
	m_hComm = CreateFileA(portname,  /** 设备名,COM1,COM2等 */  
		GENERIC_READ|GENERIC_WRITE, /** 访问模式,可同时读写 */  
		0,                            /** 共享模式,0表示不共享 */  
		NULL,                         /** 安全性设置,一般使用NULL */  
		OPEN_EXISTING,                /** 该参数表示设备必须存在,否则创建失败 */  
		0,  
		0);  

	/** 如果打开失败,释放资源并返回 */  
	if (m_hComm == INVALID_HANDLE_VALUE)  
	{   
		LOG_WARN("Can't Open Serial Port."<<OS::ErrorNo());  
		ret = -2;  
	} 

#else
	if (m_ComFd != -1)
	{
		return -1;
	}

	m_ComFd = open(portname, O_RDWR|O_NOCTTY|O_NDELAY);  
	if (-1 == m_ComFd)  
	{  
		printf("Can't Open Serial Port.%d\n", OS::ErrorNo());
		return -2;  
	}  

	ret = fcntl(m_ComFd, F_SETFL, 0);
	if (ret == -1)  
	{  
		LOG_WARN("fcntl failed!");  
		ret = -2;
	}  
	else  
	{  
		//printf("fcntl=%d\n", ret);  

		设置串口
		//if (isatty(STDIN_FILENO) == 0)  
		//{  
		//	LOG_WARN("standard input is not a terminal device."<<OS::ErrorNo());  
		//}  
	}  
#endif
  
    return ret;  
}     
/*******************************************************************************
*  Function   : ReadChar
*  Description: 读取串口接收缓冲区中len长度字节的数据
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/ 
SInt32 CSerialPort::Read(UChar *cRecved, const SInt32 len)
{
#ifdef WIN32 
	if (m_hComm == INVALID_HANDLE_VALUE || cRecved == NULL || len <= 0)  
	{  
		m_WRErrTimes++;
		return -1;  
	}  

	//从缓冲区读取一个字节的数据
	DWORD BytesRead = 0; 
	BOOL  bResult = ReadFile(m_hComm, cRecved, len, &BytesRead, NULL);  
	if ((!bResult))  
	{  
		/** 获取错误码,可以根据该错误码查出错误原因 */
		LOG_WARN("Read com fail."<<OS::ErrorNo());

		/** 清空串口缓冲区 */  
		PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_RXABORT); 

		m_WRErrTimes++;
		return -2;  
	} 
	else
	{
		if (m_WRErrTimes != 0)
		{
			m_WRErrTimes = 0;
		}
	}

	return BytesRead;  
#else//linux
	if (m_ComFd == -1 || cRecved == NULL || len <= 0)  
	{  
		m_WRErrTimes++;
		return -1;  
	}  

	struct timeval tv_timeout;
	fd_set fdread;
	FD_ZERO (&fdread);
	FD_SET (m_ComFd, &fdread);
	SInt32 timeout = TIMEOUT_USEC(len, m_SeriaPortParam.m_BaudRate);
	tv_timeout.tv_sec = timeout/1000000;
	tv_timeout.tv_usec = timeout%1000000;
	SInt32 ret = select(m_ComFd+1, &fdread, NULL, NULL, &tv_timeout);
	if (ret > 0)
	{
		//读取数据
		ret = read(m_ComFd, cRecved, len); 
	}
	else
	{
		if (ret < 0) 
		{
			ret = -2;
		}
	}

	//判断错误码
	if (ret < 0)
	{
		//获取错误码,可以根据该错误码查出错误原因 
		LOG_WARN("Read com fail."<<OS::ErrorNo());
#ifdef DEBUG
		printf("Read com fail.ret:%d:%d\n",ret, OS::ErrorNo());
#endif
		m_WRErrTimes++;

		//清掉串口缓存 
		tcflush(m_ComFd, TCIOFLUSH); 
	}
	else
	{
		if (m_WRErrTimes != 0)
		{
			m_WRErrTimes = 0;
		}
	}

	return ret; 
#endif
}
/*******************************************************************************
*  Function   : Write
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/
UInt32 CSerialPort::Write(UChar *pData, UInt32 length)  
{  
#ifdef WIN32  
    if (m_hComm == INVALID_HANDLE_VALUE || pData == NULL || length <= 0)  
    {  
		m_WRErrTimes++;
        return -1;  
    }  

	//清空串口缓冲区  
	PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_RXABORT);  

    //向缓冲区写入指定量的数据
	DWORD  BytesToSend = 0; 
    BOOL bResult = WriteFile(m_hComm, pData, length, &BytesToSend, NULL);  
    if (!bResult)  
    {  
		//获取错误码,可以根据该错误码查出错误原因 
		LOG_WARN("write com fail."<<OS::ErrorNo());

		m_WRErrTimes++;

        //清空串口缓冲区  
        PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_RXABORT);  

		return -2;
    }
	else
	{
		if (m_WRErrTimes != 0)
		{
			m_WRErrTimes = 0;
		}
	}
  
    return BytesToSend; 
#else
	if (m_ComFd == -1 || pData == NULL || length <= 0)  
	{ 
		m_WRErrTimes++;
		return -1;  
	}  

	//清掉串口缓存 
	tcflush(m_ComFd, TCIOFLUSH); 

	struct timeval tv_timeout;
	fd_set fdwrite;
	FD_ZERO(&fdwrite);
	FD_SET(m_ComFd, &fdwrite);

	SInt32 timeout = TIMEOUT_USEC(length, m_SeriaPortParam.m_BaudRate);
	tv_timeout.tv_sec = timeout/1000000;
	tv_timeout.tv_usec = timeout%1000000;
	SInt32 totallen = 0;
	while(totallen < length)
	{
		//等待写数据
		SInt32 ret = select(m_ComFd+1, NULL, &fdwrite, NULL, &tv_timeout);
		if (ret > 0)
		{
			ret = write(m_ComFd, pData+totallen, length-totallen);
			if (ret > 0) 
			{
				totallen += ret;
				if (m_WRErrTimes != 0)
				{
					m_WRErrTimes = 0;
				}
			}
			else
			{
				if (ret < 0)
				{
					ret = -2;
				}
			}
		}
		else
		{
			ret = -3;
		}

		if (ret < 0)
		{
			LOG_WARN("Write com fail."<<OS::ErrorNo());
#ifdef DEBUG
			printf("Write com fail.ret:%d:%d\n",ret, OS::ErrorNo());
#endif
			m_WRErrTimes++;

			//清掉串口缓存 
			tcflush(m_ComFd, TCIOFLUSH); 
			break;
		}
	}

	return totallen; 
#endif
}  
/*******************************************************************************
*  Function   : GetBytesInCOM
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/ 
UInt32 CSerialPort::GetBytesInCOM()  
{
	UInt32 BytesInQue = 0; 
#ifdef WIN32
	DWORD dwError = 0;  /** 错误码 */  
	COMSTAT  comstat;   /** COMSTAT结构体,记录通信设备的状态信息 */  
	memset(&comstat, 0, sizeof(COMSTAT));  

	/** 在调用ReadFile和WriteFile之前,通过本函数清除以前遗留的错误标志 */  
	if (ClearCommError(m_hComm, &dwError, &comstat))  
	{  
		BytesInQue = comstat.cbInQue; /** 获取在输入缓冲区中的字节数 */  
	}  
#else
	int retval;  
	fd_set rfds;  
	struct timeval tv;  
	int ret, pos;  
	tv.tv_sec = 0;  //set the rcv wait time    
	tv.tv_usec = 100000;  //100000us = 0.1s   

	FD_ZERO(&rfds);  
	FD_SET(m_ComFd, &rfds);  
	retval = select(m_ComFd + 1, &rfds, NULL, NULL, &tv);  
	if (retval == -1)  
	{
		return 0;
	}

	//于是里面有数据
	BytesInQue = 1;

#endif

	return BytesInQue;  
}  
/*******************************************************************************
*  Function   : SetComOpt
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/
SInt32 CSerialPort::SetComOpt(UInt32 nSpeed, UInt32 nBits, UInt8 parity, UInt32 nStop, 
							  UInt64 dwCommEvents)
{
	SInt32 ret = 0;
#ifdef WIN32  
	/** 临时变量,将制定参数转化为字符串形式,以构造DCB结构 */  
	char szDCBparam[50]= {0};  
	sprintf(szDCBparam, "baud=%d parity=%c data=%d stop=%d", nSpeed, parity, nBits, nStop);  

    /** 是否有错误发生 */  
    BOOL bIsSuccess = TRUE;  
  
    /** 在此可以设置输入输出的缓冲区大小,如果不设置,则系统会设置默认值. 
    *  自己设置缓冲区大小时,要注意设置稍大一些,避免缓冲区溢出 
    */  
    /*if (bIsSuccess ) 
    { 
		bIsSuccess = SetupComm(m_hComm,10,10); 
    }*/  
  
    /** 设置串口的超时时间,均设为0,表示不使用超时限制 */  
    COMMTIMEOUTS  CommTimeouts;  
    CommTimeouts.ReadIntervalTimeout = 1;  
    CommTimeouts.ReadTotalTimeoutMultiplier = 0;  
    CommTimeouts.ReadTotalTimeoutConstant = 40;  
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;  
    CommTimeouts.WriteTotalTimeoutConstant = 0;  
    if (bIsSuccess)  
    {  
        bIsSuccess = SetCommTimeouts(m_hComm, &CommTimeouts); 
		if (!bIsSuccess)
		{
			ret = -2;
		}
    }  
  
    DCB  dcb;  
    if (bIsSuccess)  
    {  
        // 将ANSI字符串转换为UNICODE字符串    
        DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, szDCBparam, -1, NULL, 0);  
        wchar_t *pwText = new wchar_t[dwNum];  
        if (!MultiByteToWideChar(CP_ACP, 0, szDCBparam, -1, pwText, dwNum))  
        {  
            bIsSuccess = TRUE;  
        }  
  
        /** 获取当前串口配置参数,并且构造串口DCB参数 */  
        bIsSuccess = GetCommState(m_hComm, &dcb);
		if (bIsSuccess)
		{
			bIsSuccess = BuildCommDCBW(pwText, &dcb); 
		}
		if (!bIsSuccess)
		{
			ret = OS::ErrorNo();
			ret = -3;
		}

        /** 开启RTS flow控制 */  
        dcb.fRtsControl = RTS_CONTROL_ENABLE;  
  
        /** 释放内存空间 */  
        delete[] pwText;  
    }  
  
    if (bIsSuccess)  
    {  
        /** 使用DCB参数配置串口状态 */  
        bIsSuccess = SetCommState(m_hComm, &dcb);  
		if (!bIsSuccess)
		{
			ret = -4;
		}
    }  
  
    /**  清空串口缓冲区 */  
    PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);  
	return ret;
#else
	struct termios newoptions, oldoptions;  
	if (tcgetattr(m_ComFd, &oldoptions) != 0)  
	{  
		return -1;  
	}  

	bzero(&newoptions, sizeof(newoptions));  
	newoptions.c_cflag |= CLOCAL | CREAD;  
	newoptions.c_cflag &= ~CSIZE;  

	switch (nBits)  
	{  
	case 7:  
		newoptions.c_cflag |= CS7;  
		break;  
	case 8:  
		newoptions.c_cflag |= CS8;  
		break;  
	}  

	switch (parity)  
	{  
	case 'n': //无校验 
	case 'N':                    
		newoptions.c_cflag &= ~PARENB;  
		newoptions.c_iflag &= ~INPCK;
		break; 
	case 'o'://奇校验
	case 'O':                       
		newoptions.c_cflag |= (PARENB | PARODD);   
		newoptions.c_iflag |= (INPCK | ISTRIP);  
		break; 
	case 'e'://偶校验 
	case 'E':                      
		newoptions.c_cflag |= PARENB;  
		newoptions.c_cflag &= ~PARODD; 
		newoptions.c_iflag |= (INPCK | ISTRIP);  
		break;
	case 's':
	case 'S':
		newoptions.c_cflag &= ~PARENB;
		newoptions.c_cflag &= ~CSTOPB;
		break;
 
	}  

	//设置波特率
	cfsetispeed(&newoptions, GetBaudRate(nSpeed));  
	cfsetospeed(&newoptions, GetBaudRate(nSpeed));  

	//设置停止位
	switch (nStop)
	{
	case 1:
		newoptions.c_cflag &= ~CSTOPB;
		break;

	case 2:
		newoptions.c_cflag |= CSTOPB;
		break;
	default:
		newoptions.c_cflag &= ~CSTOPB;
	}
  
	newoptions.c_cc[VTIME] = 0;  
	newoptions.c_cc[VMIN] = 0;  
	tcflush(m_ComFd, TCIFLUSH);  
	if ((tcsetattr(m_ComFd, TCSANOW, &newoptions)) != 0)  
	{  
		return -1;  
	}  
	return 0;  
#endif
}
/*******************************************************************************
*  Function   : SetComOpt
*  Description: 
*  Calls      : 见函数实现
*  Called By  : 
*  Input      : 无
*  Output     : 无
*  Return     : 
*******************************************************************************/
UInt32 CSerialPort::GetBaudRate(UInt32 baud)
{
#ifdef WIN32  
	return baud;
#else
	switch(baud)
	{
	case SBR_50:
		return B50;
	case SBR_75:
		return B75;
	case SBR_110:
		return B110;
	case SBR_134:
		return B134;
	case SBR_150:
		return B150;
	case SBR_200:
		return B200;
	case SBR_300:
		return B300;
	case SBR_600:
		return B600;
	case SBR_1200:
		return B1200;
	case SBR_1800:
		return B1800;
	case SBR_2400:
		return B2400;
	case SBR_4800:
		return B4800;
	case SBR_9600:
		return B9600;
	case SBR_19200:
		return B19200;
	case SBR_38400: 
		return B38400;
	case SBR_57600:
		return B57600;
	case SBR_115200:
		return B115200;
	case SBR_230400:
		return B230400;
	case SBR_460800:
		return B460800;
	case SBR_500000:
		return B500000;
	case SBR_576000:
		return B576000;
	case SBR_921600:
		return B921600;
	case SBR_1000000:
		return B1000000;
	case SBR_1152000:
		return B1152000;
	case SBR_1500000:
		return B1500000;
	case SBR_2000000:
		return B2000000;
	case SBR_2500000:
		return B2500000;
	case SBR_3000000:
		return B3000000;
	case SBR_3500000:
		return B3500000;
	case SBR_4000000:
		return B4000000;
	default:
		return B0;
	}

#endif
}



  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

匠心码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值