• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            開(kāi)源之路

            憶往昔, 項(xiàng)羽不過(guò)江. 江東好風(fēng)光! 今振臂一呼,率甲三千, 試問(wèn)天!
            posts - 86, comments - 55, trackbacks - 0, articles - 0
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            Win32串口編程

            Posted on 2006-07-18 13:03 江邊之鳥(niǎo) 閱讀(967) 評(píng)論(0)  編輯 收藏 引用
            一、基本知識(shí)

               Win32下串口通信與16位串口通信有很大的區(qū)別。在Win32下,可以使用兩種編程方式實(shí)現(xiàn)串口通信,其一是調(diào)用的Windows的API函數(shù),其二是使用ActiveX控件。使用API 調(diào)用,可以清楚地掌握串口通信的機(jī)制,熟悉各種配置和自由靈活采用不同的流控進(jìn)行串口通信。下面介紹串口操作的基本知識(shí)。

              打開(kāi)串口:使用CreateFile()函數(shù),可以打開(kāi)串口。有兩種方法可以打開(kāi)串口,一種是同步方式(NonOverlapped),另外一種異步方式(Overlapped)。使用Overlapped打開(kāi)時(shí),適當(dāng)?shù)姆椒ㄊ牵?

            HANDLE hComm;
            hComm = CreateFile( gszPort,
            GENERIC_READ | GENERIC_WRITE,
            0,
            0,
            OPEN_EXISTING,
            FILE_FLAG_OVERLAPPED,
            0);
            if (hComm == INVALID_HANDLE_value)
            // error opening port; abort
              配置串口:

              1.DCB配置

               DCB(Device Control Block)結(jié)構(gòu)定義了串口通信設(shè)備的控制設(shè)置。許多重要設(shè)置都是在DCB結(jié)構(gòu)中設(shè)置的,有三種方式可以初始化DCB。

              (1)通過(guò)GetCommState()函數(shù)得DCB的初始值,其使用方式為:

            DCB dcb = {0};
            if (!GetCommState(hComm, &dcb))
            // Error getting current DCB settings
            else
            // DCB is ready for use.

              (2)用BuildCommDCB()函數(shù)初始化DCB結(jié)構(gòu),該函數(shù)填充 DCB的波特率、奇偶校驗(yàn)類(lèi)型、數(shù)據(jù)位、停止位。對(duì)于流控成員函數(shù)設(shè)置了缺省值。其用法是:

            DCB dcb;
            FillMemory(&dcb, sizeof(dcb), 0);
            dcb.DCBlength = sizeof(dcb);
            if (!BuildCommDCB(“9600,n,8,1", &dcb)) {
            // Couldn't build the DCB. Usually a problem
            // with the communications specification string.
            return FALSE;
            }
            else
            // DCB is ready for use.

              (3)用SetCommState()函數(shù)手動(dòng)設(shè)置DCB初值。用法如下:

            DCB dcb;
            FillMemory(&dcb, sizeof(dcb), 0);
            if (!GetCommState(hComm, &dcb)) // get current DCB
            // Error in GetCommState
            return FALSE;
            // Update DCB rate.
            dcb.BaudRate = CBR_9600 ;
            // Set new state.
            if (!SetCommState(hComm, &dcb))
            // Error in SetCommState.
            Possibly a problem with the communications
            // port handle or a problem with the DCB structure itself.

              手動(dòng)設(shè)置DCB值時(shí),DCB的結(jié)構(gòu)的各成員的含義,可以參看MSDN幫助。

               2.流控設(shè)置

              硬件流控:串口通信中的硬件流控有兩種,DTE/DSR方式和RTS/CTS方式,這與DCB結(jié)構(gòu)的初始化有關(guān)系,DCB結(jié)構(gòu)中的OutxCtsFlow、 fOutxDsrFlow、fDsrSensitivity、fRtsControl、fDtrControl幾個(gè)成員的初始值很關(guān)鍵,不同的值代表不同流控,也可以自己設(shè)置流控,但建議采用標(biāo)準(zhǔn)流行的流控方式。采用硬件流控時(shí),DTE、DSR、RTS、CTS的邏輯位直接影響到數(shù)據(jù)的讀寫(xiě)及收發(fā)數(shù)據(jù)的緩沖區(qū)控制。

               軟件流控:串口通信中采用特殊字符XON和XOFF作為控制串口數(shù)據(jù)的收發(fā)。與此相關(guān)的DCB成員是:fOut、fInX、XoffChar、XonChar、 XoffLim和XonLim。具體含義參見(jiàn)MSDN幫助。

               串口讀寫(xiě)操作:串口讀寫(xiě)有兩種方式:同步方式(NonOverlapped)和異步方式(Overlapped)。同步方式是指必須完成了讀寫(xiě)操作,函數(shù)才返回,這可能造成程序死掉,因?yàn)槿绻谧x寫(xiě)時(shí)發(fā)生了錯(cuò)誤,永遠(yuǎn)不返回就會(huì)出錯(cuò),可能線程將永遠(yuǎn)等待在那兒。而異步方式則靈活得多,一旦讀寫(xiě)不成功,就將讀寫(xiě)掛起,函數(shù)直接返回,可以通過(guò)GetLastError函數(shù)得知讀寫(xiě)未成功的原因,所以常常采用異步方式操作。

               讀操作:ReadFile()函數(shù)用于完成讀操作。異步方式的讀操作為:

            DWORD dwRead;
            BOOL fWaitingOnRead = FALSE;
            OVERLAPPED osReader = {0};
            // Create the overlapped event. Must be closed before exiting
            // to avoid a handle leak.
            osReader.hEvent = CreateEvent
            (NULL, TRUE, FALSE, NULL);
            if (osReader.hEvent == NULL)
            // Error creating overlapped event; abort.
            if (!fWaitingOnRead) {
            // Issue read operation.
            if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE,
             &dwRead, &osReader)) {
            if (GetLastError() != ERROR_IO_PENDING)
            // read not delayed?
            // Error in communications; report it.
            else
            fWaitingOnRead = TRUE;
            }
            else {
            // read completed immediately
            HandleASuccessfulRead(lpBuf, dwRead);
            }
            }

               如果讀操作被掛起,可以調(diào)用WaitForSingleObject()函數(shù)或WaitForMuntilpleObjects()函數(shù)等待讀操作完成或者超時(shí)發(fā)生,再調(diào)用 GetOverlappedResult()得到想要的信息。

               寫(xiě)操作:與讀操作相似,故不詳述,調(diào)用的API函數(shù)是: WriteFile函數(shù)。

               串口狀態(tài):

              (1)通信事件:用SetCommMask()函數(shù)設(shè)置想要得到的通信事件的掩碼,再調(diào)用WaitCommEvent()函數(shù)檢測(cè)通信事件的發(fā)生。可設(shè)置的通信事件標(biāo)志(即SetCommMask()函數(shù)所設(shè)置的掩碼)可以有EV_BREAK、EV_CTS、EV_DSR、 EV_ERR、EV_RING、EV_RLSD、EV_RXCHAR、EV_RXFLAG、EV_TXEMPTY。

               注意:1對(duì)于EV_RING標(biāo)志的設(shè)置,WIN95是不會(huì)返回EV_RING事件的,因?yàn)閃IN95不檢測(cè)該事件。2設(shè)置EV_RXCHAR,可以檢測(cè)到字符到達(dá),但是在綁定此事件和ReadFile()函數(shù)一起讀取串口接收數(shù)據(jù)時(shí),可能會(huì)出現(xiàn)錯(cuò)誤,造成少讀字節(jié)數(shù),具體原因查看MSDN幫助。可以采用循環(huán)讀的辦法,另外一個(gè)比較好的解決辦法是調(diào)用ClearCommError()函數(shù),確定在一次讀操作中在緩沖區(qū)中等待被讀的字節(jié)數(shù)。

              (2)錯(cuò)誤處理和通信狀態(tài):在串口通信中,可能會(huì)產(chǎn)生很多的錯(cuò)誤,使用ClearCommError()函數(shù)可以檢測(cè)錯(cuò)誤并且清除錯(cuò)誤條件。

               (3)Modem狀態(tài):用SetcommMask()可以包含很多事件標(biāo)志,但是這些事件標(biāo)志只指示在串口線路上的電壓變化情況。而調(diào)用 GetCommModemStatus()函數(shù)可以獲得線路上真正的電壓狀態(tài)。

               擴(kuò)展函數(shù):如果應(yīng)用程序想用自己的流控,可以使用 EscapeCommFunction()函數(shù)設(shè)置DTR和RTS線路的電平。

               通信超時(shí):在通信中,超時(shí)是個(gè)很重要的考慮因素,因?yàn)槿绻跀?shù)據(jù)接收過(guò)程中由于某種原因突然中斷或停止,如果不采取超時(shí)控制機(jī)制,將會(huì)使得I/O線程被掛起或無(wú)限阻塞。串口通信中的超時(shí)設(shè)置分為兩步,首先設(shè)置 COMMTIMEOUTS結(jié)構(gòu)的五個(gè)變量,然后調(diào)用SetcommTimeouts()設(shè)置超時(shí)值。對(duì)于使用異步方式讀寫(xiě)的操作,如果操作掛起后,異步成功完成了讀寫(xiě),WaitForSingleObject()或 WaitForMultipleObjects()函數(shù)將返回WAIT_OBJECT_0,GetOverlappedResult()返回TRUE。其實(shí)還可以用GetCommTimeouts()得到系統(tǒng)初始值。

               關(guān)閉串口:程序結(jié)束或需要釋放串口資源時(shí),應(yīng)該正確關(guān)閉串口,關(guān)閉串口比較簡(jiǎn)單,使用API調(diào)用CloseHandle()關(guān)閉串口的句柄就可以了。

              調(diào)用方法為:CloseHandle(hComm);

               但是值得注意的是在關(guān)閉串口之前必須保證讀寫(xiě)串口線程已經(jīng)退出,否則會(huì)引起誤操作,一般采用的辦法是使用事件驅(qū)動(dòng)機(jī)制,啟動(dòng)一事件,通知串口讀寫(xiě)線程強(qiáng)制退出,在線程退出之前,通知主線程可以關(guān)閉串口。

            二、實(shí)現(xiàn)

              1.程序設(shè)計(jì)思路

               對(duì)于不同的應(yīng)用程序,雖然界面不同,但是如果采用串口與主機(jī)之間的通信,對(duì)串口的處理方式大致相似,無(wú)非就是通過(guò)串口收發(fā)數(shù)據(jù),對(duì)于通過(guò)串口接收到的數(shù)據(jù),交給上層軟件處理顯示,對(duì)于上層要發(fā)給串口的數(shù)據(jù),進(jìn)行轉(zhuǎn)發(fā)。但在實(shí)際編程中,由于采用的通信方式和流控不同,串口設(shè)置也不同,這就涉及到 DCB的初始化問(wèn)題和讀寫(xiě)串口等細(xì)節(jié)問(wèn)題。串口通信應(yīng)用程序設(shè)計(jì)的總體思路(即操作過(guò)程)是:首先,確定要打開(kāi)的串口名、波特率、奇偶校驗(yàn)方式、數(shù)據(jù)位、停止位,傳遞給CreateFile()函數(shù)打開(kāi)特定串口;其次,為了保護(hù)系統(tǒng)對(duì)串口的初始設(shè)置,調(diào)用 GetCommTimeouts()得到串口的原始超時(shí)設(shè)置;然后,初始化DCB對(duì)象,調(diào)用SetCommState() 設(shè)置DCB,調(diào)用SetCommTimeouts()設(shè)置串口超時(shí)控制;再次,調(diào)用SetupComm()設(shè)置串口接收發(fā)送數(shù)據(jù)的緩沖區(qū)大小,串口的設(shè)置就基本完成,之后就可以啟動(dòng)讀寫(xiě)線程了。

              一般來(lái)說(shuō),串口的讀寫(xiě)由串口讀寫(xiě)線程完成,這樣可以避免讀寫(xiě)阻塞時(shí)主程序死鎖。對(duì)于全雙工的串口讀寫(xiě),應(yīng)該分別開(kāi)啟讀線程和寫(xiě)線程;對(duì)于半雙工和單工的,建議只需開(kāi)啟一個(gè)線程即可。在線程中,按照預(yù)定好的通信握手方式,正確檢測(cè)串口狀態(tài),讀取發(fā)送串口數(shù)據(jù)。

              2.實(shí)現(xiàn)細(xì)節(jié)

              在半雙工的情況下,首先完成必要的串口配置,成功打開(kāi)串口、DCB設(shè)置、超時(shí)設(shè)置;然后開(kāi)啟線程,如: CwinThread hSerialThread = (CWinThread*) AfxBeginThread(SerialOperation,hWnd,THREAD_PRIORITY_NORMAL); 其中開(kāi)啟之線程為SerialOperation,優(yōu)先級(jí)為普通。

               全雙工情況下的串口編程,與單工差不多,區(qū)別僅僅在于啟動(dòng)雙線程,分別為讀線程和寫(xiě)線程,讀線程根據(jù)不同的事件或消息,通過(guò)不斷查詢串口所收到的有效數(shù)據(jù),完成讀操作;寫(xiě)線程通過(guò)接收主線程的發(fā)送數(shù)據(jù)事件和要發(fā)送的數(shù)據(jù),向串口發(fā)送。

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            亚洲国产精品综合久久一线| 狠狠狠色丁香婷婷综合久久俺| 青青久久精品国产免费看| 伊人色综合久久天天网| 国产成人精品综合久久久久| 久久99精品久久久久久久不卡| 2020久久精品国产免费| 久久久久人妻一区精品果冻| 97视频久久久| 久久久久中文字幕| 亚洲午夜无码AV毛片久久| 久久久久亚洲精品天堂| 日韩精品久久久久久| 国产精品亚洲综合久久| 九九99精品久久久久久| 久久久久久久综合综合狠狠| 亚洲AV日韩AV天堂久久| 九九久久精品国产| 久久人人爽人人爽人人AV| 国产精品久久久天天影视香蕉| 亚洲午夜久久久影院伊人| 久久国产视屏| 久久精品中文字幕无码绿巨人| 久久久久国色AV免费看图片| 久久精品亚洲中文字幕无码麻豆| 久久福利片| 狠色狠色狠狠色综合久久| 久久亚洲国产最新网站| 国产成人精品综合久久久| 99久久夜色精品国产网站| 久久精品国产精品亚洲下载| 99久久国产热无码精品免费| 久久久国产99久久国产一| 久久国产成人午夜AV影院| 久久精品欧美日韩精品| 亚洲天堂久久久| 国产真实乱对白精彩久久| 99久久超碰中文字幕伊人| 人妻精品久久无码专区精东影业 | 嫩草影院久久国产精品| 狠狠色综合网站久久久久久久高清 |