
本系統(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í)簡化了編程和調(diào)試。它的基本思想是:后臺(tái)ISR(中斷服務(wù)程序)和前臺(tái)主程序循環(huán)之間的數(shù)據(jù)交換通過事件標(biāo)志和數(shù)據(jù)緩沖區(qū)來實(shí)現(xiàn)。當(dāng)PDIUSBD12從USB收到一個(gè)數(shù)據(jù)包時(shí),就對單片機(jī)產(chǎn)生一個(gè)中斷請求,單片機(jī)立即響應(yīng)中斷。在ISR中,固件將數(shù)據(jù)包從FDIUSBD12內(nèi)部緩沖區(qū)移到循環(huán)數(shù)據(jù)緩沖區(qū),并在隨后請求清零PDIUSBD12的內(nèi)部緩沖區(qū),以使其能接收新的數(shù)據(jù)包。然后返回到主循環(huán),檢查循環(huán)緩沖區(qū)內(nèi)是否有新的數(shù)據(jù)并開始其它的前臺(tái)任務(wù)。
基于這種結(jié)構(gòu),主循環(huán)不關(guān)心數(shù)據(jù)是來自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請求,處理USB總線事件和用戶功能處理等;
硬件提以層——對單片機(jī)的I/O口、數(shù)據(jù)總線等硬件接口進(jìn)行操作;
PDIUSBD12命令接口——對PDIUSBD12器件進(jìn)行操作的模塊子程序集;
請求處理程序——對USB的標(biāo)準(zhǔn)設(shè)備請求進(jìn)行處理和對用戶添加的廠商請求進(jìn)行處理;
中斷服務(wù)程序——當(dāng)PDIUSBD12向單片機(jī)發(fā)出中斷請求時(shí),讀取PDIUSBD12的中斷傳輸來的數(shù)據(jù),并設(shè)定事件標(biāo)志和Setup包數(shù)據(jù)緩沖區(qū),傳輸給主循環(huán)。
2.2.2 USB設(shè)備驅(qū)動(dòng)設(shè)計(jì)
在Windows下,與USB外設(shè)的任何通信必須通過USB設(shè)備驅(qū)動(dòng),這個(gè)驅(qū)動(dòng)知道如何與系統(tǒng)的USB驅(qū)動(dòng)和訪問設(shè)備的應(yīng)用程序通信。設(shè)備驅(qū)動(dòng)是保證應(yīng)用程序訪問硬件設(shè)備的軟件組件,使得應(yīng)用程序不必知道物理連接、信號和與一個(gè)設(shè)備通信需要的協(xié)議等的細(xì)節(jié),可以保證應(yīng)用程序代碼只通過外設(shè)名字訪問外設(shè)或端口目的地。應(yīng)用程序不需要知道外設(shè)連接端口的物理地址,不需要精確監(jiān)視和控制外設(shè)需要的交換信號。
設(shè)備驅(qū)動(dòng)通過在應(yīng)用層和硬件專用代碼之間的轉(zhuǎn)化來完成它的任務(wù)。應(yīng)用層代碼一般使用一套操作系統(tǒng)支持的函數(shù),硬件代碼則處理那些訪問外設(shè)電路的必要協(xié)議。設(shè)備驅(qū)動(dòng)能與應(yīng)用程序之間相互通信是通過Windows提供的API函數(shù),這些函數(shù)使應(yīng)用程序能夠控制顯示器、處理信息、訪問存儲(chǔ)器、讀寫磁盤和其它設(shè)備。對于一些標(biāo)準(zhǔn)設(shè)備,
Windows提供通用驅(qū)動(dòng);不過,這個(gè)實(shí)時(shí)數(shù)據(jù)采集系統(tǒng)是自定義的設(shè)備,對此Windows并不提供通用的驅(qū)動(dòng),需要對設(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è)備開發(fā)包(98DDK/NTDDK)。USB設(shè)備驅(qū)動(dòng)的編寫通常不是一項(xiàng)簡單的任務(wù),驅(qū)動(dòng)開發(fā)包就提供一種途徑,通過做盡可能多的工作為跳過驅(qū)動(dòng)開發(fā),這些開發(fā)庫有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)來執(zhí)行大量的初始化函數(shù)。即插用模塊實(shí)現(xiàn)USB設(shè)備的動(dòng)態(tài)插拔及配置。當(dāng)硬件檢測到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,在對設(shè)備進(jìn)行正確配置后,開始與硬件的對話。在運(yùn)行過程中,如果設(shè)備被拔除,PnP會(huì)發(fā)出相應(yīng)的IRP,驅(qū)動(dòng)程序會(huì)進(jìn)行盯應(yīng)處理。USB設(shè)備的掛起和喚醒是由電源管理模塊進(jìn)行管理的。I/O功能模塊完成I/O請求的工作。
2.2.3 應(yīng)用程序設(shè)計(jì)
固件程序和USB設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)是USB設(shè)備開發(fā)者的工作,對于廣大用戶而言,與系統(tǒng)的交互是通過應(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)用程序的主要功能有:啟動(dòng)/關(guān)閉USB設(shè)備,檢測USB設(shè)備,設(shè)置USB數(shù)據(jù)傳輸管道/端口,設(shè)置A/D,采集數(shù)據(jù),顯示/分析數(shù)據(jù)。這里,我們采用Visual C++6.0作為程序的開發(fā)環(huán)境,并且充分運(yùn)用了多線程的編程思想。
在這個(gè)設(shè)備中,設(shè)置4個(gè)線程:首先是1個(gè)主線程,負(fù)責(zé)用戶界面,并保持中樞地位。它的生存周期也就是整個(gè)用戶程序的主存期,用戶的動(dòng)作(例如鼠標(biāo)事件、鍵盤事件)都會(huì)觸發(fā)主線程的消息機(jī)制,從而完成對用戶的響應(yīng);而3個(gè)分離的輔助線程分別負(fù)責(zé)數(shù)據(jù)的采集、數(shù)據(jù)的分析處理以及數(shù)據(jù)的顯示這3個(gè)不同的任務(wù)。輔助線程是在主線程運(yùn)行過程中產(chǎn)生的,它的生命就是線程函數(shù)本身,函數(shù)一旦return,線程就結(jié)束了。因此,輔助線程的生存周期只是整個(gè)程序生存期的一部分。
MFC程序只會(huì)有一個(gè)CwinApp對象,而CwinApp派生自CwinThread,即產(chǎn)生了應(yīng)用程序的主線程。每當(dāng)需要一個(gè)額外的線程時(shí),應(yīng)先產(chǎn)生一個(gè)CwinThread對象,再調(diào)用全局函數(shù)AfxBeginThread(),將線程產(chǎn)生出來。
對于輔助線程(worker thread),要為它準(zhǔn)備一個(gè)線程函數(shù),然后調(diào)用AfxBeginThread()。例如:CWinThread* pThread=AfxBeginThread(ThreadFunc,¶m);
UINT ThreadFunc(LPVOID pParam); //線程函數(shù)
對于用戶界面線程(UI thread),不能夠光由一個(gè)線程函數(shù)來代表,因?yàn)樗幚硐,它需要一個(gè)消息循環(huán)。應(yīng)該先從CWinThread派生一個(gè)自己的類,再調(diào)用AfxBeginThread()產(chǎn)生一個(gè)CWinThread對象。具體程序見本刊網(wǎng)站(http://www.dpj.com.cn)。
結(jié)語
基于USB技術(shù)的實(shí)時(shí)數(shù)據(jù)采集系統(tǒng),在編程上運(yùn)用了多線程思想;從硬件和軟件兩方面錄求較佳的解決途徑,并將二者結(jié)合起來,在實(shí)際中取得了良好的運(yùn)行效果。





