《通信網(wǎng)絡(luò)程序設(shè)計(jì)》課件第3章_第1頁
《通信網(wǎng)絡(luò)程序設(shè)計(jì)》課件第3章_第2頁
《通信網(wǎng)絡(luò)程序設(shè)計(jì)》課件第3章_第3頁
《通信網(wǎng)絡(luò)程序設(shè)計(jì)》課件第3章_第4頁
《通信網(wǎng)絡(luò)程序設(shè)計(jì)》課件第3章_第5頁
已閱讀5頁,還剩85頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第3章串口網(wǎng)絡(luò)編程3.1串行通信概述3.2串口通信程序設(shè)計(jì)3.3串口通信程序設(shè)計(jì)小結(jié)

串口通信是一種通信條件要求最低卻十分重要的網(wǎng)絡(luò)通信模式,網(wǎng)絡(luò)設(shè)備調(diào)試、極端條件下的網(wǎng)絡(luò)通信都可以通過串口來實(shí)現(xiàn),特別是對一些便攜式、小型設(shè)備,串口通信可能是它們的唯一通信手段。串口通信處于OSI模型的數(shù)據(jù)鏈路層,通信協(xié)議簡單、編程接口函數(shù)數(shù)量較少,適合作為進(jìn)行網(wǎng)絡(luò)編程技術(shù)的入門學(xué)習(xí)內(nèi)容。

本章由串口通信的基本原理、接口入手,介紹串口通信的API函數(shù);并以主機(jī)與單片機(jī)、主機(jī)間的通信為實(shí)例,介紹串口網(wǎng)絡(luò)編程的方法。

串行總線是一種目前經(jīng)常使用的通信方式,單片機(jī)、PLC、測試儀器、PC、打印機(jī)、交換機(jī)、路由器、防火墻、工業(yè)控制設(shè)備都帶有串口總線。串行接口包括RS-232/422/485,其技術(shù)簡單成熟,性能可靠,所要求的軟硬件環(huán)境和條件都很低,是一種最簡單的建立網(wǎng)絡(luò)連接的方式。3.1串行通信概述3.1.1串行通信的模式

通過單線傳輸信息是串行數(shù)據(jù)通信的基礎(chǔ),數(shù)據(jù)通常是在兩個(gè)站(點(diǎn)對點(diǎn))之間進(jìn)行傳輸?shù)?。按照?shù)據(jù)流的方向,串行通信可分成三種傳輸模式:單工、半雙工、全雙工。

1.單工模式

單工模式的數(shù)據(jù)傳輸是單向的。通信雙方中,一方固定為發(fā)送端,另一方則固定為接收端。信息只能沿一個(gè)方向傳輸,使用一根傳輸線。單工模式一般用在只向一個(gè)方向傳輸數(shù)據(jù)的場合。例如計(jì)算機(jī)與打印機(jī)之間的通信是單工模式,因?yàn)橹挥杏?jì)算機(jī)向打印機(jī)傳輸數(shù)據(jù),而沒有相反方向的數(shù)據(jù)傳輸。在某些通信信道中,存在單工無線發(fā)送等單工模式。

2.半雙工模式

半雙工通信中使用同一根傳輸線,既可發(fā)送數(shù)據(jù)又可接收數(shù)據(jù),但不能同時(shí)進(jìn)行發(fā)送和接收。在任何時(shí)刻,只能由其中的一方發(fā)送數(shù)據(jù),另一方接收數(shù)據(jù)。因此半雙工模式既可以使用一條數(shù)據(jù)線,也可以使用兩條數(shù)據(jù)線。在半雙工通信中,每一端需裝有一個(gè)收發(fā)切換電子開關(guān),通過切換來決定數(shù)據(jù)向哪個(gè)方向傳輸。因?yàn)橛星袚Q,所以會(huì)產(chǎn)生時(shí)間延遲,信息傳輸效率也較低。

3.全雙工模式

全雙工數(shù)據(jù)通信分別由兩根可以在兩個(gè)不同的站點(diǎn)同時(shí)發(fā)送和接收的傳輸線進(jìn)行傳輸,通信雙方都能在同一時(shí)刻進(jìn)行發(fā)送和接收操作。在全雙工模式中,每一端都有發(fā)送器和接收器,有兩條傳輸線,可在交互式應(yīng)用和遠(yuǎn)程監(jiān)控系統(tǒng)中使用,信息傳輸效率較高。3.1.2串口的基本參數(shù)與標(biāo)準(zhǔn)

目前,常用的串口標(biāo)準(zhǔn)有RS-232C、RS-422、RS-485標(biāo)準(zhǔn)。

1.RS-232C

RS-232C是美國電子工業(yè)協(xié)會(huì)(ElectronicIndustryAssociation,EIA)于1962年公布并于1969年修訂的串行接口標(biāo)準(zhǔn),它已經(jīng)成為了國際上通用的標(biāo)準(zhǔn)。1987年1月,RS-232C經(jīng)修改后,正式改名為EIA-232D。由于標(biāo)準(zhǔn)修改內(nèi)容并不多,因此現(xiàn)在很多廠商仍使用舊的。RS-232C標(biāo)準(zhǔn)(協(xié)議)的全稱是EIA-RS-232C標(biāo)準(zhǔn),其中RS(RecommendedStandard)代表推薦標(biāo)準(zhǔn),232是標(biāo)識號,C代表RS-232的最新一次修改,它適合于數(shù)據(jù)傳輸速度在0~20

kb/s范圍內(nèi)的通信。這個(gè)標(biāo)準(zhǔn)對串行通信接口的有關(guān)問題,如信號電平、信號線功能、電氣特性、機(jī)械特性等都作了明確的規(guī)定。目前RS-232C已成為數(shù)據(jù)終端設(shè)備(DTE,如計(jì)算機(jī))和數(shù)據(jù)通信設(shè)備(DCE,如Modem)的接口標(biāo)準(zhǔn)。RS-232C是PC與通信工業(yè)中應(yīng)用最廣泛的一種串行接口,PC上的COM1和COM2大多是RS-232C接口。

利用RS-232C串行通信接口可實(shí)現(xiàn)兩臺個(gè)人計(jì)算機(jī)之間點(diǎn)對點(diǎn)的通信;通過RS-232C接口可與其他外設(shè)(如打印機(jī)、邏輯分析儀、智能調(diào)節(jié)儀、PLC等)近距離串行連接通過RS-232C接口連接調(diào)制解調(diào)器(Modem)可遠(yuǎn)距離地與其他計(jì)算機(jī)通信;將RS-232C接口轉(zhuǎn)換為RS-422或RS-485接口,可實(shí)現(xiàn)一臺個(gè)人計(jì)算機(jī)與多臺現(xiàn)場設(shè)備之間的通信。

RS-232的每一引腳都有它的作用,也有其信號流動(dòng)的方向,各引腳的信號功能描述見表3-1。原來的RS-232是用來連接調(diào)制解調(diào)器作為傳輸用的,因此它的引腳位意義通常也和調(diào)制解調(diào)器傳輸有關(guān)。從功能來看,全部信號線分為三類,即數(shù)據(jù)線(TXD、RXD)、地線(GND)和聯(lián)絡(luò)控制線(DSR、DTR、RI、DCD、RTS、CTS)。表3-1RS-232各引腳的信號功能只有當(dāng)DSR和DTR都處于有效(ON)狀態(tài)時(shí),才能在DTE和DCE之間進(jìn)行傳輸操作。若DTE要發(fā)送數(shù)據(jù),則預(yù)先將DTR線置成有效(ON)狀態(tài),等CTS線上收到有效(ON)狀態(tài)的回答后,才能在TXD線上發(fā)送串行數(shù)據(jù)。這種順序的規(guī)定對半雙工的通信線路特別有用,因?yàn)榘腚p工的通信確定DCE已由接收端向改為發(fā)送端向,這時(shí)線路才能開始發(fā)送。從計(jì)算機(jī)的角度來看這些引腳的通信狀況,流進(jìn)計(jì)算機(jī)端的,可以看做數(shù)字輸入;而流出計(jì)算機(jī)端的,則可以看做數(shù)字輸出。從工業(yè)應(yīng)用的角度來看,所謂的輸入就是用來“監(jiān)測”的,而輸出就是用來“控制”的。

2.RS-422

RS-422由RS-232發(fā)展而來,是為了彌補(bǔ)RS-232的不足而提出的。為了改進(jìn)RS-232抗干擾能力差、通信距離短、傳輸速度低等缺點(diǎn),RS-422定義了一種平衡通信接口,將傳輸速度提高到10

Mb/s,速率低于100

kb/s時(shí)的傳輸距離延長到4000英尺(1英尺=0.3048

m),并允許在一條平衡總線上連接最多10個(gè)接收器。RS-422是一種單機(jī)發(fā)送、多機(jī)接收的單向、平衡傳輸規(guī)范。

3.RS-485

為擴(kuò)展應(yīng)用范圍,EIA又于1983年在RS-422基礎(chǔ)上制定了RS-485標(biāo)準(zhǔn),增加了多點(diǎn)、雙向通信能力,即允許多個(gè)發(fā)送器連接到同一條總線上,同時(shí)增加了發(fā)送器的驅(qū)動(dòng)能力和沖突保護(hù)特性,擴(kuò)展了總線共模范圍。RS-485協(xié)議可以看做是RS-232協(xié)議的替代標(biāo)準(zhǔn),與傳統(tǒng)的RS-232協(xié)議相比,其在通信速率、傳輸距離、多機(jī)連接等方面均有了非常大的提高。由于RS-485總線是RS-232總線的改良標(biāo)準(zhǔn),因此在軟件設(shè)計(jì)上它與RS-232總線基本上一致。當(dāng)兩臺RS-232串口設(shè)備通信距離較近時(shí)(小于15

m),可以用電纜線直接將兩臺設(shè)備的RS-232端口連接;若通信距離較遠(yuǎn)時(shí)(大于15

m),則需要附加Modem。當(dāng)PC與串口設(shè)備的通信距離較遠(yuǎn)或PC與多臺具有RS-232接口的設(shè)備通信時(shí),也可以采用RS-485總線。3.1.3串行通信握手協(xié)議

串行通信需要使用握手協(xié)議保持?jǐn)?shù)據(jù)收發(fā)雙方的同步,握手協(xié)議靠握手信號實(shí)現(xiàn)。握手信號實(shí)際上就是控制信號,用來控制數(shù)據(jù)的傳輸。通過握手信號,發(fā)送端可以得知接收端是否有數(shù)據(jù)要發(fā)送。接收端通過握手信號通知發(fā)送端它是否已經(jīng)準(zhǔn)備好了接收信號。握手信號遵循某種協(xié)議。當(dāng)發(fā)送端和接收端處理數(shù)據(jù)的速度不一樣時(shí),可能會(huì)造成數(shù)據(jù)丟失。在數(shù)據(jù)傳輸中,如果發(fā)送端的發(fā)送速度大于接收端的接收速度,同時(shí)接收端處理數(shù)據(jù)的速度不夠快,那么接收端的緩沖區(qū)必定在一定時(shí)間后溢出,從而造成以后發(fā)送過來的數(shù)據(jù)不能進(jìn)入緩沖區(qū)而丟失。發(fā)送端何時(shí)可以繼續(xù)發(fā)送數(shù)據(jù),何時(shí)必須暫停發(fā)送,從而讓接收端有時(shí)間處理數(shù)據(jù),則必須靠握手信號來解決這個(gè)問題。例如,打印機(jī)和計(jì)算機(jī)進(jìn)行通信時(shí),一些打印機(jī)的打印速度可能跟不上計(jì)算機(jī)發(fā)送數(shù)據(jù)的速度,就必須通過握手信號通知計(jì)算機(jī)暫停發(fā)送數(shù)據(jù)。通常,串行通信握手的協(xié)議可以是硬件握手、軟件握手或二者的結(jié)合,具體如下所述。

