介绍一个简单的串口类,同一时间只能读或写

介绍一个简单的串口类,同一时间只能读或写,但这个类比较简单,不必每次都要使用P.J和龚建伟等的串口类,这个类没有开启线程,就是一个简单的串口操作类。

先看下头文件的声明,主要就几个函数,打开串口,读写串口数据,关闭串口与确认串口状态

#pragma once

#ifndef _PC_SERIAL_H__
#define _PC_SERIAL_H__
class	CSerial:public CObject
{
public:
	CSerial();
	virtual	~CSerial();
	BOOL	OpenComm(int nPort,LONG32	nPaud,char parity = 'N',
		DWORD dwCommEvents = EV_RXCHAR,UINT databits = 8, UINT stopbits = 1);
	BOOL	IsOpen();
	void	CloseComm();
	int		WriteComm(BYTE ch,int delay);
	int		WriteCommData(BYTE*	buff,int	len,int delay = 1,int flag = 0);
	int		ReadCommData(BYTE*	buff,int len,int timeout);
	int		ReadCommData(int  timeout);

	int		m_nPort;
	int		m_nPaud;
private:
	//int		m_hComm;
	HANDLE	m_hComm;
};
#endif
接下来看具体的实现,首先是构造析构函数
CSerial::CSerial()
{
	m_hComm	= INVALID_HANDLE_VALUE;
}

CSerial::~CSerial()
{
	CloseComm();
}
接下来是打开串口函数,这里有默认的串口设置
BOOL	CSerial::OpenComm(int nPort,LONG32 nPaud,char parity /* =  */, 
						  DWORD dwCommEvents /* = EV_RXCHAR */,UINT databits /* = 8 */, UINT stopbits /* = 1 */)
{
	COMMTIMEOUTS	tous;
	DCB		dcb;
	CString		strComm;
	memset(&tous,0,sizeof(tous));
	tous.ReadIntervalTimeout = MAXWORD;
	//在串口号大于10时,需要修改其字符串形式
	if (nPort >=10)
	{
		strComm.Format(_T("\\\\.\\%d"),nPort);
	}
	else
		strComm.Format(_T("COM%d"),nPort);
	m_hComm = CreateFile(strComm,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
	if (m_hComm!=INVALID_HANDLE_VALUE)
	{
		GetCommState(m_hComm,&dcb);
		dcb.BaudRate = nPaud;
		dcb.Parity = parity;
		dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = 0;
		dcb.fOutX = dcb.fInX = 0;
		dcb.fRtsControl = RTS_CONTROL_ENABLE;
		dcb.fDtrControl = DTR_CONTROL_ENABLE;

		dcb.ByteSize = databits;
		dcb.StopBits = stopbits;

		SetCommState(m_hComm,&dcb);
		SetupComm(m_hComm,4096,4096);	//串口缓冲区大小设置,InQueue与OutQueue均为4k
		SetCommTimeouts(m_hComm,&tous);
		EscapeCommFunction(m_hComm,SETDTR);
		EscapeCommFunction(m_hComm,SETRTS);		

		m_nPaud = nPaud;
		m_nPort = nPort;
		return TRUE;
	}
	return FALSE;
}
接下来是写串口数据函数, 对其中数据可以分为一次性全部写入与一个字节一个字节进行写入两种方式,大多数情况下,是使用前一种方式写入数据

int CSerial::WriteComm(BYTE ch,int delay)
{
	return(WriteCommData(&ch,1,delay));
}

int CSerial::WriteCommData(BYTE* buff,int len,int delay /* = 1 */,int flag /* = 0 */)
{
	int i=0;
	unsigned long number = 0;
	if (flag == 0)
	{
		if(delay!=0)
			Sleep(delay);
		WriteFile(m_hComm,buff,len,&number,NULL);
		return ((int)number);
	}
	//为了一个字节一个字节的写入
	else
	{
		for (i=0;i<len;i++)
		{
			if(delay!=0)
				Sleep(delay);
			WriteFile(m_hComm,buff+i,1,&number,NULL);
			//当不再写入数据时,退出循环
			if(number<1)
				break;
		}
		return i;
	}
}
然后便是读取数据了,然后这里也是分为两类,第一种是用于已知要接收数据对象的形式,用于上下层设计好接口方式的程序中,第二种则是类似等待数据的形式,当无法获知串口何时会有数据上传时,可以在while循环中使用该函数来作为等待

//根据接口定义已经获知需要读取的数据大小
int CSerial::ReadCommData(BYTE* buff,int len,int timeout)
{
	DWORD	start;
	COMSTAT	stat;
	DWORD	dwError;

	int i=0;
	unsigned long number = 0;
	start = GetTickCount();
	do 
	{
		//清除COMM标志
		int err = GetLastError();
		ClearCommError(m_hComm,&dwError,&stat);
		//担心一次readfile操作无法完全获取到需要的数据,
		//故对该操作的长度进行限定并判断
		ReadFile(m_hComm,buff+i,len-i,&number,NULL);
		//若是该此读取出来的数据大小与剩下需要的大小相同,则说明已经读取完毕
		if(number == (unsigned long)(len-i))
			return len;
		//若是还可以读取出数据,说明还有,将读取出来的数据进行迭代
		else if(number>0)
			i+=number;
		else if(timeout>5)
			Sleep(1);
	} while (GetTickCount()-start <(unsigned int)timeout);
	return i;
}
int CSerial::ReadCommData(int timeout)
{
	BYTE	ch;
	DWORD	start;
	COMSTAT	stat;
	DWORD	dwError;
	unsigned long	number = 0;
	start = GetTickCount();
	do 
	{
		int err = GetLastError();

		ClearCommError(m_hComm,&dwError,&stat);
		//一个字节一个字节进行读取
		ReadFile(m_hComm,&ch,1,&number,NULL);
		//说明串口中是存在数据的
		if(number>0)
			return (int)ch;
	} while (GetTickCount()-start <(unsigned int)timeout);
	return -1;
}
然后是最后两个函数了
void CSerial::CloseComm()
{
	if (m_hComm!=INVALID_HANDLE_VALUE)
	{
		Sleep(5);
		CloseHandle(m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;
	}
}
BOOL	CSerial::IsOpen()
{
	return (m_hComm!=INVALID_HANDLE_VALUE);
}
就这样,一个简单的串口类就算完成了,以上这些代码并不是我的原创,只是觉得这个类比较简洁,于是就拿来用了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值