基于USB和多線程的實(shí)時(shí)數(shù)據(jù)采集系統(tǒng)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
關(guān)鍵詞:USB PDIUSBD12 多線程 實(shí)時(shí)數(shù)據(jù)采集
1 問(wèn)題的提出
隨著信息技術(shù)的飛速發(fā)展,各種數(shù)據(jù)的實(shí)時(shí)采集和處理在現(xiàn)代工業(yè)控制中已成為必不可少的。這就為我們的設(shè)計(jì)提出了兩個(gè)方面的要求:一方面,要求接口簡(jiǎn)單靈活且有較高的數(shù)據(jù)傳輸率;另一方面,由于數(shù)據(jù)量通常都較大,要求主機(jī)能夠?qū)?shí)時(shí)數(shù)據(jù)做出快速響應(yīng),并及時(shí)進(jìn)行分析和處理。
傳統(tǒng)的外設(shè)與主機(jī)的通信接口難以滿足上述第一個(gè)方面的要求。這些接口一般采用PCI部線或RS-232串行總線。PCI總線雖然有很高的傳輸率(可達(dá)132Mbps),還能“即插即用”,但是它們的擴(kuò)充槽相當(dāng)有限,且插拔并不方便。RS-232串行總線雖然連接方便,可是它的帶寬非常有限,傳輸速度太慢,而且1條RS-232串口通信電纜只能連接1個(gè)物理設(shè)備。USB技術(shù)正是順序這一要求提出的,它集PCI和RS-232的優(yōu)點(diǎn)于一身:具有較高的傳輸速率(USB協(xié)議1.1支持最高傳輸速度達(dá)12Mbps,USB協(xié)議2.0支持最高傳輸速度可達(dá)148Mbps),實(shí)現(xiàn)了真正意義上的“即插即用”(Plug & Play),同時(shí)USB上最多可以連接127個(gè)外設(shè)。因此,將USB技術(shù)應(yīng)用于數(shù)據(jù)的實(shí)時(shí)采集是非常適合的。
實(shí)時(shí)系統(tǒng)對(duì)多任務(wù)的要求比較普遍。往往在后臺(tái)采集數(shù)據(jù)、進(jìn)行數(shù)據(jù)顯示的同時(shí),還要在前臺(tái)界面對(duì)用戶的操作做出響應(yīng)。在實(shí)時(shí)系統(tǒng)中,對(duì)實(shí)時(shí)數(shù)據(jù)做出及時(shí)而準(zhǔn)確的反應(yīng)是十分重要的。由于受A/D采集速度等因素的限制,從硬件上采用USB接口技術(shù)的確可以提高速度,但畢竟?jié)摿τ邢?,因此在現(xiàn)有硬件設(shè)計(jì)基礎(chǔ)上充分發(fā)揮軟件的作用就能進(jìn)一步提升速度。使用傳統(tǒng)的單線程編程技術(shù)效率較低,無(wú)法及時(shí)處理,必須充分利用Windows的多任務(wù)處理功能,采用多線程編程技術(shù)來(lái)處理數(shù)據(jù)。
在這個(gè)實(shí)時(shí)采集系統(tǒng)的設(shè)計(jì)上,我們將這兩種技術(shù)結(jié)合起來(lái):在硬件上采用USB技術(shù);軟件用VC++進(jìn)行開(kāi)發(fā),采用多線程編程,使系統(tǒng)的效率從這兩方面都得到提升。
2 系統(tǒng)體系結(jié)構(gòu)
2.1 硬件結(jié)構(gòu)
整個(gè)系統(tǒng)硬件結(jié)構(gòu)如圖1所示。
實(shí)時(shí)數(shù)據(jù)采集系統(tǒng)主要由多路選擇開(kāi)關(guān)、A/D轉(zhuǎn)換、單片機(jī)系統(tǒng)、PDIUSBD12、微機(jī)組成。多路選擇開(kāi)關(guān)對(duì)多路信號(hào)進(jìn)行選擇,使其分時(shí)輸入;A/D轉(zhuǎn)換實(shí)現(xiàn)模擬信號(hào)的數(shù)字化;單片機(jī)系統(tǒng)主要完成信號(hào)采集、數(shù)據(jù)通信;PDIUSBD12實(shí)現(xiàn)USB接口;微機(jī)完成數(shù)據(jù)接收、存入數(shù)據(jù)庫(kù)、數(shù)據(jù)處理、計(jì)算、顯示等功能。
其中PDIUSBD12是系統(tǒng)USB技術(shù)得以實(shí)現(xiàn)的關(guān)鍵。它是Philips公司的一個(gè)帶并行總線的USB接口器件,支持本地的DMA傳輸。它完全符合USB1.1版的規(guī)范,同時(shí)集成了SIE(串行接口引擎)、FIFO存儲(chǔ)器、收發(fā)器以及電壓調(diào)整器。其主端點(diǎn)的雙緩沖配置增加了數(shù)據(jù)吞吐量并輕松實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)傳輸,功能框圖如圖2所示。
在這個(gè)系統(tǒng)中,單片機(jī)采用的是80C52。PDIUSBD12與80C52的接口有2種方式:多路地址/數(shù)據(jù)總線方式、單地址/數(shù)據(jù)總線方式。我們采用的是前一種方式:使用了80C52的INT0、ALE、WR、RD和P0口,當(dāng)PDIUSBD12接收到主機(jī)的有效信息時(shí),會(huì)產(chǎn)生一個(gè)中斷通知80C52進(jìn)行處理。在此種方式下,PDIUSBD12在ALE下降沿的時(shí)候,對(duì)單片機(jī)的輸出地址進(jìn)行鎖存。若輸出地址為奇數(shù),則表示對(duì)PDIUSBD12發(fā)送指令;若輸出地址為偶數(shù),則表示對(duì)PDIUSBD12進(jìn)行數(shù)據(jù)傳輸。接口電路如圖3所示。
80C52將A/D采集的數(shù)據(jù)經(jīng)PDIUSBD12的并行接口送入FIFO存儲(chǔ)器。當(dāng)USB的傳輸速率達(dá)到12Mbps時(shí),MMU(存儲(chǔ)器管理單元)和集成RAM作為USB之間速度差異的緩沖區(qū),這就允許單片機(jī)以它自己的速率對(duì)USB信息包進(jìn)行讀寫。若FIFO中數(shù)據(jù)已滿,SIE會(huì)立即對(duì)數(shù)據(jù)做處理:同步模式的識(shí)別、并行/串行轉(zhuǎn)換、位填充/解除填充、CRC校驗(yàn)/產(chǎn)生、PID校驗(yàn)/產(chǎn)生、地址識(shí)別和握手評(píng)估/產(chǎn)生。SIE實(shí)現(xiàn)了全部的USB協(xié)議層,完全由硬件實(shí)現(xiàn)而不需要固件的參與。數(shù)據(jù)經(jīng)處理后由收發(fā)器通過(guò)數(shù)據(jù)線D+、D-傳送到主機(jī)。對(duì)一個(gè)單片機(jī)而言,PDIUSBD12看起來(lái)就像1個(gè)帶8位數(shù)據(jù)總線和1個(gè)地址位的存儲(chǔ)器件。
2.2 軟件結(jié)構(gòu)
USB的軟件系統(tǒng)包括三部分:客戶應(yīng)用軟件、設(shè)備固件以及USB設(shè)備驅(qū)動(dòng)程序。其中,設(shè)備固件和USB設(shè)備驅(qū)動(dòng)程序又被稱為主機(jī)軟件。軟件層次如圖4所示。
2.2.1 固件設(shè)備
設(shè)備固件(firmware)是儲(chǔ)存在程序內(nèi)存中的代碼。它使得USB接口芯片與主機(jī)和外設(shè)中其它電路能夠通信。固件由USB驅(qū)動(dòng)程序(USBD)、主控制器驅(qū)動(dòng)程序(HCD)兩部分組成。USBD的功能可以概括為:配置管理、總線管理、數(shù)據(jù)傳輸管理、提供客戶服務(wù)。USBD把IRP劃分為USB和設(shè)備需要大小的塊,確保每一個(gè)設(shè)備能分配到它所要求的USB資源,這樣它就可以支持USB設(shè)備配置。USBD提供了一個(gè)編程接口USBDI(USB驅(qū)動(dòng)程序接口),給客戶驅(qū)動(dòng)程序一種方式,用于傳輸請(qǐng)求,傳輸?shù)姆较蚩梢允莵?lái)自或發(fā)往USB的功能單元。大量的客戶服務(wù)是由USB的驅(qū)動(dòng)程序提供的,它幫助USB的客戶控制和訪問(wèn)它們的功能單元。HCD提供了對(duì)USB的低級(jí)支持,通過(guò)把IRP轉(zhuǎn)換成為單獨(dú)的事務(wù)處理后在USB上執(zhí)行。
本系統(tǒng)固件設(shè)計(jì)的目標(biāo)是使PDIUSBD12達(dá)到最高的傳輸速度。微處理器主要忙于多路數(shù)據(jù)的采集及處理,PDIUSBD12的固件設(shè)計(jì)成完全的中斷驅(qū)動(dòng)。USB的傳輸可在后臺(tái)進(jìn)行,這確保了最佳的傳輸速率和更好的軟件結(jié)構(gòu),同時(shí)簡(jiǎn)化了編程和調(diào)試。它的基本思想是:后臺(tái)ISR(中斷服務(wù)程序)和前臺(tái)主程序循環(huán)之間的數(shù)據(jù)交換通過(guò)事件標(biāo)志和數(shù)據(jù)緩沖區(qū)來(lái)實(shí)現(xiàn)。當(dāng)PDIUSBD12從USB收到一個(gè)數(shù)據(jù)包時(shí),就對(duì)單片機(jī)產(chǎn)生一個(gè)中斷請(qǐng)求,單片機(jī)立即響應(yīng)中斷。在ISR中,固件將數(shù)據(jù)包從FDIUSBD12內(nèi)部緩沖區(qū)移到循環(huán)數(shù)據(jù)緩沖區(qū),并在隨后請(qǐng)求清零PDIUSBD12的內(nèi)部緩沖區(qū),以使其能接收新的數(shù)據(jù)包。然后返回到主循環(huán),檢查循環(huán)緩沖區(qū)內(nèi)是否有新的數(shù)據(jù)并開(kāi)始其它的前臺(tái)任務(wù)。
基于這種結(jié)構(gòu),主循環(huán)不關(guān)心數(shù)據(jù)是來(lái)自USB、串口還是并口,只檢查循環(huán)緩沖區(qū)內(nèi)需要處理的新數(shù)據(jù)。這樣,主循環(huán)程序?qū)W⒂跀?shù)據(jù)的處理而ISR能夠以盡可能高的可能高的速度進(jìn)行數(shù)據(jù)的傳輸。
這部分程序結(jié)構(gòu)可包括:
主循環(huán)程序——發(fā)送USB請(qǐng)求,處理USB總線事件和用戶功能處理等;
硬件提以層——對(duì)單片機(jī)的I/O口、數(shù)據(jù)總線等硬件接口進(jìn)行操作;
PDIUSBD12命令接口——對(duì)PDIUSBD12器件進(jìn)行操作的模塊子程序集;
請(qǐng)求處理程序——對(duì)USB的標(biāo)準(zhǔn)設(shè)備請(qǐng)求進(jìn)行處理和對(duì)用戶添加的廠商請(qǐng)求進(jìn)行處理;
中斷服務(wù)程序——當(dāng)PDIUSBD12向單片機(jī)發(fā)出中斷請(qǐng)求時(shí),讀取PDIUSBD12的中斷傳輸來(lái)的數(shù)據(jù),并設(shè)定事件標(biāo)志和Setup包數(shù)據(jù)緩沖區(qū),傳輸給主循環(huán)。
2.2.2 USB設(shè)備驅(qū)動(dòng)設(shè)計(jì)
在Windows下,與USB外設(shè)的任何通信必須通過(guò)USB設(shè)備驅(qū)動(dòng),這個(gè)驅(qū)動(dòng)知道如何與系統(tǒng)的USB驅(qū)動(dòng)和訪問(wèn)設(shè)備的應(yīng)用程序通信。設(shè)備驅(qū)動(dòng)是保證應(yīng)用程序訪問(wèn)硬件設(shè)備的軟件組件,使得應(yīng)用程序不必知道物理連接、信號(hào)和與一個(gè)設(shè)備通信需要的協(xié)議等的細(xì)節(jié),可以保證應(yīng)用程序代碼只通過(guò)外設(shè)名字訪問(wèn)外設(shè)或端口目的地。應(yīng)用程序不需要知道外設(shè)連接端口的物理地址,不需要精確監(jiān)視和控制外設(shè)需要的交換信號(hào)。
設(shè)備驅(qū)動(dòng)通過(guò)在應(yīng)用層和硬件專用代碼之間的轉(zhuǎn)化來(lái)完成它的任務(wù)。應(yīng)用層代碼一般使用一套操作系統(tǒng)支持的函數(shù),硬件代碼則處理那些訪問(wèn)外設(shè)電路的必要協(xié)議。設(shè)備驅(qū)動(dòng)能與應(yīng)用程序之間相互通信是通過(guò)Windows提供的API函數(shù),這些函數(shù)使應(yīng)用程序能夠控制顯示器、處理信息、訪問(wèn)存儲(chǔ)器、讀寫磁盤和其它設(shè)備。對(duì)于一些標(biāo)準(zhǔn)設(shè)備,Windows提供通用驅(qū)動(dòng);不過(guò),這個(gè)實(shí)時(shí)數(shù)據(jù)采集系統(tǒng)是自定義的設(shè)備,對(duì)此Windows并不提供通用的驅(qū)動(dòng),需要對(duì)設(shè)備編寫自定義的驅(qū)動(dòng),并且必須遵循微軟在Windows98和更新版本中為用戶定義的Win32驅(qū)動(dòng)模式。Windows98和Windows2000中,USB總線驅(qū)動(dòng)是WDM驅(qū)動(dòng),擴(kuò)展名為.sys。編寫USB設(shè)備驅(qū)動(dòng)需要使用Visual C++,此外還需要Windows 98或2000設(shè)備開(kāi)發(fā)包(98DDK/NTDDK)。USB設(shè)備驅(qū)動(dòng)的編寫通常不是一項(xiàng)簡(jiǎn)單的任務(wù),驅(qū)動(dòng)開(kāi)發(fā)包就提供一種途徑,通過(guò)做盡可能多的工作為跳過(guò)驅(qū)動(dòng)開(kāi)發(fā),這些開(kāi)發(fā)庫(kù)有Blue Water Systems的WinDK和Compuware NuMega的DriverWorks。這些工具包能夠集成到Visual C++編程環(huán)境中。運(yùn)用這些工具包只需很少的時(shí)間就能生成一個(gè)高效的驅(qū)動(dòng)程序。
這一部分可以包括4個(gè)模塊:初始化模塊、即插即用管理模塊、電源管理模塊和I/O功能模塊。初始化模塊提供一個(gè)DriverEntery入口點(diǎn)來(lái)執(zhí)行大量的初始化函數(shù)。即插用模塊實(shí)現(xiàn)USB設(shè)備的動(dòng)態(tài)插拔及配置。當(dāng)硬件檢測(cè)到USB設(shè)備接入時(shí),Windows查找相應(yīng)的驅(qū)動(dòng)程序,并且調(diào)用它的DriverEntery例程,PnP(即插即用)管理器調(diào)用驅(qū)動(dòng)程序的AddDevice例程,通知它添加了一個(gè)設(shè)備。驅(qū)動(dòng)程序會(huì)收到一個(gè)包含有設(shè)備分配資源信息的啟動(dòng)設(shè)備的IRP,在對(duì)設(shè)備進(jìn)行正確配置后,開(kāi)始與硬件的對(duì)話。在運(yùn)行過(guò)程中,如果設(shè)備被拔除,PnP會(huì)發(fā)出相應(yīng)的IRP,驅(qū)動(dòng)程序會(huì)進(jìn)行盯應(yīng)處理。USB設(shè)備的掛起和喚醒是由電源管理模塊進(jìn)行管理的。I/O功能模塊完成I/O請(qǐng)求的工作。
2.2.3 應(yīng)用程序設(shè)計(jì)
固件程序和USB設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)是USB設(shè)備開(kāi)發(fā)者的工作,對(duì)于廣大用戶而言,與系統(tǒng)的交互是通過(guò)應(yīng)用程序?qū)崿F(xiàn),而且整個(gè)實(shí)時(shí)采集系統(tǒng)的主要數(shù)據(jù)處理都是在這里完成的。因此,運(yùn)行效率高、界面友好、具有強(qiáng)大數(shù)據(jù)分析和處理的應(yīng)用程序的設(shè)計(jì),也是系統(tǒng)設(shè)計(jì)上一個(gè)不容忽視的關(guān)鍵因素。應(yīng)用程序的主要功能有:?jiǎn)?dòng)/關(guān)閉USB設(shè)備,檢測(cè)USB設(shè)備,設(shè)置USB數(shù)據(jù)傳輸管道/端口,設(shè)置A/D,采集數(shù)據(jù),顯示/分析數(shù)據(jù)。這里,我們采用Visual C++6.0作為程序的開(kāi)發(fā)環(huán)境,并且充分運(yùn)用了多線程的編程思想。
在這個(gè)設(shè)備中,設(shè)置4個(gè)線程:首先是1個(gè)主線程,負(fù)責(zé)用戶界面,并保持中樞地位。它的生存周期也就是整個(gè)用戶程序的主存期,用戶的動(dòng)作(例如鼠標(biāo)事件、鍵盤事件)都會(huì)觸發(fā)主線程的消息機(jī)制,從而完成對(duì)用戶的響應(yīng);而3個(gè)分離的輔助線程分別負(fù)責(zé)數(shù)據(jù)的采集、數(shù)據(jù)的分析處理以及數(shù)據(jù)的顯示這3個(gè)不同的任務(wù)。輔助線程是在主線程運(yùn)行過(guò)程中產(chǎn)生的,它的生命就是線程函數(shù)本身,函數(shù)一旦return,線程就結(jié)束了。因此,輔助線程的生存周期只是整個(gè)程序生存期的一部分。
MFC程序只會(huì)有一個(gè)CwinApp對(duì)象,而CwinApp派生自CwinThread,即產(chǎn)生了應(yīng)用程序的主線程。每當(dāng)需要一個(gè)額外的線程時(shí),應(yīng)先產(chǎn)生一個(gè)CwinThread對(duì)象,再調(diào)用全局函數(shù)AfxBeginThread(),將線程產(chǎn)生出來(lái)。
對(duì)于輔助線程(worker thread),要為它準(zhǔn)備一個(gè)線程函數(shù),然后調(diào)用AfxBeginThread()。例如:CWinThread* pThread=AfxBeginThread(ThreadFunc,¶m);
UINT ThreadFunc(LPVOID pParam); //線程函數(shù)
對(duì)于用戶界面線程(UI thread),不能夠光由一個(gè)線程函數(shù)來(lái)代表,因?yàn)樗幚硐?,它需要一個(gè)消息循環(huán)。應(yīng)該先從CWinThread派生一個(gè)自己的類,再調(diào)用AfxBeginThread()產(chǎn)生一個(gè)CWinThread對(duì)象。具體程序見(jiàn)本刊網(wǎng)站(http://www.dpj.com.cn)。
結(jié)語(yǔ)
基于USB技術(shù)的實(shí)時(shí)數(shù)據(jù)采集系統(tǒng),在編程上運(yùn)用了多線程思想;從硬件和軟件兩方面錄求較佳的解決途徑,并將二者結(jié)合起來(lái),在實(shí)際中取得了良好的運(yùn)行效果。