📄 win32串口编程技术.htm
字号:
<OL><P ALIGN="JUSTIFY"><LI>串口状态:</LI><p></P></OL></FONT><DIR><DIR><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>(</font><FONT SIZE=3>1</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>)通信事件:用</FONT><FONT SIZE=3>SetCommMask()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数设置想要得到的通信事件的掩码,再调用</FONT><FONT SIZE=3>WaitCommEvent()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数检测通信事件的发生。可设置的通信事件标志(即</FONT><FONT SIZE=3>SetCommMask()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数所设置的掩码)可以有</FONT><FONT SIZE=3>EV_BREAK </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_CTS</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_DSR</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_ERR</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_RING</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_RLSD</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_RXCHAR</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_RXFLAG</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>EV_TXEMPTY</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</font></P><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>注意:(</font><FONT SIZE=3>1</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>)对于</FONT><FONT SIZE=3>EV_RING</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>标志的设置,</FONT><FONT SIZE=3>WIN95</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>是不会返回</FONT><FONT SIZE=3>EV_RING</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>事件的,因为</FONT><FONT SIZE=3>WIN95</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>不检测该事件。(</FONT><FONT SIZE=3>2</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>)设置</FONT><FONT SIZE=3>EV_RXCHAR</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,可以检测到字符到达,但是在绑定此事件和</FONT><FONT SIZE=3>ReadFile()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数一起读取串口接收数据时,可能会出现错误,造成少读字节数,具体原因查看</FONT><FONT SIZE=3>MSDN</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>帮助。可以采用循环读的办法,另外一个比较好的解决办法是调用</FONT><FONT SIZE=3>ClearCommError()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数确定在一次读操作中在缓冲区中等待被读的字节数。</font></P><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>(</font><FONT SIZE=3>2</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>)错误处理和通信状态:</font></P><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在串口通信中,可能会产生很多的错误,使用</font><FONT SIZE=3>ClearCommError()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数可以检测错误并且清除错误条件。</font></P><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>(</font><FONT SIZE=3>3</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>)</FONT><FONT SIZE=3>Modem</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>状态:</font></P><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用</font><FONT SIZE=3>SetcommMask()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>可以包含很多事件标志,但是这些事件标志只指示在串口线路上的电压变化情况。而调用</FONT><FONT SIZE=3>GetCommModemStatus()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数可以获得线路上真正的电压状态。</font></P></DIR></DIR><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><OL START=4><OL><P ALIGN="JUSTIFY"><LI>扩展函数:</LI><p></P></OL></OL></FONT><DIR><DIR><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>如果应用程序想用自己的流控,可以使用</font><FONT SIZE=3>EscapeCommFunction()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数设置</FONT><FONT SIZE=3>DTR</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>RTS</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>线路的电平</font></P></DIR></DIR><OL><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>通信超时:</LI><p></P></font><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在通信中,超时是个很重要的考虑因素,因为如果在数据接收过程中由于某种原因突然中断或停止,如果不采取超时控制机制,将会使得</font><FONT SIZE=3>I/0</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>现程被挂起或无限阻塞。串口通信中的超时设置氛围两步,首先设置</FONT><FONT SIZE=3>COMMTIMEOUTS</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>结构的五个变量,然后调用</FONT><FONT SIZE=3>SetcommTimeouts()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>设置超时值。对于使用异步方式读写的操作,如果操作挂起后,异步成功完成了读写,</FONT><FONT SIZE=3>WaitForSingleObject()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>WaitForMultilpleObjects()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数将返回</FONT><FONT SIZE=3>WAIT_OBJECT_0</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</FONT><FONT SIZE=3>GetOverlappedResult()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>返回</FONT><FONT SIZE=3>TRUE</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。其实还可以用</FONT><FONT SIZE=3>GetCommTimeouts()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>得到系统初始值。</font></P><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>关闭串口:</LI><p></P></font></OL><DIR><FONT FACE="宋体" LANG="ZH-CN" SIZE=3></font><P ALIGN="JUSTIFY"><FONT SIZE=3> </font><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>程序结束或需要需要释放串口资源时,应该正确的关闭串口,关闭串口比较简单,使用</FONT><FONT SIZE=3>API</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>调用</FONT><FONT SIZE=3>CloseHandle()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>关闭串口的句柄就可以了。</font></P><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>调用方法为:</font><FONT SIZE=3>CloseHandle(hComm);</font></P><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">但是值得注意的是在关闭串口之前必须保证读写串口线程已经退出,否则会引起误操作,一般采用的办法是使用事件驱动机制,启动一事件,通知串口读写线程强制退出,在线程退出之前,通知主线程可以关闭串口。</P><P ALIGN="JUSTIFY"> </P></font></DIR><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><B><P ALIGN="JUSTIFY">二.Win32串口通信实现</P><P ALIGN="JUSTIFY"> </P></B></FONT><OL><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><B></b><P ALIGN="JUSTIFY"><LI>程序设计思路:</LI><p></P></font><P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对于不同的应用程序,虽然界面不同,但是如果采用串口与主机之间的通信,对串口的处理方式大致相似。无非就是通过串口收发数据,对于通过串口接收到的数据,交给上层软件处理显示,对于上层要发给串口的数据,进行转发。但在实际编程中,由于采用的通信方式和流控不同,串口设置也不同,这就涉及到</font><FONT SIZE=3>DCB</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的初始化问题和读写串口等细节问题。串口通信应用程序设计的总体思路(即操作过程)是:首先,确定要打开的串口名,波特率,奇偶校验方式,数据位,停止位,传递给</FONT><FONT SIZE=3>CreateFile()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数打开特定串口;其次,为了保护系统对串口的初始设置,调用</FONT><FONT SIZE=3>GetCommTimeouts()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>得到串口的原始超时设置;然后,初始化</FONT><FONT SIZE=3>DCB</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象,调用</FONT><FONT SIZE=3>SetCommState()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>设置</FONT><FONT SIZE=3>DCB</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,调用</FONT><FONT SIZE=3>SetCommTimeouts()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>设置串口超时控制;再次,调用</FONT><FONT SIZE=3>SetupComm()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>设置串口接收发送数据的缓冲区大小,串口的设置就基本完成,之后就可以启动读写线程了。</font></P><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">一般来说,串口的读写由串口读写线程完成,这样可以避免读写阻塞时主程序死锁。对于全双工的串口读写,应该分别开启读线程和写线程;对于半双工和单工的,建议只需开启一个线程即可。在线程中,按照预定好的通信握手方式,正确检测串口状态,读取发送串口数据。</P><P ALIGN="JUSTIFY"> </P><P ALIGN="JUSTIFY"><LI>实现细节:</LI><p></P></font></OL><DIR> <P ALIGN="JUSTIFY"> <FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在半双工的情况下,首先完成必要的串口配置,成功打开串口,</font><FONT SIZE=3>DCB</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>设置,超时设置;然后,开启线程,如:</FONT><FONT SIZE=3> CwinThread hSerialThread = (CWinThread*) AfxBeginThread(</font></P> <P ALIGN="JUSTIFY"> <FONT SIZE=3> SerialOperation</font><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</FONT><FONT SIZE=3>hWnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</FONT><FONT SIZE=3>THREAD_PRIORITY_NORMAL);</font></P> <P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>其中开启之线程为</font><FONT SIZE=3>SerialOperation</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,优先级为普通。线程的流程图见图</FONT><FONT SIZE=3>1-1</font></P> <FONT FACE="宋体" LANG="ZH-CN" SIZE=3> <P ALIGN="JUSTIFY"> <img src="Serial_Image1.jpg" width=321 height=384 hspace="120"> </P> </font></DIR><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>全双工情况下的串口编程,与单工差不多,区别仅仅在于启动双线程,分别为读线程和写线程,读线程根据不同的事件或消息,通过不断查询串口所收到的有效数据,完成读操作;写线程通过接收主线程的发送数据事件和要发送的数据,向串口发送。 </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3> </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> </P></FONT><B><FONT FACE="宋体" LANG="ZH-CN"> <P ALIGN="JUSTIFY">参考文献</P></font></B> <OL> <FONT FACE="宋体" LANG="ZH-CN"><B> </b></font><P ALIGN="JUSTIFY"> <FONT FACE="宋体" LANG="ZH-CN" SIZE=3> </font> <FONT SIZE=3></FONT><FONT SIZE=3> </FONT><FONT SIZE=3> <p></P> </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3> <P ALIGN="JUSTIFY"> </FONT> <LI><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>张力,吕振肃,赵庆林,“</font><FONT SIZE=3>VC++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>下串行通信的编程方法”,计算机应用,</FONT><FONT SIZE=3>1999(3)</font></LI> <FONT SIZE=3> <p></P> </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3> <P ALIGN="JUSTIFY"> </FONT> <LI><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>郭峰林,朱才连,“</font><FONT SIZE=3>Windows 95</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>下串行通信编程技术及实现”,计算机应用,</FONT><FONT SIZE=3>1999(6)</font></LI> <FONT SIZE=3> <p></P> <P ALIGN="JUSTIFY"> </FONT> <LI><FONT SIZE=3>Microsoft Corporation</font><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>著,“</FONT><FONT SIZE=3>Win32</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>程序员参考大全</FONT><FONT SIZE=3>(</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>二</FONT><FONT SIZE=3>)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>”,欣力等译,北京</FONT><FONT SIZE=3>:</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>清华大学出版社,</FONT><FONT SIZE=3>1995</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</FONT><FONT SIZE=3>4</font></LI> <FONT SIZE=3> <p></P> <P ALIGN="JUSTIFY"> </FONT> <LI><FONT SIZE=3>Charles A. Mirho, Andre Terrisse</font><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>著,“</FONT><FONT SIZE=3>Windows95</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>通信编程”,贺军等译,北京</FONT><FONT SIZE=3>:</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>清华大学出版社,</FONT><FONT SIZE=3>1997</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,</FONT><FONT SIZE=3>12</font></LI> <FONT SIZE=3> <p></P> </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3> <P ALIGN="JUSTIFY"> </FONT> <LI><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>周升峰,“</font><FONT SIZE=3>Visual C++ Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>实用编程技术”,北京:北京航空航天大学出版社</font></LI> <FONT FACE="宋体" LANG="ZH-CN" SIZE=3> <p></P> </FONT><FONT SIZE=3> <P ALIGN="JUSTIFY"> </FONT> <LI><FONT SIZE=3>Kate Gregory</font><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>著,“</FONT><FONT SIZE=3>Visual C++6</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>开发使用手册”,前导工作室译,机械出版社</font></LI> <FONT FACE="宋体" LANG="ZH-CN" SIZE=3> <p></P> </FONT><FONT SIZE=3> <p></P> <P ALIGN="JUSTIFY"> <LI>Allen Denver. Serial Communications in Win32. Microsoft Windows Developer Support, December 11, 1995</LI> <p></P> <P ALIGN="JUSTIFY"> <LI>Brain, Marshall. Win32 System Services: The Heart of Windows NT. Englewood Cliffs, NJ: Prentice Hall, 1994</LI> <p></P> <P ALIGN="JUSTIFY"> <LI>Campbell, Joe. C Programmer’s Guide to Serial Communications. 2d ed. Indianapolis, IN: Howard W. Sams & Company, 1994</LI> <p></P> <P ALIGN="JUSTIFY"> <LI>Mirho, Charles, and Andy Terrice. “Create Communications Programs for Windows 95 with the Win32 Comm API.” Microsoft Systems Journal 12 (December 1994). (MSDN Library, Books and Periodicals)</LI> <p></P> </font> </OL></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -