基于Windows環(huán)境的實時串行通訊
基于Windows環(huán)境的實時串行通訊
一、概述
隨著電力電子技術和計算機技術的發(fā)展,各種各樣的智能終端也出現(xiàn)了。但智能終端管理功能較小,需要將其檢測與控制的參數(shù)送到計算機上進行管理,為克服各廠家設備的不兼容性,一般采用標準RS-232C接口串行通訊來傳送數(shù)據(jù),由于在實時性方面具有嚴格的要求,所以大多數(shù)的工控軟件還是基于DOS環(huán)境的,其綜合性能對于Windows程序就弱一些,造成這種現(xiàn)象的原因在于,在Windows環(huán)境中,系統(tǒng)接管了中斷,所有資源均由其統(tǒng)一管理,以便多個程序共享,它通過設備驅(qū)動程序為用戶提供標準的外設接口,禁止程序員通過Windows直接訪問內(nèi)存和外設?;诖宋奶岢隽嗽赪indows下響應硬件中斷的串行通訊的方法,并針對不同語言的特點,用BorlandC++編制程序?qū)Χ丝谥苯硬僮?,并響應?zhí)行硬件中斷程序接收數(shù)據(jù),利用DDE(動態(tài)數(shù)據(jù)交換)將數(shù)據(jù)傳送給用Delphi編制的程序處理數(shù)據(jù),將其加入數(shù)據(jù)庫,建立實時數(shù)據(jù)庫、動態(tài)顯示、打印及報警等。
二、串行通訊的原理
圖1 串行通訊口的連接
如圖1所示,串行通訊口的連接采用七根線直接連接方式,通過兩對應答信號線相連,可進行全雙工傳輸。UART是可編程的異步串行通信芯片。用戶對其編程實際上是對UART內(nèi)部寄存器的讀出或?qū)懭氩僮?。CPU可通過相應的輸入輸出指令對UART內(nèi)部寄存器訪問。通過訪問寄存器可初始化串行口、發(fā)送數(shù)據(jù)、接收數(shù)據(jù)、檢測線路設備狀態(tài)以達到通訊的目的。其端口地址名稱如表1所示(以串行口2為例)。
表1 UART內(nèi)部寄存器端口分配
端口地址 | 指令 | 寄存器名稱及作用 |
2F8H | OUT | 寫入發(fā)送保持寄存器 |
2F8H | IN | 讀出接收數(shù)據(jù)寄存器 |
2F8H | OUT | 寫入波特率因子(LSB) |
2F9H | OUT | 寫入波特率因子(MSB) |
2F9H | OUT | 寫入中斷允許寄存器 |
2FAH | IN | 讀出中斷標識寄存器 |
2FBH | OUT | 寫入線路控制寄存器 |
2FCH | OUT | 寫入MODEM控制寄存器 |
2FDH | IN | 讀出線路狀態(tài)寄存器 |
二、通訊的實現(xiàn)
一般通訊軟件采用的協(xié)議是這樣的:
發(fā)送者定時向串行口發(fā)送數(shù)據(jù);
接收者以中斷方式或查詢方式讀取數(shù)據(jù);
接收者將讀取的數(shù)據(jù)發(fā)送給發(fā)送者;
發(fā)送者將原發(fā)送數(shù)據(jù)與接收者發(fā)送的數(shù)據(jù)進行比較,如果一致則發(fā)送一個成功的標志給接收者,繼續(xù)發(fā)送數(shù)據(jù),否則發(fā)送一個失敗的標志給接收者,再重發(fā)送數(shù)據(jù);
重復1-4的過程直到數(shù)據(jù)傳送完成。
但這種傳送方式由于智能終端的速度處理數(shù)據(jù)較慢及協(xié)議繁瑣以致傳送速率變慢,且使智能終端程序變得復雜。為加快速度,本文將上述通訊協(xié)議進行了一些修改,利用計算機計算速度快的特點,由計算機進行數(shù)據(jù)處理,并采用異步通訊中斷方式接收,以增加接收數(shù)據(jù)的可靠性。其通訊協(xié)議如下:
發(fā)送者定時傳送兩個相同帶結(jié)束標志數(shù)據(jù);
接收者以中斷方式讀取這兩個數(shù)據(jù),并進行比較,如一致則發(fā)送一個成功的標志給發(fā)送者,否則發(fā)送一個失敗的標志給接收者,再重發(fā)送數(shù)據(jù)。
異步通訊中斷接收程序主要由通訊中斷初始化程序和通訊中斷服務程序兩部分組成。
1、通訊中斷初始化程序
通訊中斷初始化程序安排在整個通訊程序之前,它的工作如圖2所示,首先修改中斷向量表,按使用的串行口COM2,接管中斷0BH,使新的中斷向量指向自行編制的通訊中斷程序;其次確定UART操作方式,設置中斷寄存器相應位的允許或禁止,并允許中斷操作;第三確定通訊波特率及數(shù)據(jù)幀傳輸格式;最后對中斷控制器的屏蔽寄存器編程,允許中斷IRQ3。必須注意在應用程序終止退出時,從變量中獲取原中斷向量恢復到中斷向量表中,否則將引起系統(tǒng)死機。
圖2 通訊中斷初始化流程圖
2、通訊中斷服務程序
圖3 通訊中斷服務程序流程
通訊中斷服務程序如圖3所示,當智能終端有數(shù)據(jù)發(fā)送時,引起硬件中斷執(zhí)行中斷服務程序。當接收數(shù)據(jù)就緒時,將接收數(shù)據(jù)放入緩沖區(qū),且接收到結(jié)束標志時,發(fā)出一個用戶消息到應用程序隊列中,由應用程序繼續(xù)處理數(shù)據(jù),以便使中斷服務程序時間盡量壓縮到最小,讓其他應用程序獲得CPU的服務。在中斷返回前應向中斷控制器發(fā)出結(jié)束中斷命令,否則以后將屏蔽對同級中斷和低一級中斷的處理,只能接收一次數(shù)據(jù)。
異步通訊中斷接收程序代碼由Borland C++編制。利用inportb和outportb函數(shù)對表1中所列出的端口地址直接操作初始化和讀取數(shù)據(jù),用interrupt函數(shù)設置自己的中斷服務程序接收數(shù)據(jù)。另外由于對端口的直接操作,也使得執(zhí)行中斷服務程序的時間減少,以致CPU能獲得充分利用。
三、動態(tài)數(shù)據(jù)交換及數(shù)據(jù)處理
動態(tài)數(shù)據(jù)交換是Windows提供的一種利用共享內(nèi)存進行程序間數(shù)據(jù)交換或傳遞信息的方法,它充分體現(xiàn)了Windows的多任務優(yōu)點,使得各應用程序間的數(shù)據(jù)傳遞可以隨時方便地進行,尤其適合于程序間動態(tài)數(shù)據(jù)的傳遞。本文利用了Microsoft公司在Windows 31下推出的動態(tài)數(shù)據(jù)交換管理庫DDEML來實現(xiàn)程序間的動態(tài)數(shù)據(jù)交換。它使得所有的DDE程序采用了同樣的方式交換數(shù)據(jù),增加了程序的可靠性,使得用Borland C++編制的程序和Delphi編制的程序進行動態(tài)數(shù)據(jù)交換成為了可能。
本文以Borland C++編制的DDE客戶程序為數(shù)據(jù)源,一旦接收數(shù)據(jù)正確立即將數(shù)據(jù)傳送給Delphi編制的DDE服務器程序處理。
1、編寫DDE客戶程序
(1)初始化
客戶程序在使用DDEML函數(shù)前必須進行初始化,進行初始化可調(diào)用DdeInitialize函數(shù),可如下操作:
DdeInitialize(&idInst,(PFNCALLBACK)lpCallBack,APPCMDCLIENTONLY,0);
其中idInst為客戶程序需要保護的此呈現(xiàn)戶的標識符地址,標識符的值由DDEML給出;lpCallBack為回調(diào)函數(shù)的地址;APPCMDCLIENTONLY指明此程序的性質(zhì)。
另外創(chuàng)建服務名、話題名及項目名句柄:
hszService=DdeCreateStringHandle(idInst,"Server",CP[CD#*2]WINANSI);
hszTopic=DdeCreateStringHandle(idInst,"DdeServer",CP[CD#*2]WINANSI);
hszItem=DdeCreateStringHandle(idInst,"DdeServerIteml",CP[CD#*2]WINANSI);
(2)建立會話
調(diào)用DdeConnect建立單個會話:
hConv=DdeConnect(idInst,hszService,hszTopic,NULL);
這里idInst是客戶程序在調(diào)用DdeInitalize時由DDEML傳遞過來的代表客戶程序的標識符;hszService是服務名字符串的句柄;hszTopic是話題名字符串的句柄。
(3)向服務器傳遞數(shù)據(jù)
DdeClientTransaction((LPBYTE)szData,strlen(szData)+1,hConv,hszItem,
CF[CD#*2]TEXT,XTYP[CD#*2]POKE,0,NULL)
這里SzData是需傳遞的字符串指針;strlen(szData)+1是數(shù)據(jù)的大小;hConv是會話名;hszItem是項目名字符串的句柄;XTYPPOKE是調(diào)用DdeClientTransaction函數(shù)時事務;CFTEXT是數(shù)據(jù)格式。
(4)會話結(jié)束
應用程序結(jié)束時需要調(diào)用DdeFreeStringHandle函數(shù)來釋放所占用的空間,調(diào)用DdeDisConnect函數(shù)結(jié)束會話。
DdeFreeStringHandle(idInst,hszService);
DdeFreeStringHandle(idInst,hszTopic);
DdeFreeStringHandle(idInst,hszItem);
DdeDisconnect(hConv);
2、編寫DDE服務器及數(shù)據(jù)處理程序
在服務器Server端的窗體中放一DdeServerItem組件將其屬性Name設為DdeServerIteml,當有數(shù)據(jù)向服務器傳遞時,觸發(fā)事件OnPokeDate接收處理數(shù)據(jù)。另外Delphi提供了豐富的繪圖功能,利用此特性將接收的數(shù)據(jù)在虛擬界面上顯示數(shù)據(jù)及波形,并對數(shù)據(jù)進行報警打印,采用客戶/服務器形式,使用WINNTF的SQL Server服務器作為后臺,用Delphi編制程序作為前端工具將數(shù)據(jù)加入數(shù)據(jù)庫,建立實時數(shù)據(jù)庫,以便工程人員及管理層通過網(wǎng)絡共享數(shù)據(jù)。
四、軟件功能結(jié)構
軟件功能結(jié)構如圖4所示,程序由通訊程序和數(shù)據(jù)管理程序構成,其工作步驟如下:
1、由中斷通訊模塊接收智能終端發(fā)送的數(shù)據(jù)放入緩沖區(qū),并發(fā)出消息。
2、響應消息對數(shù)據(jù)進行處理,對智能終端發(fā)送數(shù)據(jù)正確或錯誤標志,并將緩沖區(qū)的數(shù)據(jù)經(jīng)DDE客戶模塊發(fā)送給數(shù)據(jù)管理程序的DDE服務器模塊。
3、數(shù)據(jù)管理程序?qū)DE服務器模塊接收的數(shù)據(jù)分別給數(shù)據(jù)庫模塊、動態(tài)顯示模塊、報警及打印模塊進行處理。
圖4 軟件功能模塊圖