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

来源:互联网 发布:淘宝母婴用品货源 编辑:程序博客网 时间:2024/06/04 00:45

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

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

#pragma once#ifndef _PC_SERIAL_H__#define _PC_SERIAL_H__classCSerial:public CObject{public:CSerial();virtual~CSerial();BOOLOpenComm(int nPort,LONG32nPaud,char parity = 'N',DWORD dwCommEvents = EV_RXCHAR,UINT databits = 8, UINT stopbits = 1);BOOLIsOpen();voidCloseComm();intWriteComm(BYTE ch,int delay);intWriteCommData(BYTE*buff,intlen,int delay = 1,int flag = 0);intReadCommData(BYTE*buff,int len,int timeout);intReadCommData(int  timeout);intm_nPort;intm_nPaud;private://intm_hComm;HANDLEm_hComm;};#endif
接下来看具体的实现,首先是构造析构函数
CSerial::CSerial(){m_hComm= INVALID_HANDLE_VALUE;}CSerial::~CSerial(){CloseComm();}
接下来是打开串口函数,这里有默认的串口设置
BOOLCSerial::OpenComm(int nPort,LONG32 nPaud,char parity /* =  */,   DWORD dwCommEvents /* = EV_RXCHAR */,UINT databits /* = 8 */, UINT stopbits /* = 1 */){COMMTIMEOUTStous;DCBdcb;CStringstrComm;memset(&tous,0,sizeof(tous));tous.ReadIntervalTimeout = MAXWORD;//在串口号大于10时,需要修改其字符串形式if (nPort >=10){strComm.Format(_T("\\\\.\\%d"),nPort);}elsestrComm.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均为4kSetCommTimeouts(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){DWORDstart;COMSTATstat;DWORDdwError;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){BYTEch;DWORDstart;COMSTATstat;DWORDdwError;unsigned longnumber = 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;}}BOOLCSerial::IsOpen(){return (m_hComm!=INVALID_HANDLE_VALUE);}
就这样,一个简单的串口类就算完成了,以上这些代码并不是我的原创,只是觉得这个类比较简洁,于是就拿来用了。





原创粉丝点击