1.硬件握手

在硬件握手中,發(fā)送端通過將某一條導(dǎo)線拉到高電平或者低電平,以表示發(fā)送端可以發(fā)送數(shù)據(jù)。接收端已經(jīng)準(zhǔn)備好接收數(shù)據(jù)之后,也把某一個(gè)導(dǎo)線拉到高電平或者是低電平,以通知發(fā)送端,發(fā)送端一直在檢測這個(gè)信號。接收端可以在任何時(shí)候把這個(gè)信號變?yōu)闊o效,甚至是在接收一個(gè)數(shù)據(jù)塊的過程中。當(dāng)發(fā)送端檢測到這個(gè)信號變?yōu)闊o效之后,就必須停止本次發(fā)送,直到這個(gè)信號變?yōu)橛行橹埂?/p>

2.軟件握手

在軟件握手中,以數(shù)據(jù)線上特定的數(shù)據(jù)信號來代替實(shí)際的硬件電路電平變化。這種方法用在直接連接或者通過調(diào)制解調(diào)器連接的兩臺計(jì)算機(jī)之間進(jìn)行雙向通信的場合。

對于軟件握手,現(xiàn)在已經(jīng)建立了一些標(biāo)準(zhǔn)協(xié)議,其中最常用的是通信協(xié)議。通信協(xié)議是指通信雙方的一種約定,包括對數(shù)據(jù)格式、同步方式、傳輸速度、傳輸步驟、檢/糾錯(cuò)方式以及控制字符定義等問題進(jìn)行統(tǒng)一規(guī)定,通信雙方必須共同遵守,也叫做通信控制規(guī)程或傳輸控制規(guī)程,它屬于OSI七層參考模型中的數(shù)據(jù)鏈路層。

3.軟硬結(jié)合握手

在使用個(gè)人計(jì)算機(jī)或終端設(shè)備通過調(diào)制解調(diào)器和主計(jì)算機(jī)進(jìn)行通信時(shí)(例如:對路由器進(jìn)行基于串口的遠(yuǎn)程配置的情況),一般會(huì)采用軟硬結(jié)合的握手。這種握手同時(shí)采用了硬件握手和軟件握手:一方面,個(gè)人計(jì)算機(jī)與調(diào)制解調(diào)器、主計(jì)算機(jī)與調(diào)制解調(diào)器之間,使用硬件握手方法進(jìn)行聯(lián)系;另一方面,主計(jì)算機(jī)和個(gè)人計(jì)算機(jī)之間將使用軟件握手方法進(jìn)行聯(lián)系。因此,個(gè)人計(jì)算機(jī)向主計(jì)算機(jī)傳輸數(shù)據(jù)時(shí),同時(shí)要考慮硬件和軟件握手。例如:在個(gè)人計(jì)算機(jī)通過調(diào)制解調(diào)器向主計(jì)算機(jī)發(fā)送數(shù)據(jù)時(shí),只有在調(diào)制解調(diào)器DSR(有時(shí)可能使用CD)線電位變高,且沒有收到來自主計(jì)算機(jī)的“停止傳輸”軟件信號時(shí),才送出數(shù)據(jù)。

一些計(jì)算機(jī)會(huì)自動(dòng)監(jiān)測硬件握手信號,所以應(yīng)用程序只需要處理軟件握手信號即可。但這種情況并不等于硬件握手不存在,依然是軟硬結(jié)合的握手。

現(xiàn)在的產(chǎn)品若要自動(dòng)化,一定要提供一個(gè)能與計(jì)算機(jī)進(jìn)行通信的通道。最簡單的方式就是在產(chǎn)品內(nèi)部燒上一顆單芯片,利用單芯片上的串行通信功能進(jìn)行自動(dòng)化的工作,由于計(jì)算機(jī)中的串口是必備的通道,且從價(jià)格及技術(shù)上來說是最能被廠商所接受的,因此,市面上很多自動(dòng)化產(chǎn)品也就加上了串行通信的功能,從而擴(kuò)大了產(chǎn)品的使用領(lǐng)域,使產(chǎn)品自動(dòng)化的實(shí)現(xiàn)技術(shù)變得簡單化。3.2串口通信程序設(shè)計(jì)3.2.1串行通信軟件工具

除了用戶自己動(dòng)手編寫串口通信軟件之外,目前也有一些現(xiàn)成的串口通信軟件工具。

1.超級終端程序

超級終端程序是Windows操作系統(tǒng)自帶的串口通信軟件,用戶可以選擇“開始/程序/附件/通信/超級終端”命令來調(diào)用它。使用超級終端程序需要對其進(jìn)行設(shè)置,設(shè)置步驟如下:

(1)首先按照“開始/程序/附件/通信”順序,執(zhí)行“超級終端”操作(對應(yīng)系統(tǒng)目錄“C:\ProgramFiles\WindowsNT”下的hypertrm.exe應(yīng)用程序),會(huì)出現(xiàn)一個(gè)本次聯(lián)機(jī)的名稱設(shè)置窗口(第一次使用該應(yīng)用程序時(shí),可能還會(huì)被要求設(shè)置國家、區(qū)號等屬性參數(shù)),在其中輸入名稱并選擇一個(gè)代表圖標(biāo)。此名稱通常應(yīng)使用易記的名稱來命名,以后再進(jìn)行聯(lián)機(jī)操作時(shí),只要加載該名稱,一切其它的設(shè)置就會(huì)恢復(fù)。

