?? 190.htm
字號:
<p>使用Visual Basic開發通訊軟件</p>
<p></p>
<p>一、pc串行通信程序機制 </p>
<p></p>
<p>常用的pc串行通信程序大多利用biosint14h中斷,以查詢i/o方式完成異步串行通信。 </p>
<p></p>
<p></p>
<p>windows系統提供中斷方式驅動的串行通信驅動程序comm.drv。通信程序無需直接對串行端口進行操作,而是通過驅動程序這一編程接口進行間接操作。 </p>
<p></p>
<p></p>
<p>windows操作系統中,串行通信采用“事件通知”方式,支持數據按塊傳送。進行通信時,windows開辟一個用戶定義的輸入輸出緩沖區,每接收一個字符就產生一個低級硬件中斷,串行驅動程序立即取得控制權,并將字符放入輸入數據緩沖區,然后將控制權返還正在運行的應用程序。如果輸入數據緩沖區滿了,驅動程序用當前定義的流控制機制通知發送方停止發送數據。發送數據也采用類似的處理方式,應用程序將需要發送的數據放入輸出數據緩沖區,串口每發送一個字符就產生一個低級硬件中斷。 </p>
<p></p>
<p></p>
<p>二、pc串行口遠程通信的硬件配置 </p>
<p></p>
<p></p>
<p>串行通信數據鏈中,計算機一端稱為dte,即數據終端設備;調制解調器一端稱為dce,即數據通信設備。pc串行通信的硬件連接方式分為零modem連接和modem連接。 </p>
<p></p>
<p></p>
<p>零modem連接即直接用調制解調器電纜將兩臺設備連接起來,modem連接則通過dce(modem)將兩臺pc連接起來。 </p>
<p></p>
<p></p>
<p>零modem連接用于距離15m內兩臺dte或dce設備之間的連接。而modem連接則通過電話網或專線用于長距離的通信。 </p>
<p></p>
<p></p>
<p>txd和rxd信號線用于計算機和modem間傳輸數據信息;rts從計算機端發送信號到modem,表示希望把數據傳給modem,若modem能接收這個數據,它將發送cts信號給計算機;dtr從計算機端發送信號到modem,表示計算機已作好通信準備,modem將dtr信號作為初始化自己的信號,然后給計算機回送數據設置就緒信號dsr;當本地modem接收到遠地modem的呼叫,則發送ring信號給計算機;modem應答呼叫后,發送數據載波檢測dcd信號到計算機,表示已建立連接。 </p>
<p></p>
<p></p>
<p>modem的工作狀態分為命令狀態和在線狀態。處于命令狀態時,modem對串口發送的信息進行解釋,可通過pc串口向modem發送at命令對其進行初始化、設置和操作。 </p>
<p></p>
<p></p>
<p>例如,初始化命令為:“atqov1wosoκ1&c1&d2&yo&wo”,其含義為: </p>
<p></p>
<p></p>
<p>qo:返回結果碼; </p>
<p></p>
<p></p>
<p>v1:以字符形式顯示結果碼; </p>
<p></p>
<p></p>
<p>wo:不返回協商進程結果碼; </p>
<p></p>
<p></p>
<p>soκ1:振鈴一次,即應答; </p>
<p></p>
<p></p>
<p>&c1:追蹤數據載波信號cd; </p>
<p></p>
<p></p>
<p>&d2當dtr從開到關時,modem掛機進入命令狀態; </p>
<p></p>
<p></p>
<p>&yo:modem上電時重新調出用戶方案; </p>
<p></p>
<p></p>
<p>&wo:將以上設置存為動態設置用戶方案0; </p>
<p></p>
<p></p>
<p>一旦本地modem與遠地modem建立連接,modem即處于在線狀態,可進行數據傳輸。此時,modem不響應at命令,直接傳送所收到的數據。 </p>
<p></p>
<p></p>
<p>三、modem連接遠程通信軟件的編制 </p>
<p></p>
<p></p>
<p>通信過程中大部分的工作由串行通信驅動軟件承擔。 </p>
<p></p>
<p></p>
<p>本文軟件的運行環境為ast+4/66d,hayes公司的accura144+fax144modem,windows3.2,vb3.0專業版。vb3.0專業版中提供了一個mscomm.vbx通信控件。它使用戶能很方便地通過對控件屬性的設置、檢測,訪問串行通信驅動程序的大多數特性,而不必考慮其實現細節。該控件為“事件驅動”,只響應“oncomm”事件,該事件可對已發生的事件或錯誤進行處理,與commevent屬性緊密相關。 </p>
<p></p>
<p></p>
<p>通信軟件、通信驅動軟件和modem之間的通信關系 </p>
<p></p>
<p></p>
<p>以下程序實現了通信的基本過程。包括初始化串口和modem,上位機撥號呼叫下位機,下位機應答并開始定時傳輸數據,掛機停止傳輸等功能。 </p>
<p></p>
<p></p>
<p>vb3.0編制的通信軟件清單如下: </p>
<p></p>
<p></p>
<p>上位機控件清單: </p>
<p></p>
<p></p>
<p>控件名稱 屬性 </p>
<p></p>
<p></p>
<p>form1form1caption ″上位機通信″ </p>
<p></p>
<p></p>
<p>mscomm comm1 </p>
<p></p>
<p></p>
<p>commandbutton1callcaption ″撥號″ </p>
<p></p>
<p></p>
<p>commandbutton2hangcaption ″掛機″ </p>
<p></p>
<p></p>
<p>commandbutton3exitcaption ″退出″ </p>
<p></p>
<p></p>
<p>下位機控件清單 </p>
<p></p>
<p></p>
<p>控件名稱 屬性 </p>
<p></p>
<p></p>
<p>form1form1caption ″下位機通信″ </p>
<p></p>
<p></p>
<p>mscomm comm1 </p>
<p></p>
<p></p>
<p>commandbutton1hangcaption ″掛機″ </p>
<p></p>
<p></p>
<p>commandbutton2exitcaption ″退出″ </p>
<p></p>
<p></p>
<p>timer1timer1interval 3000 </p>
<p></p>
<p></p>
<p>text(i)text(i) </p>
<p>使用Visual Basic開發通訊軟件 </p>
<p></p>
<p></p>
<p>[enet學院] </p>
<p></p>
<p></p>
<p><<<上一頁 </p>
<p></p>
<p></p>
<p>1.串口初始化、設置程序 </p>
<p></p>
<p></p>
<p>在程序初始化時,先對串口初始化。因為使用rts/cts握手信號的硬件設備只有rts信號置為高才能接收數據,所以需將mscomm通信控件的rtsenable屬性設為true。由于modem在處于命令狀態時,通過串口發送的命令以及命令結果均會回顯在輸入緩沖區中,因此在進入在線狀態前,禁止產生ev-receive事件,避免數據誤處理。 </p>
<p></p>
<p></p>
<p>由于windows是多任務系統,在進行數據收發循環處理時,應調用doevents事件,將控制權交還系統,允許windows執行其他任務。但應注意,在處理oncomm事件時小心使用doevents,避免系統又產生oncomm事件,造成嵌套,出現堆棧溢出錯誤。 </p>
<p></p>
<p></p>
<p>sub form-load() </p>
<p></p>
<p></p>
<p>comm1.commportκ1′com1口通信 </p>
<p></p>
<p></p>
<p>comm1.settingsκ″9600,n,8,1″′波特率9600,無校驗,8位數據位1位停止位 </p>
<p></p>
<p></p>
<p>comm1.outbuffersizeκoutpack′設置輸出緩沖區大小 </p>
<p></p>
<p></p>
<p>comm1.inbuffersizeκinpack′設置輸入緩沖區大小 </p>
<p></p>
<p></p>
<p>comm1.inputlenκ1′每次從輸入緩沖區中取一個字符 </p>
<p></p>
<p></p>
<p>comm1.rtsenableκ-1′rts信號為高 </p>
<p></p>
<p></p>
<p>comm1.rthresholdκ0′不產生mscomm-ev-receive事件 </p>
<p></p>
<p></p>
<p>comm1.portopenκ-1′打開串口 </p>
<p></p>
<p></p>
<p>cdκcomm1.cdholding′取載波檢測信號線原始狀態 </p>
<p></p>
<p></p>
<p>comm1.outputκ″atqov1wosoκ1&c1&d2&yowo″′初始化modem </p>
<p></p>
<p></p>
<p>do doeventsloopuntilcomm1.outbuffercountκ0 </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>2.上位機撥號呼叫下位機 </p>
<p></p>
<p></p>
<p>subcallcom-click() </p>
<p></p>
<p></p>
<p>comm1.outputκ″atdt″&phonnum$&chr$(13)′向modem發撥號命令 </p>
<p></p>
<p></p>
<p>do doeventsloopuntilcomm1.outbuffercountκ0 </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>3.下位機modem應答,連通后開始定時傳輸數據 </p>
<p></p>
<p></p>
<p>下位機檢測cd,判斷是否連通: </p>
<p></p>
<p></p>
<p>sub comm1-oncomm() </p>
<p></p>
<p></p>
<p>select casecomm1.commevent </p>
<p></p>
<p></p>
<p>case5 ′mscomm-ev-cd </p>
<p></p>
<p></p>
<p>timer1.enabledκ-1′啟動定時器 </p>
<p></p>
<p></p>
<p>end select </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>vb傳送定長字符串,數據接收處理相對簡單。但在發送實時數據時,若將數據轉換成定長字符串,這樣會大大降低傳輸效率。在接收端,通知程序從輸入緩沖區中取字符有兩種方法:一是用輪詢方法循環判斷inbuffercount是否為0;另外就是利用rthreshold屬性觸發“oncomm”事件及“commevent”屬性中ev-receive事件。當rthreshold的值不為0時,允許產生ev-receive事件。該屬性設置和返回在通信控件設定commevent特性為接收和產生oncomm事件之前要接收的字符數。vb傳送變長字符串時,接收端的rthreshold值要作相應的改變,以確保接收數據及時準確。 </p>
<p></p>
<p></p>
<p>下位機定時發送字符串“strin3$κformat$(len(strin1$),″0000″)&chr$(8)&strin2$”。strin1$為當前字符串,strin2$為上一字符串。上位機根據接收strin3$中len(strin1$),相應改變rthresholdκlen(strin1$)+4。這樣,通過提前發送字符串長度,改變rthreshold值可實現發送變長數據。 </p>
<p></p>
<p></p>
<p>windows串行通信驅動程序的事件驅動特性仍有不穩定的缺陷。如inputlenκ0時,有可能取出不完整的數據。為保證可靠,采取降低處理速率的方法,保證下位機發送的數據流完整地進入輸入緩沖區。設inputlenκ1,即每次從緩沖區中取一個字符。也可采用輪詢方法,定時檢測輸入緩沖區。下位機定時發送數據: </p>
<p></p>
<p></p>
<p>sub timer1-timer() </p>
<p></p>
<p></p>
<p>if comm1.cdholdingιλcdthen </p>
<p></p>
<p></p>
<p>str1$-text1(i).text </p>
<p></p>
<p></p>
<p>strin2$κstrin1$′上一字符串 </p>
<p></p>
<p></p>
<p>strin1$κstr1$′當前字符串 </p>
<p></p>
<p></p>
<p>strin3$κformat$(len(strin1$),″0000″)&chr$(8)&strin2$ </p>
<p></p>
<p></p>
<p>′傳送當前字符串長度,以及上一字符串內容 </p>
<p></p>
<p></p>
<p>com m1.outputκstrin3$ </p>
<p></p>
<p></p>
<p>do doeventsloopuntilcomm1.outbuffercountκ0 </p>
<p></p>
<p></p>
<p>else </p>
<p></p>
<p></p>
<p>timer1.enabledκ0 </p>
<p></p>
<p></p>
<p>end if </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>上位機檢測cd狀態,判斷是否連通、并接收處理數據。 </p>
<p></p>
<p></p>
<p>sub comm1-oncomm() </p>
<p></p>
<p></p>
<p>select case comm1.commevent </p>
<p></p>
<p></p>
<p>case5 ′mscomm-ev-cd檢測cd狀態,判斷是否連通 </p>
<p></p>
<p></p>
<p>comm1.inbuffercountκ0′清輸入緩沖區 </p>
<p></p>
<p></p>
<p>comm1.rthresholdκ4′當輸入緩沖區中有五個字符, </p>
<p></p>
<p></p>
<p>case2′mscomm-ev-receive產生ev-receive事件,接收處理數據 </p>
<p></p>
<p></p>
<p>do doevents </p>
<p></p>
<p></p>
<p>ifcomm1.inbuffercountthen′循環從緩沖區中取數據 </p>
<p></p>
<p></p>
<p>str1$κstr1$+comm1.input </p>
<p></p>
<p></p>
<p>else </p>
<p></p>
<p></p>
<p>exit do </p>
<p></p>
<p></p>
<p>end if </p>
<p></p>
<p></p>
<p>loop </p>
<p></p>
<p></p>
<p>len2κ1en1′當前字符串長度 </p>
<p></p>
<p></p>
<p>len1κva1(left$(str1$,5))′即將發送的字符串長度 </p>
<p></p>
<p></p>
<p>comm1.rthresholdκlen1+4 </p>
<p></p>
<p></p>
<p>strin$κright$(str1$,len2)′數據處理 </p>
<p></p>
<p></p>
<p>…… </p>
<p></p>
<p></p>
<p>end select </p>
<p></p>
<p></p>
<p>str1$κ″″ </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>4.根據設置的at命令“&d2”,當置dtr信號為低時,modem掛機進入命令狀態。也可通過串口輸出““+++ath”+chr$(13)”字符串掛機。 </p>
<p></p>
<p></p>
<p>sub hang-click() </p>
<p></p>
<p></p>
<p>if comm1.cdholdingιλcdthen′檢測cd,判斷是否掛機 </p>
<p></p>
<p></p>
<p>comm1.dtrenableκ0 </p>
<p></p>
<p></p>
<p>comm1.dtrenableκ-1′置dtr信號為高,為下一次通信準備 </p>
<p></p>
<p></p>
<p>end if </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>5.退出程序時,一定要關閉串口 </p>
<p></p>
<p></p>
<p>sub exitcomm() </p>
<p></p>
<p></p>
<p>comm1.portopenκfalse </p>
<p></p>
<p></p>
<p>end </p>
<p></p>
<p></p>
<p>end sub </p>
<p></p>
<p></p>
<p>四、windows通信機制和vb3.0通信控件潛在缺陷 </p>
<p></p>
<p></p>
<p>在通信軟件編制過程中,我們發現windows下通信機制采用的“事件驅動”在實際運行中不穩定。如在文件傳輸過程中,誤碼和數據丟失的情況時有發生;若串口波特率過高,會產生無法通信或在通信過程中隨機掛機的情況。這主要是由于windows本身通信機制和通信線路介質及質量的影響。為保證數據傳輸穩定可靠,可采用通信協議如xmodem-crc或ymodem。在mscomm.vbx通信控件中,rthreshold屬性值大小與輸入緩沖區inbuffersize大小有關,當rthreshold值較接近inbuffersize值時,有可能不產生ev-receive事件,為保證產生該事件,可將inbuffersize值取得較大。 </p>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -