串口通信模块3:串口通信编程基础(读写、关闭)
上一节总结了如何打开串口并讨论了如何配置串口,本节是在上一节的基础上,进一步讨论串口编程的基础——如何进行文件读写?如何关闭串口?
1. 读写串口
串口的读写操作和文件的读写操作是一样的,也是通过ReadFile()及WriteFile()函数来实现的。这两个函数的原型分别如下:
写文件函数原型及说明:
BOOL WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped, ); 该函数包含5各参数,其具体意义为:
hFile:打开串口时返回的句柄。
lpBuffer:写入的数据存储的地址,即以该指针得值为首地址的nNumberOfBytesToWrite个字节的数据,将要写入串口的发送数据缓冲区。
nNumberOfBytesToWrite:要写入的数据的字节数
lpNumberOfByteWritten:指向一个DWORD数值,该数值返回实际写入的字节数。
lpOverlapped:重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL.
读文件函数原型及说明:
再用ReadFile()和WriteFile()函数读写串口时,即可以同步执行也可以重叠执行。再同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在重叠操作时,即时操作还未完成,这两个函数也会立即返回,费事的I/O操作在后台运行。
而在调用CreateFile()函数打开串口时,就已经决定了ReadFile()和WriteFile()函数对串口的操作是同步还是异步。如果在调用CreateFile()函数创建打开串口时指定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile()和WriteFile()函数对该打开串口时返回的句柄进行的操作就是重叠的。如果没有指定重叠标志,那么读写操作就应该是同步的。这里强调的是:ReadFile()和WriteFile()函数的同步或异步选择应该和CreateFile()函数相一致。
说明:ReadFile()函数只要在串口输入缓冲区中读入指定数量的字符,就算完成了工作。然而,WriteFile()函数不但要把指定数量的字符复制到输出缓冲区,而且要等这些字符从创航口送出去才算完成操作。
由于同步读写串口的实现很简单,先研究同步串口读写的代码:
//同步读串口代码 bool ReadCom(char * str, int len) {DWORD wCount; //读取的字节数BOOL bReadStat;bReadStat = ReadFile( hCom, str, len, &wCount, NULL);if (!bReadStat){AfxMessageBox(" 读串口失败! ");return FALSE;}return TRUE; }
异步读写串口的实现就比较灵活了,即可以实现非阻塞读写,也可以实现阻塞读写。有两种方法可以等待操作完成而实现阻塞读写。
# 应用像WaitForSingleObject()等待函数一样来等待OVERLAPPED结构的hEvent成员。
# 调用GetOverlappedResult()函数等待
在OVERLAPPED结构中包含了重叠I/O的一些信息,它的详细定义如下:
typedef struct _OVERLAPPED {DWORD Internal; //操作系统保留,指出一个和系统相关的状态DWORD InternalHigh;//指出发送或接收的数据长度DWORD Offset; //文件传送的开始位置DWORD OffsetHigh; //文件传送字节变一辆的高字节HANDLE hEvent; //指定一个I/O操作完成后触发的事件 }OVERLAPPED;在使用ReadFile()和WriteFile()函数进行异步重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。线程通过OVERLAPPED结构获得当前的操作状态,该结构的成员是hEvent。 hEvent是读写事件,当串口使用异步通信时,函数返回时可能还没有完成,程序可以通过检查该事件的值是否读写完毕。当调用ReadFile()或WriteFile()函数的时候,该成员会自动被指为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。
而GetOverlappedResult()函数返回重叠操作结束有点不同,他是通过判断OVERLAPPED结构中的hEvent是否被置位,来判断异步操作是否完成,函数原型如下:
BOOL GetOverlappedResults(HANDLE hFile, //串口的句柄LPOVERLAPPED lpOverlapped, //重叠操作开始时指定的OVERLAPPED结构LPWORD lpNumberOfBytesTransferred, //实际读写操作传输的字节数BOOL bWait //用于指定函数是否一直等到重叠操作结束 );在异步操作前应先使用ClearCommError()函数获取尚未读取的字节数,函数原型如下:
BOOL ClearComError(HANDLE hFile, //串口句柄LPDWORD lpErrors, //指向接受错误码的变量LPCOMSTAT lpStat //指向通信状态缓存区 );根据以上信息可以编写异步读串口的程序:
bool ReadCom(char* str, DWORD *len) {COMSTAT ComStat;DWORD dwErrorFlags;OVERLAPPED m_osRead;memset(&m_osRead,0,sizeof(OVERLAPPED));m_osRead.hEvent = CreateEveent(NULL, TRUE, FALSE, NULL);ClearCommError(hCom, &dwErrorFlags, &ComStat);dwBytesRead = min(len, (DWORD)ComStat.cbInQue);//获取尚未读取的字节数if (!dwBytesRead)return FALSE;BOOL bReadStatus;bReadStatus = ReadFile(hCom, str, len, &len, &m_osRead);//读取数据if (!bReadStatus){//错误处理if (GetLastError == ERROR_IO_PENDING){ //串口正在进行读操作//等到读操作完成或延时已经达到2秒WaitForSingleObject(m_osRead.hEvent,2000);PurgeComm(hCom,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);}//清空串口缓冲return false;}//清空串口缓存区PurgeComm(hCom,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);return true; }
2. 关闭串口
利用API函数关闭串口是非常简单的活儿,只需要使用CreateFile()函数返回的句柄作为参数调用CloseHandle()函数即可。CloseHandle()函数如下:
BOOL CloseHandle(HANDLE hObject; ); 到此,串口编程的基础就OK了,明天继续研究自定义串口类,以及界面设计的几点敲门,晚安!!
总结
以上是生活随笔为你收集整理的串口通信模块3:串口通信编程基础(读写、关闭)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 中国企业即时通讯
- 下一篇: 【绿色版】飞鸽传书2011绿色版