(2)然后在出現(xiàn)的界面中選擇所要連接的設(shè)備??梢愿鶕?jù)需要連接相應(yīng)的設(shè)備,可選得選項(xiàng)包括:COM、TCP/IP等,在這里選擇COM。

(3)在彈出的窗口中設(shè)置相關(guān)的參數(shù),如圖3-1所示。圖3-1超級終端參數(shù)設(shè)置

(4)單擊“確定”按鈕后,就會(huì)出現(xiàn)一個(gè)工作窗口,這說明已經(jīng)連接到需要連接的設(shè)備上。

設(shè)置完成后,會(huì)出現(xiàn)連接提示,包括連接時(shí)間、終端類型、連接參數(shù)等。如果串口不存在,或已被其他設(shè)備使用,超級終端就無法打開該端口,會(huì)顯示錯(cuò)誤提示。

用超級終端和其他的設(shè)備進(jìn)行連接時(shí),雙方互傳的數(shù)據(jù)以文字?jǐn)?shù)據(jù)為主,在正式用程序?qū)⒂?jì)算機(jī)和設(shè)備聯(lián)機(jī)之前,最好使用類似超級終端之類的程序先行做一些基本的測試,以確定使用字符串的通信沒有問題,然后再進(jìn)行控制。

2.窗口精靈軟件

窗口精靈軟件是一個(gè)極好的串口監(jiān)視與調(diào)試程序,適用于Win9X/NT平臺,能提高開發(fā)效率。它可以在線設(shè)置各種通信速度、奇偶校驗(yàn)、通信口而無需重新啟動(dòng)程序;可以設(shè)置定時(shí)發(fā)送的數(shù)據(jù)以及時(shí)間間隔;可以自動(dòng)顯示接收到的數(shù)據(jù),并能在字符串、十進(jìn)制和十六進(jìn)制之間自由切換;還能自動(dòng)保存設(shè)置參數(shù)。窗口精靈軟件是工程技術(shù)人員監(jiān)視、調(diào)試串口程序的必備工具。

3.串口調(diào)試助手

串口調(diào)試助手是在實(shí)際工程應(yīng)用中,根據(jù)實(shí)際的、普遍的需求而開發(fā)的串口調(diào)試工具,其界面精致美觀、實(shí)用性強(qiáng),支持各種串口設(shè)置,如波特率、校驗(yàn)位、數(shù)據(jù)位和停止位等。支持ASCII/Hex發(fā)送,發(fā)送和接收的數(shù)據(jù)可以在十六進(jìn)制和ASCII碼之間任意轉(zhuǎn)換??梢宰詣?dòng)在發(fā)送的數(shù)據(jù)末尾增加校驗(yàn)位,支持多種校驗(yàn)格式。支持間隔發(fā)送、循環(huán)發(fā)送和批處理發(fā)送,輸入的數(shù)據(jù)可以從外部文件導(dǎo)入,并且能夠自動(dòng)將接收到的數(shù)據(jù)保存到磁盤文件。

4.串口監(jiān)控器

串口監(jiān)控器是一個(gè)免費(fèi)的多功能串口通信監(jiān)控軟件,它能夠以多種方式顯示、接收、分析通信數(shù)據(jù);能夠以多種靈活方式發(fā)送數(shù)據(jù);具有方便的數(shù)據(jù)編輯功能。串口監(jiān)控器的特點(diǎn)是功能強(qiáng)大,操作簡單,在串口通信監(jiān)控、設(shè)備通信測試中,能夠很好地提高工作效率。它的主要功能如下:

(1)接收數(shù)據(jù);

(2)以十六進(jìn)制方式顯示接收到的數(shù)據(jù);

(3)以字符方式顯示接收到的數(shù)據(jù);

(4)數(shù)據(jù)幀自動(dòng)識別,分行顯示。

5.串口文件自動(dòng)發(fā)送/接收系統(tǒng)

當(dāng)要求隔離的兩個(gè)網(wǎng)絡(luò)之間需要經(jīng)常性地傳輸一些文件時(shí),若使用優(yōu)盤拷貝則費(fèi)時(shí)、費(fèi)力,使用網(wǎng)閘則動(dòng)輒花費(fèi)數(shù)萬至數(shù)十萬元,而此時(shí)使用“串口文件自動(dòng)發(fā)送/接收系統(tǒng)”不失為一種很好的解決方案。串口文件自動(dòng)發(fā)送/接收系統(tǒng)使用的是Zmodem文件傳輸協(xié)議,雖然速度不快,但不使用任何網(wǎng)絡(luò)協(xié)議。串口文件自動(dòng)發(fā)送/接收系統(tǒng)由發(fā)送端和接收端兩部分組成:發(fā)送端可設(shè)置需要傳輸?shù)奈募A和文件類型,支持定時(shí)檢測,當(dāng)發(fā)現(xiàn)新增文件或當(dāng)文件長度、創(chuàng)建時(shí)間發(fā)生變化時(shí),都會(huì)自動(dòng)地通過串口發(fā)送到接收端;接收端處在自動(dòng)接收狀態(tài),當(dāng)收到文件后會(huì)自動(dòng)將其保存到指定的文件夾中。

上述軟件在基于串口通信的工程實(shí)踐中發(fā)揮了巨大效益,使用范圍非常廣泛。下面我們將從串口操作函數(shù)入手,講解如何設(shè)計(jì)實(shí)現(xiàn)自己的串口通信程序。3.2.2串口操作API函數(shù)

在32位的Windows系統(tǒng)中,串口和其他通信設(shè)備都是作為文件進(jìn)行處理的。串口的打開、關(guān)閉、讀取和寫入所用的函數(shù)與操作文件的函數(shù)完全一樣。

1.打開串口

