?? win32串口編程技術.htm
字號:
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb_2312-80"><META NAME="Generator" CONTENT="Microsoft Word 97"><TITLE>WIN32串口通信技術</TITLE></HEAD><BODY bgcolor="#CCCCFF"><B><FONT FACE="宋體" LANG="ZH-CN"> <P ALIGN="JUSTIFY">Win32串口編程技術</P></font></B><FONT FACE="宋體" LANG="ZH-CN" SIZE=3> <P ALIGN="JUSTIFY"> <b><font face="宋體" lang="ZH-CN" size="2">金貝貝</font><font size="2"> </font></b> </P><P ALIGN="JUSTIFY">串口通信是經典的數據通信,從單片機串口通信DOS下串口通信到WIN32串口通信,發展變換很大,WIN32下的串口通信與其他串口通信有很大的區別,在WIN32下的串口通信編程方式主要有兩種,一種是采用WIN32 API函數調用,另外一種方式是使用ActiveX控件。該綜述的第二部分介紹了WIN32下的串口通信。主要是利用多線程技術,調用WIN32 API函數,實現同步或異步的串口通信,根據不同的硬件握手方式和串口連線方式,WIN32下的串口通信方式十分靈活。作者利用該串口通信技術,采用VC6.0編程,在Windows98環境下開發了一套“公安350兆無線集群調度系統”,實時傳遞集群系統的電臺的數據和計算機的指令,成功的實現了集群系統的計算機調度,工作情況良好。</P><B><P ALIGN="JUSTIFY"> </P><P ALIGN="JUSTIFY">一.Win32串口通信基本知識</P></B><P ALIGN="JUSTIFY"> </P></FONT><P ALIGN="JUSTIFY"><FONT SIZE=3>Win32</font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>下串口通信與</FONT><FONT SIZE=3>16</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>Windows</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>ActiveX</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>控件。使用</FONT><FONT SIZE=3>API</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>調用,可以清楚地掌握串口通信的機制,熟悉各種配置和自由靈活采用不同的流控進行串口通信。下面介紹一下串口操作的基本知識。</font></P><OL><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"></font><LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>打開串口:使用</font><FONT SIZE=3>CreateFile()</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數,可以打開串口,有兩種方法可以打開串口,一種是同步方式(</FONT><FONT SIZE=3>NonOverlapped</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>)</FONT><FONT SIZE=3>,</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>另外一種異步方式(</FONT><FONT SIZE=3>overlapped</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>)。使用</FONT><FONT SIZE=3>Overlapped</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">HANDLE hComm;</P><P ALIGN="JUSTIFY">hComm = CreateFile( gszPort, </P><P ALIGN="JUSTIFY"> GENERIC_READ | GENERIC_WRITE, </P><P ALIGN="JUSTIFY"> 0, </P><P ALIGN="JUSTIFY"> 0, </P><P ALIGN="JUSTIFY"> OPEN_EXISTING,</P><P ALIGN="JUSTIFY"> FILE_FLAG_OVERLAPPED,</P><P ALIGN="JUSTIFY"> 0);</P><P ALIGN="JUSTIFY">if (hComm == INVALID_HANDLE_VALUE)</P><P ALIGN="JUSTIFY"> // error opening port; abort</P></FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>配置串口:</LI><p></P></font></OL><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>DCB</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>配置:</FONT> </P><DIR><DIR><P ALIGN="JUSTIFY"><FONT SIZE=3>DCB</font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>(</FONT><FONT SIZE=3>Device Control Block</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>DCB</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>。</font></P></DIR></DIR><P ALIGN="JUSTIFY"><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>其一是:通過</font><FONT SIZE=3>GetCommState()</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數得</FONT><FONT SIZE=3>DCB</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>的初始值,其使用方式為:</font></P><FONT SIZE=3><P ALIGN="JUSTIFY"> DCB dcb = {0};</P><P ALIGN="JUSTIFY"> if (!GetCommState(hComm, &dcb))</P><P ALIGN="JUSTIFY"> // Error getting current DCB settings</P><P ALIGN="JUSTIFY"> else</P><P ALIGN="JUSTIFY"> // DCB is ready for use.</P></FONT><DIR><DIR><FONT SIZE=3></font><P ALIGN="JUSTIFY"><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>其二是:用</font><FONT SIZE=3>BuildCommDCB()</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>DCB</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>的波特率,奇偶校驗類型,數據位,停止位,和數據位。對于流控成員函數設置了缺省值。其用法是:</font></P></DIR></DIR><FONT SIZE=3><P ALIGN="JUSTIFY"> DCB dcb;</P><P ALIGN="JUSTIFY"> FillMemory(&dcb, sizeof(dcb), 0);</P><P ALIGN="JUSTIFY"> dcb.DCBlength = sizeof(dcb);</P><P ALIGN="JUSTIFY"> if (!BuildCommDCB("9600,n,8,1", &dcb)) { </P><P ALIGN="JUSTIFY"> // Couldn't build the DCB. Usually a problem</P><P ALIGN="JUSTIFY"> // with the communications specification string.</P><P ALIGN="JUSTIFY"> return FALSE;</P><P ALIGN="JUSTIFY"> }</P><P ALIGN="JUSTIFY"> else</P><P ALIGN="JUSTIFY"> // DCB is ready for use.</P></FONT><DIR><FONT SIZE=3></font><P ALIGN="JUSTIFY"><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></P></DIR></DIR><FONT SIZE=3><P ALIGN="JUSTIFY"> DCB dcb;</P><P ALIGN="JUSTIFY"> FillMemory(&dcb, sizeof(dcb), 0);</P><P ALIGN="JUSTIFY"> if (!GetCommState(hComm, &dcb)) // get current DCB</P></FONT><P ALIGN="JUSTIFY"><FONT SIZE=3> </font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>	</FONT><FONT SIZE=3> // Error in GetCommState</font></P><FONT SIZE=3><P ALIGN="JUSTIFY"> 	return FALSE;</P><DIR><P ALIGN="JUSTIFY">// Update DCB rate.</P></DIR></FONT><P ALIGN="JUSTIFY"><FONT SIZE=3> </font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>	</FONT><FONT SIZE=3> dcb.BaudRate = CBR_9600 ;</font></P><P ALIGN="JUSTIFY"><FONT SIZE=3> </font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>	</FONT><FONT SIZE=3>// Set new state.</font></P><FONT SIZE=3><P ALIGN="JUSTIFY"> if (!SetCommState(hComm, &dcb))</P><P ALIGN="JUSTIFY"> // Error in SetCommState. Possibly a problem with the communications </P><P ALIGN="JUSTIFY"> // port handle or a problem with the DCB structure itself.</P></FONT><P ALIGN="JUSTIFY"><FONT SIZE=3> </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>DCB</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>的結構的各成員的含義,可以參看</FONT><FONT SIZE=3>MSDN</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>幫助。</font></P><P ALIGN="JUSTIFY"><FONT SIZE=3> </font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>(</FONT><FONT SIZE=3>2</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>)流控設置:</font></P><OL TYPE="A"><DIR><DIR><OL TYPE="A"><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"></font><LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>硬件流控:串口通信中的硬件流控有兩種,</font><FONT SIZE=3>DTE/DSR</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>方式和</FONT><FONT SIZE=3>RTS/CTS</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>DCB</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>結構中的</FONT><FONT SIZE=3>OutxCtsFlow</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>fOutxDsrFlow</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>fDsrSensitivity</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>fRtsControl</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>fDtrControl</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>幾個成員的初始值很關鍵,不同的值代表不同流控,也可以自己設置流控。但建議采用標準流行的流控方式。采用硬件流控時,</FONT><FONT SIZE=3>DTE</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>DSR</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>RTS</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>CTS</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>的邏輯位直接影響到數據的讀寫及收發數據的緩沖區控制。</font></LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><p></P><P ALIGN="JUSTIFY"></FONT><LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>軟件流控:串口通信中采用特殊字符</font><FONT SIZE=3>XON</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>XOFF</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>fOut</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>fInX</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>XoffChar</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>XonChar</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>、</FONT><FONT SIZE=3>XoffLim</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>XonLim</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>。</font></LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><p></P></font></OL></DIR></DIR></OL><P ALIGN="JUSTIFY"><FONT SIZE=3> </font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>具體含義參見</FONT><FONT SIZE=3>MSDN</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>幫助。</font></P><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><OL><P ALIGN="JUSTIFY"><LI>串口讀寫操作:</LI><p></P></OL></FONT><DIR><P ALIGN="JUSTIFY"><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>串口讀寫有兩種方式:同步方式(</font><FONT SIZE=3>NonOverlapped</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>)和異步方式(</FONT><FONT SIZE=3>Overlapped</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>)。同步方式是指必需完成了讀寫操作,函數才返回,這可能造成程序死掉,因為如果在讀寫時發生了錯誤,永遠不返回就會出錯,可能線程將永遠等待在那兒。而異步方式則靈活得多,一旦讀寫不成功,就將讀寫掛起,函數直接返回,可以通過</FONT><FONT SIZE=3>GetLastError</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數得到讀寫未成功的原因。所以常常采用異步方式操作。</font></P></DIR><OL><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>讀操作:</LI><p></P></font><P ALIGN="JUSTIFY"><FONT SIZE=3>ReadFile()</font><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數用于完成讀操作。異步方式的讀操作為:</font></P><FONT SIZE=3><P ALIGN="JUSTIFY">DWORD dwRead;</P><P ALIGN="JUSTIFY">BOOL fWaitingOnRead = FALSE;</P><P ALIGN="JUSTIFY">OVERLAPPED osReader = {0};</P><P ALIGN="JUSTIFY">// Create the overlapped event. Must be closed before exiting</P><P ALIGN="JUSTIFY">// to avoid a handle leak.</P><P ALIGN="JUSTIFY">osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);</P><P ALIGN="JUSTIFY">if (osReader.hEvent == NULL)</P><P ALIGN="JUSTIFY"> // Error creating overlapped event; abort.</P><P ALIGN="JUSTIFY">if (!fWaitingOnRead) {</P><P ALIGN="JUSTIFY"> // Issue read operation.</P><P ALIGN="JUSTIFY"> if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE, &dwRead, &osReader)) {</P><P ALIGN="JUSTIFY"> if (GetLastError() != ERROR_IO_PENDING) // read not delayed?</P><P ALIGN="JUSTIFY"> // Error in communications; report it.</P><P ALIGN="JUSTIFY"> else</P><P ALIGN="JUSTIFY"> fWaitingOnRead = TRUE;</P><P ALIGN="JUSTIFY"> }</P><P ALIGN="JUSTIFY"> else { </P><P ALIGN="JUSTIFY"> // read completed immediately</P><P ALIGN="JUSTIFY"> HandleASuccessfulRead(lpBuf, dwRead);</P><P ALIGN="JUSTIFY"> }</P><P ALIGN="JUSTIFY">}</P></FONT><P ALIGN="JUSTIFY"><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>如果讀操作被掛起,可以調用</font><FONT SIZE=3>WaitForSingleObject()</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數或</FONT><FONT SIZE=3>WaitForMuntilpleObjects()</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數等待讀操作完成或者超時發生,再調用</FONT><FONT SIZE=3>GetOverlappedResult()</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>得到想要的信息。</font></P><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"></FONT><LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>寫操作:與讀操作相似,故不詳述,調用的</font><FONT SIZE=3>API</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數是:</FONT><FONT SIZE=3>WriteFile</FONT><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>函數。</font></LI><FONT FACE="宋體" LANG="ZH-CN" SIZE=3><p></P></font></OL><FONT FACE="宋體" LANG="ZH-CN" SIZE=3>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -