孫 超
(西安電子科技大學(xué) 電子工程學(xué)院,陜西 西安710071)
數(shù)據(jù)采集與監(jiān)視控制系統(tǒng)(Supervisory Control and Data Aquisition,SCADA)廣泛應(yīng)用于電力、石油、化工等領(lǐng)域,其系統(tǒng)包括以下幾個(gè)組成部分:人機(jī)界面(Human Machine Interface,HMI)、遠(yuǎn)程終端控制系統(tǒng)(RTU)以及通信網(wǎng)絡(luò)。其中RTU通過(guò)連接傳感器采集數(shù)據(jù),并將采集的數(shù)據(jù)傳送給HMI;操作員可以用HMI了解系統(tǒng)狀態(tài),并決定是否要調(diào)整RTU的控制;通信網(wǎng)絡(luò)則提供HMI與RTU之間傳輸數(shù)據(jù)的管道。監(jiān)控中心的HMI組態(tài)軟件與RTU終端設(shè)備,采用少數(shù)幾種標(biāo)準(zhǔn)的通信協(xié)議進(jìn)行通信,如果RTU終端設(shè)備采用的是這幾種標(biāo)準(zhǔn)通信協(xié)議之一,則可以直接接入系統(tǒng)與組態(tài)軟件進(jìn)行通信,但如果RTU終端使用的不是這幾種標(biāo)準(zhǔn)的通信協(xié)議,則無(wú)法直接與組態(tài)軟件連接,并且由于涉及到許多復(fù)雜的專(zhuān)業(yè)計(jì)算,又使得這些設(shè)備難以被替代。為此,可采用VC++串口通信技術(shù)編寫(xiě)一個(gè)協(xié)議轉(zhuǎn)換軟件,通過(guò)對(duì)非標(biāo)準(zhǔn)協(xié)議與標(biāo)準(zhǔn)協(xié)議的互相轉(zhuǎn)換來(lái)實(shí)現(xiàn)非標(biāo)準(zhǔn)通信協(xié)議組件的接入。
協(xié)議轉(zhuǎn)換軟件能實(shí)現(xiàn)組態(tài)軟件接入非標(biāo)準(zhǔn)協(xié)議組件需要滿足兩個(gè)條件:組態(tài)軟件所使用的標(biāo)準(zhǔn)協(xié)議與非標(biāo)準(zhǔn)協(xié)議組件使用的協(xié)議能互相轉(zhuǎn)換;VC++編寫(xiě)的軟件能與其它軟件或設(shè)備進(jìn)行串口通信。
方案中的組態(tài)軟件是組態(tài)王,組態(tài)王使用ModBus-RTU標(biāo)準(zhǔn)協(xié)議與RTU終端設(shè)備通信。ModBus-RTU協(xié)議按主從方式通信,系統(tǒng)中只有一個(gè)主機(jī),可以有一個(gè)或多個(gè)從機(jī),每個(gè)從機(jī)有唯一的地址。主機(jī)和從機(jī)的通訊以查詢(xún)/應(yīng)答的方式進(jìn)行,一次通信過(guò)程由主機(jī)構(gòu)建并發(fā)送查詢(xún)數(shù)據(jù)幀開(kāi)始。所有的從機(jī)都將查看查詢(xún)數(shù)據(jù)幀中的地址并與本機(jī)地址比較:如果與本機(jī)地址不一致,則不作處理;如果與本機(jī)的地址一致,則按功能碼的要求完成操作并構(gòu)建應(yīng)答數(shù)據(jù)幀并發(fā)送給主機(jī),從而結(jié)束一次通信過(guò)程[1-2]。
ModBus-RTU協(xié)議數(shù)據(jù)幀的格式如圖11所示。
圖1 ModBus-RTU協(xié)議數(shù)據(jù)幀的格式
對(duì)于查詢(xún)幀,地址碼表示主機(jī)要查詢(xún)哪一個(gè)從機(jī),功能碼通知從機(jī)應(yīng)該執(zhí)行何種操作,數(shù)據(jù)提供了為執(zhí)行該操作而需要的一些附加信息,對(duì)于正常情況下的應(yīng)答幀,地址碼是本機(jī)的地址,功能碼與查詢(xún)幀相同,數(shù)據(jù)是從機(jī)按要求提供給主機(jī)的數(shù)據(jù)信息。數(shù)據(jù)校驗(yàn)都采用16位CRC校驗(yàn)方式。
方案中非標(biāo)準(zhǔn)協(xié)議組件是成都某公司生產(chǎn)的雷電監(jiān)測(cè)儀。該雷電監(jiān)測(cè)儀使用的是企業(yè)自行定義的一種485通信協(xié)議[3],該通信方式只要雷電監(jiān)測(cè)儀檢測(cè)到雷擊事件或跳閘事件,就會(huì)自動(dòng)將相應(yīng)的數(shù)據(jù)幀通過(guò)485串口發(fā)送給上位機(jī),同時(shí)上位機(jī)也可以發(fā)送指令查詢(xún)歷史數(shù)據(jù)。該自定義協(xié)議數(shù)據(jù)幀的格式如圖2所示。
圖2 雷電監(jiān)測(cè)儀自定義協(xié)議數(shù)據(jù)幀格式
幀頭是兩個(gè)固定的字節(jié)0xaa55,長(zhǎng)度是除幀頭外本數(shù)據(jù)幀的字節(jié)數(shù),命令表示檢測(cè)到的是什么事件,數(shù)據(jù)提供了所檢測(cè)到事件的檢測(cè)結(jié)果,數(shù)據(jù)校驗(yàn)采用累加和校驗(yàn)方式[3]。
對(duì)比以上兩種協(xié)議的通信方式和數(shù)據(jù)幀格式可知,兩種協(xié)議在數(shù)據(jù)幀上具有較好的對(duì)應(yīng)關(guān)系,在通信方式上存在的主要問(wèn)題是ModBus-RTU協(xié)議采取主從式通信,只有在組態(tài)軟件發(fā)送查詢(xún)幀時(shí),從機(jī)才能向組態(tài)軟件發(fā)送應(yīng)答幀,而自定義協(xié)議規(guī)定雷電監(jiān)測(cè)儀只要檢測(cè)到相關(guān)事件就自動(dòng)向上位機(jī)發(fā)送數(shù)據(jù)幀,不會(huì)等待上位機(jī)的查詢(xún)幀。為此,可以在協(xié)議轉(zhuǎn)換軟件中設(shè)置一個(gè)數(shù)據(jù)緩沖區(qū),用來(lái)暫時(shí)存放接收到的數(shù)據(jù)幀,等到被查詢(xún)時(shí)再發(fā)送組態(tài)軟件,這樣就可以實(shí)現(xiàn)兩種協(xié)議的互相轉(zhuǎn)換。
使用VC++實(shí)現(xiàn)串口通信[4]的方法有3種:使用MSComm控件、使用CSerialPort類(lèi)或者使用Windows API函數(shù)實(shí)現(xiàn)串口通信。MSComm控件由微軟提供,編程過(guò)程較容易,但控件內(nèi)部函數(shù)不開(kāi)放不透明。Windows API是所有Windows應(yīng)用程序的基礎(chǔ),但編程過(guò)程比較繁瑣。CSerialPort類(lèi)是一個(gè)免費(fèi)開(kāi)放的串口通信類(lèi),不僅編程過(guò)程較容易,而且類(lèi)函數(shù)均開(kāi)放透明,允許使用者進(jìn)行改造。因此,本方案的串口通信使用CSerialPort類(lèi)來(lái)實(shí)現(xiàn)。
CSerialPort是一個(gè)基于多線程的串口通信類(lèi),其工作流程如下:首先設(shè)置好串口參數(shù),再開(kāi)啟串口監(jiān)測(cè)工作線程,串口監(jiān)測(cè)工作線程檢測(cè)到串口接收到的數(shù)據(jù)、流控制事件或其他串口事件后,就以消息方式通知主程序,激發(fā)消息處理函數(shù)來(lái)進(jìn)行數(shù)據(jù)處理,這是對(duì)接收數(shù)據(jù)而言的;發(fā)送數(shù)據(jù)可以直接向串口發(fā)送[4]。
CSerialPort類(lèi)定義了多個(gè)消息,但在一般的串口通信編程中只需要處理WM_COMM_RXCHAR這一個(gè)消息。WM_COMM_RXCHAR消息的功能是表示串口接收到一個(gè)字符并已放入接收緩沖區(qū)。
CSerialPort類(lèi)還定義了多個(gè)函數(shù),但在一般的串口通信編程中經(jīng)常用到的是InitPort()、StartMonitoring()、StopMonitor()、CloseMonitor()和WriteToPort()。
InitPort()在串口通信過(guò)程中首先被調(diào)用。此函數(shù)的作用是初始化串口,即設(shè)置串口的通信參數(shù):需要打開(kāi)的串口號(hào)、波特率、奇偶校驗(yàn)方式、數(shù)據(jù)位、停止位。這里還可以用來(lái)進(jìn)行事件的設(shè)定,如果串口初始化成功,就返回true,若串口被其它設(shè)備占用、不存在、或存在其它故障,就返回false,編程者可以提示串口操作是否成功。
StartMonitoring()函數(shù)一般緊跟在InitPort()之后調(diào)用。此函數(shù)的作用是啟動(dòng)串口監(jiān)測(cè)線程,如果線程啟動(dòng)成功,則函數(shù)返回true。在調(diào)用InitPort()函數(shù)和StartMonitoring()函數(shù)后,串口就被打開(kāi),各種串口狀態(tài)和事件就可以被檢測(cè)到了。
在串口通信過(guò)程中,當(dāng)需要通過(guò)串口發(fā)送數(shù)據(jù)時(shí),可調(diào)用WriteToPort()函數(shù)。該函數(shù)的功能是寫(xiě)串口,即向串口發(fā)送字符。
在串口通信過(guò)程中,當(dāng)需要暫?;蛲V勾诒O(jiān)測(cè)時(shí),可調(diào)用StopMonitor()函數(shù)。調(diào)用該函數(shù)后串口被暫?;蛲V梗谫Y源仍被占用。
CloseMonitor()函數(shù)的功能是關(guān)閉串口,釋放串口資源。調(diào)用該函數(shù)后,如果要繼續(xù)使用串口,需要重新調(diào)用InitPort()和StartMonitoring()函數(shù)。
協(xié)議轉(zhuǎn)換軟件有3個(gè)線程,主線程顯示主界面,用來(lái)設(shè)置參數(shù)及顯示串口通信數(shù)據(jù),兩個(gè)串口通信線程分別用來(lái)與組態(tài)王和非標(biāo)準(zhǔn)協(xié)議組件通信。軟件各部分功能采用模塊化處理,使程序簡(jiǎn)潔易懂,便于移植。
(1)線程間數(shù)據(jù)傳輸模塊。用于主線程與兩個(gè)子線程之間傳遞數(shù)據(jù)。主界面上設(shè)置的參數(shù)通過(guò)全局變量傳遞給子線程,子線程中對(duì)參數(shù)的修改也通過(guò)全局變量反映到主界面。子線程之間的線程同步使用互斥對(duì)象(CMutex)來(lái)實(shí)現(xiàn)。
(2)串口通信模塊。用于與組態(tài)王和雷電監(jiān)測(cè)儀進(jìn)行通信。監(jiān)聽(tīng)并接收來(lái)自于組態(tài)王和雷電監(jiān)測(cè)儀的數(shù)據(jù)幀,并將轉(zhuǎn)換后的數(shù)據(jù)幀發(fā)送給這兩個(gè)設(shè)備。
(3)協(xié)議轉(zhuǎn)換模塊。用于ModBus-RTU協(xié)議數(shù)據(jù)幀與雷電監(jiān)測(cè)儀非標(biāo)準(zhǔn)協(xié)議數(shù)據(jù)幀的轉(zhuǎn)換。將接收到的ModBus-RTU協(xié)議數(shù)據(jù)幀中的數(shù)據(jù)提取出來(lái),按照非標(biāo)準(zhǔn)協(xié)議構(gòu)造成新的數(shù)據(jù)幀,然后發(fā)送給雷電監(jiān)測(cè)儀。同理,將接收到的非標(biāo)準(zhǔn)協(xié)議數(shù)據(jù)幀中的數(shù)據(jù)提取出來(lái),按照ModBus-RTU協(xié)議生成新的數(shù)據(jù)幀,然后在被查詢(xún)時(shí)發(fā)送給組態(tài)軟件。
(4)數(shù)據(jù)校驗(yàn)?zāi)K。用于對(duì)串口接收和發(fā)送的數(shù)據(jù)幀進(jìn)行校驗(yàn)。ModBus-RTU協(xié)議數(shù)據(jù)幀所使用的是16位CRC校驗(yàn),非標(biāo)協(xié)議數(shù)據(jù)幀所使用的是累加和校驗(yàn)。對(duì)于接收到的數(shù)據(jù)幀通過(guò)比較按照相應(yīng)協(xié)議的校驗(yàn)方式計(jì)算的校驗(yàn)碼與接收到數(shù)據(jù)幀中的校驗(yàn)碼是否相同來(lái)判斷接收到的數(shù)據(jù)幀是否有效;對(duì)于待發(fā)送的數(shù)據(jù)幀則按照相應(yīng)協(xié)議的校驗(yàn)方式來(lái)計(jì)算生成該數(shù)據(jù)幀的校驗(yàn)碼。
串口通信分為串口接收和串口發(fā)送。串口發(fā)送,只要在需要發(fā)送時(shí)調(diào)用寫(xiě)串口函數(shù)WriteToPort()就可以將數(shù)據(jù)幀發(fā)送出去了。由于串口接收到數(shù)據(jù)幀的時(shí)間是隨機(jī)的,所以需要對(duì)串口進(jìn)行持續(xù)監(jiān)測(cè),以便接收到數(shù)據(jù)幀后能及時(shí)處理。串口通信線程的接收處理流程如圖3所示。
圖3 串口通信接收處理流程圖
串口接收到數(shù)據(jù)幀后將數(shù)據(jù)幀存放在數(shù)據(jù)緩存區(qū)中。當(dāng)軟件檢測(cè)到數(shù)據(jù)緩存區(qū)中有新的數(shù)據(jù)幀時(shí),就會(huì)啟動(dòng)協(xié)議轉(zhuǎn)換過(guò)程。協(xié)議轉(zhuǎn)換的流程如圖4所示。
圖4 協(xié)議轉(zhuǎn)換流程圖
軟件編寫(xiě)好之后和組態(tài)軟件一起運(yùn)行于Windows平臺(tái)。默認(rèn)狀態(tài)下軟件是在后臺(tái)運(yùn)行的,只有在需要查看時(shí)才調(diào)出如圖5所示的協(xié)議轉(zhuǎn)換軟件運(yùn)行主界面。圖5中485串口和ModBus串口用于設(shè)置協(xié)議轉(zhuǎn)換軟件與雷電監(jiān)測(cè)儀和組態(tài)王進(jìn)行通信的串口號(hào)。485接收窗口和ModBus接收窗口用于顯示接收到的數(shù)據(jù)幀,以便查看軟件與組態(tài)王和雷電監(jiān)測(cè)儀的通信是否正常。
軟件工作流程為:首先設(shè)置485串口和ModBus串口的串口號(hào),然后打開(kāi)串口開(kāi)始對(duì)串口進(jìn)行持續(xù)監(jiān)測(cè),如果監(jiān)測(cè)到來(lái)自組態(tài)王的數(shù)據(jù)幀,則將其顯示在ModBus接收窗口,然后根據(jù)組態(tài)王數(shù)據(jù)幀的指令或直接到數(shù)據(jù)緩沖區(qū)中取出新接收到的雷電監(jiān)測(cè)儀數(shù)據(jù)幀,轉(zhuǎn)換為應(yīng)答幀發(fā)送給組態(tài)王,或者將組態(tài)王數(shù)據(jù)幀轉(zhuǎn)換為符合非標(biāo)準(zhǔn)協(xié)議的數(shù)據(jù)幀后發(fā)送給雷電監(jiān)測(cè)儀。如果監(jiān)測(cè)到來(lái)自雷電監(jiān)測(cè)儀的數(shù)據(jù)幀,則將其顯示在485接收窗口,然后存放到數(shù)據(jù)緩沖區(qū)中,等待組態(tài)王的查詢(xún)。
圖5 協(xié)議轉(zhuǎn)換軟件界面
組態(tài)軟件廣泛應(yīng)用于各領(lǐng)域的監(jiān)控系統(tǒng)中,需要與各種使用非標(biāo)準(zhǔn)通信協(xié)議的設(shè)備互連。本文介紹了一種采用VC++串口通信技術(shù)編寫(xiě)一個(gè)協(xié)議轉(zhuǎn)換軟件來(lái)解決工業(yè)組態(tài)軟件接入非標(biāo)準(zhǔn)通信協(xié)議組件的方案。該協(xié)議轉(zhuǎn)換軟件已在某智能化電力監(jiān)控系統(tǒng)中得到應(yīng)用,為解決組態(tài)軟件接入非標(biāo)準(zhǔn)通信協(xié)議組件的問(wèn)題提供了一個(gè)參考。
[1] 呂國(guó)芳,唐海龍,李進(jìn).基于ModBus RTU的串口調(diào)試軟件的實(shí)現(xiàn)[J].計(jì)算機(jī)技術(shù)與發(fā)展,2009,19(9):236-238.
[2] 顏河恒,王曉華,佟為明.Modbus關(guān)鍵技術(shù)分析及節(jié)點(diǎn)開(kāi)發(fā)[J].自動(dòng)化技術(shù)與應(yīng)用,2006,25(5):49-51.
[3] 四川中光防雷科技股份有限公司.ZGLF-2通信協(xié)議[M].成都:四川中光防雷科技股份有限公司,2012.
[4] 龔建偉,熊光明.Visual C++/Turbo C串口通信編程實(shí)踐[M].北京:電子工業(yè)出版社,2007.