在通信過程中,程序是通過CreateFile()函數(shù)打開串口來進(jìn)行讀、寫或讀/寫訪問的。CreateFile()調(diào)用成功后返回一個(gè)句柄,這個(gè)句柄將會(huì)在后續(xù)操作中使用,可以打開已經(jīng)存在的文件、創(chuàng)建新文件和打開系統(tǒng)設(shè)備(例如:串口設(shè)備、并口設(shè)備和調(diào)制解調(diào)器等。注意:這些設(shè)備需正確安裝驅(qū)動(dòng),獲得系統(tǒng)合法I/O資源),它的原型如下:

HANDLECreateFile(

LPCTSTRlpFileName, //指向文件名的指針

DWORDdwDesiredAccess, //訪問模式(寫/讀)

DWORDdwShareMode, //共享模式

LPSECURITY_ATTRIBUTESlpSecurityAttributes,//指向安全屬性的指針

DWORDdwCreationDisposition,//如何創(chuàng)建

DWORDdwFlagsAndAttributes,//文件屬性

HANDLEhTemplateFile); //用于復(fù)制文件句柄函數(shù)調(diào)用成功后,返回一個(gè)HANDLE句柄,可以在串口后續(xù)操作中對其進(jìn)行調(diào)用,該句柄指向所開辟串口。

2.關(guān)閉串口

調(diào)用CloseHandle()函數(shù)即可關(guān)閉由CreateFile()函數(shù)返回的句柄。使用串口后一般要關(guān)閉串口,如果忘記關(guān)閉串口,串口就會(huì)始終處于打開狀態(tài),其他應(yīng)用程序就不能打開并使用串口了,其原型如下:

BOOLCloseHandle(HANDLEhObject); //指向需關(guān)閉的文件句柄

3.讀串口操作

程序可以使用Win32API的ReadFile()函數(shù)或者ReadFileEx()函數(shù)從串口中讀取數(shù)據(jù)。Readfile()函數(shù)對同步或異步操作都支持,而ReadFileEx()函數(shù)只支持異步操作。這兩個(gè)函數(shù)不受函數(shù)是否異步操作、超時(shí)操作等有關(guān)參數(shù)的影響和限制。利用Win32API讀/寫串口時(shí),既可同步執(zhí)行,也可以異步執(zhí)行。同步執(zhí)行時(shí),函數(shù)直到操作完成后才返回,這意味著在同步執(zhí)行時(shí)線程會(huì)被阻塞,從而導(dǎo)致效率變低。異步執(zhí)行時(shí),即使操作還未完成,調(diào)用的函數(shù)也會(huì)立即返回并交出控制權(quán),把費(fèi)時(shí)的I/O操作安排在后臺進(jìn)行,這樣就可以提高工作效率。ReadFile()的原型如下(ReadFilEx()與之非常類似):

BOOLReadFile( HANDLEhFile,//文件的句柄

LPVOIDlpBuffer, //用于保存讀入數(shù)據(jù)的一個(gè)緩沖區(qū)

DWORDnNumberOfBytesToRead, //要讀入的字符數(shù)

LPDWORDlpNumberOfBytesRead, //指向?qū)嶋H讀取字節(jié)數(shù)的指針

LPOVERLAPPEDlpOverlapped); //異步讀取操作數(shù)據(jù)結(jié)構(gòu)體指針

Windows9X/NT/2000中讀/寫串口時(shí)引入了超時(shí)結(jié)構(gòu)。超時(shí)結(jié)構(gòu)直接影響讀/寫操作行為。當(dāng)事先設(shè)定的超時(shí)間隔消失時(shí),ReadFile()、ReadFileEx()、WriteFile()和WriteFileEx()函數(shù)操作仍未結(jié)束,那么超時(shí)設(shè)置將無條件結(jié)束讀/寫操作,而不管是否已讀出或已寫入指定數(shù)量的字符。在讀/寫操作期間發(fā)生的超時(shí)將不按錯(cuò)誤處理,即讀/寫操作返回指定成功的值。對于同步讀/寫操作,實(shí)際傳輸?shù)淖止?jié)數(shù)由ReadFile()和WriteFile()函數(shù)報(bào)告。對于異步操作,則由OVERLAPPED結(jié)構(gòu)來獲取。該結(jié)構(gòu)定義如下:

typedefstruct_OVERLAPPED{ DWORDInternal; //操作系統(tǒng)保留,指出系統(tǒng)相關(guān)狀態(tài)

DWORDInternalHigh; //指出發(fā)送或接收的數(shù)據(jù)長度

DWORDOffset; //文件傳送的開始位置

DWORDOffsetHigh; //文件傳送的字節(jié)偏移量的高位字

HANDLEhEvent //指定一個(gè)I/O操作完成后觸發(fā)的事件

}OVERLAPPED

可以使用下面函數(shù)獲得超時(shí)設(shè)定時(shí)間:

BOOLGetCommTimeouts(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPCOMMTIMEOUTSlpCommTimeouts); //超時(shí)結(jié)構(gòu)體指針

可以使用下面函數(shù)設(shè)置超時(shí):

BOOLSetCommTimeouts(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPCOMMTIMEOUTSlpCommTimeouts); //超時(shí)結(jié)構(gòu)體指針

4.寫串口操作

可以使用Win32API的函數(shù)WriteFile()或者WriteFileEx()向串口中寫數(shù)據(jù)。WriteFile()函數(shù)對同步或異步操作都支持,而WriteFileEx()函數(shù)只支持異步操作。這兩個(gè)函數(shù)都受函數(shù)是否異步操作、超時(shí)操作等有關(guān)參數(shù)的影響和限制。WriteFile()函數(shù)原型如下:

BOOLWriteFile(HANDLEhFile, //文件句柄

LPCVOIDlpBuffer, //數(shù)據(jù)緩存區(qū)指針

DWORDnNumberOfBytesToWrite, //需寫入的字節(jié)數(shù)

LPDWORDlpNumberOfBytesWritten, //實(shí)際寫入字節(jié)數(shù)的存儲區(qū)域指針

LPOVERLAPPEDlpOverlapped); //OVERLAPPED結(jié)構(gòu)體指針

