李麗宏 王淑娟
(太原理工大學(xué)信息工程學(xué)院,太原 030024)
在高速公路計(jì)重收費(fèi)系統(tǒng)中,車輛稱重?cái)?shù)據(jù)是收費(fèi)軟件計(jì)算通行費(fèi)的主要依據(jù)。通常收費(fèi)計(jì)算機(jī)通過串口獲取稱重儀表數(shù)據(jù),但不同廠商、不同型號(hào)的稱重儀表采用不同的協(xié)議,導(dǎo)致計(jì)重收費(fèi)軟件的通用性差和管理復(fù)雜[1]。因此本文設(shè)計(jì)了串口通信動(dòng)態(tài)鏈接庫,它作為稱重儀表與收費(fèi)軟件接口,使收費(fèi)軟件可以通過訪問動(dòng)態(tài)鏈接庫中的函數(shù)來獲取車輛稱重?cái)?shù)據(jù);同時(shí),方便了收費(fèi)軟件的管理,并實(shí)現(xiàn)不同協(xié)議的儀表共用統(tǒng)一收費(fèi)軟件的目的。計(jì)重收費(fèi)系統(tǒng)中稱重?cái)?shù)據(jù)流圖如圖1所示。
圖1 計(jì)重收費(fèi)系統(tǒng)中稱重?cái)?shù)據(jù)流圖
動(dòng)態(tài)鏈接庫的三個(gè)關(guān)鍵文件:*.cpp、*.h和*.def,其中“*.cpp”文件用來編寫函數(shù)主體[2];“*.h”文件用來定義動(dòng)態(tài)鏈接庫的導(dǎo)出函數(shù),在導(dǎo)出函數(shù)前使用_declspec (dllexport)關(guān)鍵字和extern "C"連接指示符來實(shí)現(xiàn)動(dòng)態(tài)鏈接庫函數(shù)的導(dǎo)出[3];“*.def”文件用來設(shè)置導(dǎo)出函數(shù)名,當(dāng)使用“_stdcall”調(diào)用約定時(shí),若不通過此文件來設(shè)置導(dǎo)出函數(shù)名稱,則會(huì)發(fā)生函數(shù)命名改變的情況[4]。
本文設(shè)計(jì)的串口通信動(dòng)態(tài)鏈接庫是在Microsoft Visual C++6.0環(huán)境下開發(fā)完成的,VC++6.0中對串口操作的流程為:打開串口、設(shè)置串口、讀串口、寫串口及關(guān)閉串口[5]。在實(shí)現(xiàn)串行通信的動(dòng)態(tài)鏈接庫時(shí),首先以重疊I/O方式打開串口并初始化,然后創(chuàng)建讀串口線程[6],此時(shí)讀串口線程函數(shù)開始在后臺(tái)實(shí)時(shí)讀取串口數(shù)據(jù)。當(dāng)收到符合要求的數(shù)據(jù)后,該線程回應(yīng)相應(yīng)數(shù)據(jù)幀給稱重儀表,同時(shí)將數(shù)據(jù)保存在Temprecord.dat文件中,確保串口數(shù)據(jù)的掉電不丟失,從而達(dá)到數(shù)據(jù)完整的效果。
串口設(shè)置函數(shù)WimDev_SetCom實(shí)現(xiàn)對串口通信的配置,函數(shù)中首先判斷串口是否已打開,然后再對串口號(hào)、波特率、輸入輸出緩沖區(qū)以及字符間隔時(shí)間進(jìn)行配置,最后創(chuàng)建串口讀線程,設(shè)置串口函數(shù)流程圖如圖2所示。
圖2 串口設(shè)置流程圖
函數(shù)中主要采用串口API函數(shù)CreateFile、SetCommState來打開、設(shè)置串口,并用CreateThread函數(shù)創(chuàng)建串口讀線程。
由于高速公路計(jì)重收費(fèi)系統(tǒng)要求在接收稱重?cái)?shù)據(jù)的同時(shí)完成對已接收到的數(shù)據(jù)進(jìn)行實(shí)時(shí)保存,若處理不好,將導(dǎo)致稱重?cái)?shù)據(jù)的丟失甚至程序的崩潰,這就需要應(yīng)用程序能夠同時(shí)處理多個(gè)不同任務(wù)。因此在動(dòng)態(tài)鏈接庫中創(chuàng)建讀串口數(shù)據(jù)線程,它在動(dòng)態(tài)鏈接庫的運(yùn)行中一直處于后臺(tái)運(yùn)行的狀態(tài),為其它數(shù)據(jù)處理函數(shù)提供數(shù)據(jù)來源。讀串口線程的創(chuàng)建不但提高了收費(fèi)軟件的響應(yīng)速度,同時(shí)增強(qiáng)了對稱重?cái)?shù)據(jù)處理的實(shí)時(shí)性。
在讀線程函數(shù)中,線程打開后先對已保存在Temprecord.dat文件中的車輛數(shù)據(jù)進(jìn)行讀取并存入數(shù)據(jù)鏈表中。當(dāng)串口緩存區(qū)中有新數(shù)據(jù)時(shí),首先對收到的數(shù)據(jù)進(jìn)行CRC校驗(yàn),然后根據(jù)數(shù)據(jù)的功能位對串口做出相應(yīng)的回應(yīng)并發(fā)送相應(yīng)的消息,即:若讀取的是設(shè)備自檢信息,則將數(shù)據(jù)存入state.dat文件中,并發(fā)送自檢消息;若讀取的是過車信息,待數(shù)據(jù)校驗(yàn)成功后,通過WriteFile函數(shù)實(shí)現(xiàn)對串口的過車信息回應(yīng),并將車輛數(shù)據(jù)信息保存在數(shù)據(jù)鏈表中和Temprecord.dat文件中,最后發(fā)送過車消息;若讀取的是倒車信息且數(shù)據(jù)校驗(yàn)成功后,通過WriteFile函數(shù)實(shí)現(xiàn)對串口的倒車信息回應(yīng),并刪除數(shù)據(jù)鏈表中最后一輛車的數(shù)據(jù)和Temprecord.dat文件中最后一輛車數(shù)據(jù),最后發(fā)送倒車消息。讀取串口線程流程如圖3所示。
線程掛起就是使線程暫停運(yùn)行,此時(shí)CPU不再給線程分配時(shí)間片,從而降低了計(jì)算機(jī)的CPU使用率。本文設(shè)計(jì)的串口通信動(dòng)態(tài)鏈接庫中通過sleep方法實(shí)現(xiàn)線程掛起,具體實(shí)現(xiàn)如下:
while(1)//線程主體
{
……//讀串口數(shù)據(jù)并保存
sleep(50);//線程掛起
}
關(guān)閉串口程序主要用來關(guān)閉已打開的串口,退出應(yīng)用程序并釋放資源。
void _stdcall CloseCom()
{
CloseHandle(hCom); //關(guān)閉串口
………
}
圖3 讀串口線程流程圖
為增強(qiáng)計(jì)重收費(fèi)軟件對稱重?cái)?shù)據(jù)讀取的主動(dòng)性,在動(dòng)態(tài)鏈接庫收到稱重?cái)?shù)據(jù)并校驗(yàn)成功后,向Windows發(fā)送相應(yīng)的消息告知其某事件發(fā)生了,收費(fèi)軟件再根據(jù)捕捉到的消息內(nèi)容執(zhí)行相應(yīng)的動(dòng)作。
本文設(shè)計(jì)的串口通信動(dòng)態(tài)鏈接庫使用的是Windows自定義消息[7],通過自定義消息來告知收費(fèi)軟件稱重儀表發(fā)生的動(dòng)作類型,包括:設(shè)備故障信息、過車信息、倒車信息三種,設(shè)備故障消息號(hào)為0464H、過車消息號(hào)為0465H、倒車消息號(hào)為0466H。動(dòng)態(tài)庫中消息發(fā)送的具體實(shí)現(xiàn)如下:
if(lpInBuffer[i]==255&&lpInBuffer[i+1]==0&&lpInBuffer[i+2]==5)
SendMessage(hhWnd,0x0464,0,0);//發(fā)送設(shè)備故障消息
if(lpInBuffer[i]==255&&lpInBuffer[i+1]==0&&lpInBuffer[i+2]==1)
SendMessage(hhWnd,0x0465,0,0);//發(fā)送過車消息
if(lpInBuffer[i]==255&&lpInBuffer[i+1]==0&&lpInBuffer[i+2]==6)
SendMessage(hhWnd,0x0466,0,0);//發(fā)送倒車消息
計(jì)重收費(fèi)系統(tǒng)中動(dòng)態(tài)鏈接庫的使用,提高了收費(fèi)軟件的通用性,并方便了收費(fèi)軟件的管理。在動(dòng)態(tài)鏈接庫實(shí)現(xiàn)串口通信時(shí),數(shù)據(jù)鏈表和Temprecord.dat文件的使用,保證了稱重表數(shù)據(jù)的完整性;同時(shí),采用線程技術(shù)和Windows消息機(jī)制,提高了計(jì)算機(jī)對稱重儀表數(shù)據(jù)采集的實(shí)時(shí)性和主動(dòng)性。本文設(shè)計(jì)的動(dòng)態(tài)鏈接庫在某收費(fèi)站進(jìn)行了測試,測試表明:動(dòng)態(tài)鏈接庫運(yùn)行穩(wěn)定、可靠。
[1] 張會(huì)銘,雷志華.基于Windows服務(wù)的網(wǎng)口與串口通信軟件設(shè)計(jì)[J].微計(jì)算機(jī)信息,2009,25(4):114-116
[2] 陸云龍,雷志華.基于Windows服務(wù)的網(wǎng)口與串口通信設(shè)計(jì)及應(yīng)用[J].科學(xué)技術(shù)與工程,2008,8(17):76-79
[3] 吳先亮,劉春生.基于多線程的串口通信軟件的設(shè)計(jì)與實(shí)現(xiàn)[J].控制工程,2004,11(2):171-174
[4] 蘭波,曾瀟,周建瑜.利用VC++6.0動(dòng)態(tài)鏈接庫實(shí)現(xiàn)三坐標(biāo)測量機(jī)的CNC化[J].中國測試技術(shù),2008,34(5):75-78
[5] 文欣秀,米西峰,等.基于動(dòng)態(tài)鏈接庫實(shí)現(xiàn)軟件界面組件化方法研究[J].計(jì)算機(jī)應(yīng)用與軟件,2007,24(7):18-20
[6] 劉浩,萬昆.基于動(dòng)態(tài)鏈接庫DLL的實(shí)時(shí)數(shù)據(jù)庫系統(tǒng)研究與開發(fā)[J].東北電力學(xué)院學(xué)報(bào),2005,25(1):36-39
[7] 龔力柱,蔣澤軍,王麗芳.基于Windows消息機(jī)制的軟件本地化[J].計(jì)算機(jī)工程,2008,31(21):87-89