5.通信狀態(tài)操作

獲取串口狀態(tài)使用GetCommState()函數(shù),該函數(shù)原型如下:

BOOLGetCommState(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPDCBlpDCB);//驅(qū)動(dòng)控制塊結(jié)構(gòu)指針

串口的狀態(tài)在成功調(diào)用上述函數(shù)后,將被放入一個(gè)類型名為DCB的結(jié)構(gòu)體,結(jié)構(gòu)體成員定義如下:

typedefstruct_DCB{DWORDDCBlength; //DCB長度

DWORDBaudRate; //指定當(dāng)前的波特率

DWORDfBinary:1; //指定是否允許二進(jìn)制模式

DWORDfParity:1; //指定奇偶校驗(yàn)是否允許

DWORDfOutxCtsFlow:1; //指定Cts是否用于檢測發(fā)送控制

DWORDfOutxDsrFlow:1; //指定Dsr是否用于檢測發(fā)送控制

DWORDfDtrControl:2; //Dtr流控制類型

DWORDfDsrSensitivity:1; //Dsrsensitivity

DWORDfTXContinueOnXoff:1; //XOFF信號時(shí)發(fā)送是否停止

DWORDfOutX:1; //Xon/Xoff流出

DWORDfInX:1; //Xon/Xoff流入控制

DWORDfErrorChar:1; //是否用ErrorChar成員代替錯(cuò)誤字符

DWORDfNull:1; //接收時(shí)是否去掉空(0值)字節(jié)

DWORDfRtsControl:2; //Rts流控制

DWORDfAbortOnError:1; //有錯(cuò)誤發(fā)生時(shí)是否終止讀和寫操作

DWORDfDummy2:17; //保留未用

WORDwReserved; //未使用,必須為0

WORDXonLim; //傳輸Xon字符發(fā)送之前的接收緩沖區(qū)

//中可允許的最小字節(jié)數(shù)

WORDXoffLim; //傳輸Xoff字符發(fā)送之前的接收緩沖區(qū) //中可允許的最小字節(jié)數(shù)

BYTEByteSize; //指定端口當(dāng)前使用的數(shù)據(jù)位

BYTEParity;//指定端口當(dāng)前使用的奇偶校驗(yàn)方法

BYTEStopBits;//指定端口當(dāng)前使用的停止

位數(shù)

charXonChar;//指定用于發(fā)送和接收字符的Xon值

charXoffChar;//指定用于發(fā)送和接收字符的Xoff值

charErrorChar;//代替奇偶校驗(yàn)發(fā)生錯(cuò)誤時(shí)的字符值

charEofChar; //輸入字符結(jié)束

charEvtChar; //當(dāng)接收到此字符時(shí)產(chǎn)生一個(gè)事件

WORDwReserved1;//保留未用

}DCB;

也可人工填寫好DCB結(jié)構(gòu),通過調(diào)用下面函數(shù)設(shè)置串口狀態(tài):

BOOLSetCommState(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPDCBlpDCB);//驅(qū)動(dòng)控制塊結(jié)構(gòu)指針

函數(shù)調(diào)用成功,返回TRUE;否則返回FALSE。

6.串口數(shù)據(jù)清除

串口數(shù)據(jù)清除函數(shù)用于清除串口的錯(cuò)誤信息。如果在串口通信中發(fā)生錯(cuò)誤,如終端、奇偶錯(cuò)誤等,I/O操作將會(huì)終止。如果程序要進(jìn)一步執(zhí)行I/O操作,則必須調(diào)用ClearCommError()函數(shù),它有兩個(gè)作用:清除錯(cuò)誤條件和確定串口通信狀態(tài)。ClearCommError()函數(shù)原型如下:

BOOLClearCommError(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPDWORDlpErrors, //接收錯(cuò)誤碼變量指針

LPCOMSTATlpStat); //通信狀態(tài)存儲區(qū)指針清除串口緩沖區(qū)可通過下面函數(shù)來實(shí)現(xiàn):

BOOLPurgeComm(HANDLEhFile, //通信資源句柄

DWORDdwFlags); //執(zhí)行動(dòng)作

函數(shù)調(diào)用成功后,返回TRUE,代表接收緩存區(qū)被成功清空;否則返回FALSE。

7.串口事件操作

串口事件操作函數(shù)為某一個(gè)驅(qū)動(dòng)器設(shè)置事件,當(dāng)事件發(fā)生時(shí),觸發(fā)并通知主程序??蛇x的事件有EV_BREAK、EV_CTS等(見表3-2)。監(jiān)控的事件可以是“|”聯(lián)結(jié)或多個(gè)事件的組合,如EV_RXCHAR|EV_TXEMPTY。函數(shù)結(jié)構(gòu)如下:

BOOLSetCommMask(HANDLEhFile, //通信驅(qū)動(dòng)句柄

DWORDdwEvtMask); //串口事件掩碼

可使用下面函數(shù)對某事件進(jìn)行查找:

BOOLGetCommMask(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPDWORDlpEvtMask); //接收事件變量指針

事件設(shè)置完畢后,可以調(diào)用下面函數(shù)等待驅(qū)動(dòng)器上設(shè)置的事件的發(fā)生:

BOOLWaitCommEvent(HANDLEhFile, //通信驅(qū)動(dòng)句柄

LPDWORDlpEvtMask, //接收事件變量指針

LPOVERLAPPEDlpOverlapped,); //重疊結(jié)構(gòu)體指針

SetCommMask的調(diào)用會(huì)導(dǎo)致正在監(jiān)聽的WaitCommEvent()立即返回。表3-2串口可選的事件

通常,串口通信可以分為以下幾個(gè)步驟,按這些步驟操作就可以創(chuàng)建自己的串口通信傳輸軟件了。

(1)設(shè)置串口號碼,使用CreateFile()函數(shù)打開串口;

(2)設(shè)置傳輸速度等參數(shù);

(3)設(shè)置超時(shí)參數(shù);

3.3串口通信程序設(shè)計(jì)

(4)設(shè)置事件掩碼來監(jiān)視指定通信端口上的事件;

(5)監(jiān)控事件并寫出或讀入字符串,可以使用WriteFile()及ReadFile()函數(shù);

(6)使用完畢后用CloseHandle()函數(shù)將串口關(guān)閉。

由于使用WindowsAPI中的函數(shù)作為串行通信的基礎(chǔ),使用CreateFile()函數(shù)打開串口后的返回值是一個(gè)數(shù)值(稱為Handle),在往后的函數(shù)中,只要是和該串口有關(guān)的操作與設(shè)置,一定要使用到這個(gè)Handle。這個(gè)Handle就是在串口成功打開后,由操作系統(tǒng)配置的一個(gè)代碼,程序所要求的操作也必須通過出示這個(gè)代碼才得以進(jìn)行。換句話說,就是把這個(gè)分配到的Handle視為該串口的代表,當(dāng)對該Handle進(jìn)行操作時(shí),操作系統(tǒng)會(huì)代為轉(zhuǎn)向到實(shí)際的硬件對象(也就是COM1或COM2)上去。3.3.1枚舉本地機(jī)串口

串口的使用具有隨機(jī)性,也就是用戶在進(jìn)行串口編程的時(shí)候并不知道哪一個(gè)串口處于連接狀態(tài),因此有必要對本地所有串口進(jìn)行枚舉。枚舉的方法主要是查詢注冊表中HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM\\下的鍵值。

下面程序?qū)崿F(xiàn)了對該鍵值的查詢和屏幕打印,使用了RegOpenKeyEx()、RegEnumValue()、RegCloseKey()等三個(gè)注冊表操作函數(shù)。除了實(shí)現(xiàn)枚舉COM口的功能外,對于網(wǎng)絡(luò)程序設(shè)計(jì)中其他相關(guān)的注冊表操作也有借鑒作用。

#include"stdafx.h"

#include"windows.h"http://不要使用winreg.h,因其版本太舊容易引起錯(cuò)誤

intmain(intargc,char*argv[])

{

charstrSerialList[256][25];

//臨時(shí)定義256個(gè)字符串組,因?yàn)橄到y(tǒng)最多也就256個(gè)

ERROR_SUCCESSHKEYhKey;

LPCTSTRdata_Set="HARDWARE\\DEVICEMAP\\SERIALCOMM\\";

longret0=RegOpenKeyEx(HKEY_LOCAL_MACHINE,data_Set,0,KEY_READ,&hKey);

if(ret0!=ERROR_SUCCESS)return-1;

DWORDcValues;

//獲取"HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM\\"鍵值下項(xiàng)數(shù)目

RegQueryInfoKey(hKey,NULL,NULL,NULL,NULL,NULL,NULL,&cValues,NULL,

NULL,NULL,NULL);

CHARName[256];

UCHARszPortName[256];

LONGStatus;

DWORDdwIndex=0;

DWORDdwName;

DWORDdwSizeofPortName;

DWORDType;

dwName=sizeof(Name);

dwSizeofPortName=sizeof(szPortName);

for(DWORDi=0;i<cValues;i++)

{

dwName=sizeof(Name); //一定要在每一次調(diào)用RegEnumValue時(shí)都要初始化!!!

dwSizeofPortName=sizeof(szPortName);

ZeroMemory(Name,256);

ZeroMemory(szPortName,256);

Status=RegEnumValue(hKey,i,Name,&dwName,NULL,&Type,szPortName,

&dwSizeofPortName);

if(ERROR_SUCCESS!=Status)break;

strcpy(&strSerialList[i][0],(char*)szPortName);//串口字符串保存

printf("%s\n",&strSerialList[i][0]);

}

RegCloseKey(hKey);

//…COM調(diào)用

return0;

}

程序執(zhí)行后,COM將會(huì)填入strSerialList數(shù)組,以便后續(xù)調(diào)用。有時(shí)管理員會(huì)因安全原因關(guān)閉所有COM口,那么上述程序則無法查詢到任何端口。3.3.2主機(jī)與單片機(jī)間的通信

下面程序?qū)崿F(xiàn)了主機(jī)與單片機(jī)之間的單工通信,有很多應(yīng)用都是采用這種方式工作的,如主機(jī)從傳感器中接收采集信息。假設(shè)連接于PC的COM4端口,該程序監(jiān)聽一個(gè)基

于單片機(jī)無線接收器接收到的信號,接收數(shù)據(jù)由read_com()函數(shù)實(shí)現(xiàn)(假設(shè)最多接收256個(gè)字節(jié))。

#include"stdafx.h"

#include<shlobj.h>

DWORDread_com(HANDLEhCom,char*Buffer)

{

COMSTATComStat;

DWORDdwErrorFlags;

BOOLbResult;

DWORDnBytesToRead=256;

DWORDnBytesRead;

ClearCommError(hCom,&dwErrorFlags,&ComStat);

bResult=ReadFile(hCom,Buffer,nBytesToRead,&nBytesRead,NULL);

returnnBytesRead;

}

intmain(intargc,char*argv[])

{

HANDLEhCom;

charcom[10]="\\\\.\\COM4";

//1.以同步讀/寫方式打開串口COM4,這里的\\\\.\\COM4是COM的全名,最好寫成這樣

hCom=CreateFile(com, //打開串口COM4

GENERIC_READ|GENERIC_WRITE, //允許進(jìn)行讀/寫操作

0, //獨(dú)占方式

NULL,

OPEN_EXISTING, //打開一個(gè)存在的串口

0,

NULL);

//2.將串口設(shè)置為:波特率為9600,數(shù)據(jù)位數(shù)為7位,停止位為2位,偶校驗(yàn),接收

//緩沖區(qū)和發(fā)送緩沖區(qū)的大小均為1024個(gè)字節(jié),最后用PurgeComm函數(shù)終止所有的后臺

//讀/寫操作并清空接收緩沖區(qū)和發(fā)送緩沖區(qū)

DCBdcb;

GetCommState(hCom,&dcb); //必須調(diào)用一下GetCommState才能使SetCommState的

//返回值不為0?。?!

dcb.BaudRate=9600; //波特率為9600

dcb.ByteSize=7; //數(shù)據(jù)位數(shù)為7位

dcb.Parity=EVENPARITY; //偶校驗(yàn)

dcb.StopBits=2; //兩個(gè)停止位

dcb.fBinary=TRUE;

dcb.fParity=TRUE;

if(SetCommState(hCom,&dcb)==0)

{

MessageBox(NULL,"串口連接不正確!",NULL,MB_OK);

return0;

}

SetupComm(hCom,1024,1024);//設(shè)置串口緩沖區(qū)的大小為1024位

PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|

PURGE_TXCLEAR|PURGE_RXCLEAR); //清空串口緩沖區(qū)

//3.程序?qū)⒋谧x操作的超時(shí)設(shè)定為10毫秒

COMMTIMEOUTSto;

memset(&to,0,sizeof(to));

to.ReadIntervalTimeout=10;

SetCommTimeouts(hCom,&to);

//4.設(shè)置事件掩碼來監(jiān)視指定通信端口上的事件

SetCommMask(hCom,EV_RXCHAR|EV_TXEMPTY|EV_BREAK);

OVERLAPPEDov;

DWORDlpEvtMask;

charrcvbuff[256];

ZeroMemory(&ov,sizeof(ov));

intread_num=0;

ov.hEvent=CreateEvent(0,true,0,0);

do

{

PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|

PURGE_TXCLEAR|PURGE_RXCLEAR);

//5.等待串口上出現(xiàn)了利用SetCommMask()函數(shù)設(shè)置的事件

WaitCommEvent(hCom,&lpEvtMask,&ov);//程序在此阻塞,直到COM中接收到數(shù)據(jù)

if((lpEvtMask&EV_BREAK)==EV_BREAK)

{

printf("串口斷開!\n");

break;

}

read_num=read_com(hCom,rcvbuff);

if(read_num==0)continue;

//...接收數(shù)據(jù)處理

ZeroMemory(rcvbuff,256);

}while(1);

//6.關(guān)閉串口

CloseHandle(hCom);

return0;

}

注意:在接收數(shù)據(jù)前,必須根據(jù)監(jiān)控設(shè)備的有關(guān)通信參數(shù)約定雙方的通信方式,包括各種參數(shù)的設(shè)置,如程序中的步驟2。3.3.3主機(jī)間的通信

以下程序可以實(shí)現(xiàn)兩臺主機(jī)之間的串口數(shù)據(jù)傳輸,可用于計(jì)算機(jī)與路由器或交換機(jī)進(jìn)行交互。在無網(wǎng)絡(luò)可用的時(shí)候應(yīng)急用。與3.3.1節(jié)中的程序功能不完全相同,最大的區(qū)別就是該程序是雙工的。連接線采用TXD與RXD交叉相連、GND共線的方法。程序代碼如下(下面主要列出了與3.3.1節(jié)中不同的代碼):

DWORDwrite_com(HANDLEhCom,char*Buffer)

{

OVERLAPPEDm_ov;

BOOLbResult;

DWORDnBytesToSend=strlen(Buffer);

DWORDnBytesSend;

charbuff[10];

m_ov.Offset=0;

m_ov.OffsetHigh=0;

PurgeComm(

hCom,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|

PURGE_TXABORT);

bResult=WriteFile(hCom,buff,nBytesToSend,&nBytesSend,&m_ov);//Overlappedstructure

returnnBytesSend;

}

intmain(intargc,char*argv[])

{

HANDLEhCom;

charcom[10]="\\\\.\\COM4";

//1.以同步讀/寫方式打開串口COM4,這里的\\\\.\\COM4是COM的全名,最好寫成這樣

hCom=CreateFile(com, //打開串口COM4

GENERIC_READ|GENERIC_WRITE, //允許進(jìn)行讀/寫操作

0, //獨(dú)占方式

NULL,

OPEN_EXISTING, //打開一個(gè)存在的串口

FILE_FLAG_OVERLAPPED, //設(shè)置為異步串口

NULL);

…//與3.3.2節(jié)的程序相同

//4.設(shè)置事件掩碼來監(jiān)視指定通信端口上的事件

SetCommMask(hCom,EV_RXCHAR|EV_TXEMPTY|EV_BREAK);

OVERLAPPEDov;

DWORDlpEvtMask;

charbuff[256];

ZeroMemory(&ov,sizeof(ov));

DWORDEvent;

DWORDCommEvent=0;

intread_num=0;

HANDLE m_hEventArray[2];

HANDLE WriteEvent={0};

HANDLE ExitEvent={0};

ov.hEvent=CreateEvent(0,true,0,0);

PurgeComm(hCom,URGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|

PURGE_RXCLEAR);

m_hEventArray[0]=ov.hEvent;

m_hEventArray[1]=WriteEvent;

m_hEventArray[2]=ExitEvent;

//5.等待串口上出現(xiàn)讀、寫和關(guān)閉串口等三類事件

do

{

if(WaitCommEvent(hCom,&lpEvtMask,&ov)==0) //因?yàn)閔Com為異步模式,所以在

//這里不會(huì)阻塞

{

printf("WaitCommEventiserror!\n");

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論