焦杰,王英濤
(1.吉林省廣播電視研究所,長春130041;2.吉林省廣播電視技術(shù)中心臺)
?
用于遠(yuǎn)程廣播監(jiān)測的組合USB設(shè)備接口設(shè)計(jì)
焦杰1,王英濤2
(1.吉林省廣播電視研究所,長春130041;2.吉林省廣播電視技術(shù)中心臺)
介紹了一種應(yīng)用在遠(yuǎn)程廣播無人監(jiān)測點(diǎn)的組合USB設(shè)備,使用一片STM32F407單片機(jī)的單個(gè)OTG_FS同時(shí)設(shè)計(jì)出兩個(gè)設(shè)備接口,其中一個(gè)是監(jiān)測專用的自定義USB設(shè)備,另一個(gè)是標(biāo)準(zhǔn)HID設(shè)備。整個(gè)系統(tǒng)除了具備廣播信號監(jiān)測接收功能之外,還帶有計(jì)算機(jī)運(yùn)行監(jiān)控看門狗、遠(yuǎn)程電源遙控器和一個(gè)遠(yuǎn)程USB鍵盤。對于64位Windows不允許安裝未簽名的自定義設(shè)備驅(qū)動程序問題,采取了WinUSB方案解決。
廣播監(jiān)測;USB;組合設(shè)備;WinUSB;STM32F407
在廣播電視監(jiān)管工作中,需要設(shè)置一些遠(yuǎn)程的無人監(jiān)測站,用于收測當(dāng)?shù)氐膹V播無線電信號,并對節(jié)目的內(nèi)容進(jìn)行自動語音分析,然后利用網(wǎng)絡(luò)把監(jiān)測信息回傳到監(jiān)測中心。系統(tǒng)主要由信號接收監(jiān)測主機(jī)、監(jiān)測計(jì)算機(jī)和網(wǎng)絡(luò)設(shè)備組成。為保證系統(tǒng)長期穩(wěn)定運(yùn)行,還需要具備系統(tǒng)看門狗、遠(yuǎn)程電源遙控、遠(yuǎn)程HID鍵盤等附加功能。監(jiān)測主機(jī)使用一片STM32F407單片機(jī),利用OTG_FS接口設(shè)計(jì)出一種具備信號監(jiān)測、系統(tǒng)看門狗、遠(yuǎn)程鍵盤等多種功能的組合USB設(shè)備,在實(shí)際應(yīng)用中取得了良好的效果。
為了直截了當(dāng)?shù)亟鉀Q困擾USB相關(guān)研發(fā)過程中的幾個(gè)實(shí)際問題,本文用實(shí)例講述研究過程中涉及的主要技術(shù)點(diǎn)。
① 如何設(shè)計(jì)多功能的USB組合設(shè)備: 在一片STM32F407的OTG_FS接口上實(shí)現(xiàn)兩個(gè)USB設(shè)備,一個(gè)是自定義的廣播監(jiān)測接收設(shè)備,另一個(gè)是HID鍵盤設(shè)備。
② 怎樣解決64位Windows系統(tǒng)的驅(qū)動程序: 64位Windows不允許安裝未簽名的驅(qū)動程序,限制了自定義USB設(shè)備的應(yīng)用。針對這一問題,本文介紹一種采用WinUSB的解決方案,可以實(shí)現(xiàn)從Windows XP SP2到Windows 10,無論32位還是64位系統(tǒng)全兼容。
③ 實(shí)現(xiàn)Windows系統(tǒng)中應(yīng)用程序: 設(shè)計(jì)應(yīng)用程序與自定義USB設(shè)備通信、控制設(shè)備,并傳輸大量的廣播節(jié)目聲音數(shù)據(jù)。
④ 系統(tǒng)管理與遠(yuǎn)程HID鍵盤: 利用USB通信實(shí)現(xiàn)系統(tǒng)運(yùn)行看門狗,并結(jié)合網(wǎng)絡(luò)實(shí)現(xiàn)遠(yuǎn)程電源遙控和遠(yuǎn)程HID鍵盤功能。
整個(gè)監(jiān)測前端由信號接收監(jiān)測主機(jī)、監(jiān)測計(jì)算機(jī)和網(wǎng)絡(luò)設(shè)備三大部分組成,其中的信號接收監(jiān)測主機(jī)也兼用作遠(yuǎn)程電源遙控器、遠(yuǎn)程USB鍵盤和系統(tǒng)運(yùn)行看門狗。遠(yuǎn)程廣播監(jiān)測前端結(jié)構(gòu)框圖如圖1所示。

圖1 遠(yuǎn)程廣播監(jiān)測前端結(jié)構(gòu)框圖
信號接收監(jiān)測主機(jī)中的接收電路完成廣播信號的接收,編碼后的聲音數(shù)據(jù)由STM32F407單片機(jī)利用USB接口送給監(jiān)測計(jì)算機(jī)。監(jiān)測主機(jī)具有網(wǎng)絡(luò)接口,可以接收監(jiān)測中心的電源遙控命令,遠(yuǎn)程開啟或關(guān)閉計(jì)算機(jī),甚至可以遠(yuǎn)程關(guān)閉網(wǎng)絡(luò)設(shè)備的電源。
監(jiān)測計(jì)算機(jī)需要定期向單片機(jī)的USB控制接口發(fā)送握手命令,如果單片機(jī)在較長的時(shí)間內(nèi)不能收到USB握手信息,那么就認(rèn)為監(jiān)測計(jì)算機(jī)發(fā)生故障,利用電源控制電路關(guān)閉計(jì)算機(jī)電源,過一段時(shí)間再自動打開,實(shí)現(xiàn)自動重啟計(jì)算機(jī)。
單片機(jī)在一個(gè)OTG_FS接口上組合了兩個(gè)USB設(shè)備:一個(gè)具有聲音數(shù)據(jù)接口及控制接口的自定義設(shè)備和一個(gè)HID遠(yuǎn)程鍵盤。當(dāng)監(jiān)測計(jì)算機(jī)發(fā)生特殊故障,不能進(jìn)入系統(tǒng)時(shí),利用這個(gè)遠(yuǎn)程鍵盤可以幫助遠(yuǎn)程排除故障。
單片機(jī)采用USB接口與計(jì)算機(jī)通信的電路非常簡單,只需把STM32F407的OTG_FS引腳經(jīng)匹配電阻聯(lián)接到計(jì)算機(jī)的USB口即可。單片機(jī)USB接口部分電路圖如圖2所示。

圖2 單片機(jī)USB接口部分電路圖
可以在一個(gè)USB接口上實(shí)現(xiàn)多個(gè)USB設(shè)備,最常見的是那種只有一個(gè)USB插頭的無線鍵盤鼠標(biāo)組合。有兩種方法能夠在一個(gè)USB接口上實(shí)現(xiàn)多個(gè)設(shè)備:一種是復(fù)合設(shè)備(Compound Device),另一種是組合設(shè)備(Composite Device)。復(fù)合設(shè)備就是把幾個(gè)獨(dú)立的USB設(shè)備用HUB連接在一起,每個(gè)設(shè)備有各自獨(dú)立的設(shè)備ID。而組合設(shè)備是在一個(gè)設(shè)備上實(shí)現(xiàn)多個(gè)接口,它們共用同一個(gè)設(shè)備ID。復(fù)合設(shè)備中有HUB,具有繼續(xù)向下級連其他設(shè)備的潛力,但是這種設(shè)計(jì)比較復(fù)雜,占用資源較多。相比之下,如果想要實(shí)現(xiàn)同樣的功能,設(shè)計(jì)組合設(shè)備會更為簡單方便。
2.1 實(shí)現(xiàn)USB組合設(shè)備框架
因?yàn)閁SB設(shè)備比較復(fù)雜,所以從零開始設(shè)計(jì)絕對不是個(gè)好主意,利用現(xiàn)成的例子進(jìn)行改造會方便得多。在STM32F407單片機(jī)固件庫中,有一個(gè)USB FS Examples USB_Device_Examples HID例子,可以在它的基礎(chǔ)之上修改得到所需要的USB功能。其中有兩個(gè)關(guān)鍵問題:需要知道在哪里改和明白應(yīng)該改成什么。
首先需要修改那些描述符,實(shí)現(xiàn)設(shè)備的基本框架。因?yàn)樵O(shè)備描述符部分只需要改PID和VID,比較容易,所以主要的工作內(nèi)容是修改配置描述符、接口描述符和端點(diǎn)描述符。例子程序把這幾個(gè)描述符按順序排列在USBD_HID_CfgDesc數(shù)組中。原來描述符結(jié)構(gòu)需要修改成新結(jié)構(gòu),如圖3所示。

圖3 描述符結(jié)構(gòu)的修改
2.1.1 修改USB設(shè)備ID
所有PNP設(shè)備都必須具有設(shè)備ID,修改usbd_desc.c中的USBD_VID和USBD_PID,改成不會與其他設(shè)備沖突的數(shù)值,這兩個(gè)數(shù)值還要寫到安裝驅(qū)動程序所需的那個(gè)INF文件中。
2.1.2 設(shè)計(jì)通信端點(diǎn)
在usbd_conf.h中添加聲音及其他端點(diǎn)號,并設(shè)定端點(diǎn)包長度。因?yàn)樵祭邮荋ID鼠標(biāo),所以只有HID_IN_EP一個(gè)IN端點(diǎn)。改成鍵盤需要增加一個(gè)OUT端點(diǎn)HID_OUT_EP,它可以接收到鍵盤上指示燈的狀態(tài)信息。為了能傳輸大量的聲音數(shù)據(jù),需要再新加兩個(gè)IN端點(diǎn)VENDOR_IN_EP_AUDIO1和VENDOR_IN_EP_AUDIO2,并多加一個(gè)OUT端點(diǎn)VENDOR_OUT_EP,用于向自定義設(shè)備寫出數(shù)據(jù)。因?yàn)殒I盤的數(shù)據(jù)包比鼠標(biāo)大,所以需要改大HID端點(diǎn)包長度為64。
2.1.3 配置端點(diǎn)FIFO
使用STM32F407單片機(jī)的OTG_FS進(jìn)行設(shè)計(jì),需要修改usb_conf.h,為各端點(diǎn)重新分配FIFO長度。必須注意在原始例子默認(rèn)狀態(tài)下,只有EP0和EP1是可用的,其他端點(diǎn)因沒有分配過FIFO所以還不能用。需要用哪個(gè)端點(diǎn)就必須給它分配FIFO,特別要注意STM32F407的FIFO總共有320字節(jié),各端點(diǎn)FIFO加起來的總數(shù)量不可以超過這個(gè)總長度。
2.1.4 修改配置描述符
在usbd_hid_core.c設(shè)計(jì)配置描述符,也就是修改USBD_HID_CfgDesc數(shù)組,把bNumInterfaces從1改成2,表示有HID鍵盤和自定義設(shè)備共計(jì)兩個(gè)接口。再把接口描述符的bNumEndpoints從1改成2,表示這個(gè)HID鍵盤接口上有兩個(gè)端點(diǎn);nInterfaceProtocol從2改成1表示把鼠標(biāo)改成鍵盤。
在原來HID端點(diǎn)描述符之后,仿照原來的IN端點(diǎn)添加一個(gè)新的HID_OUT_EP端點(diǎn)描述符。注意鍵盤鼠標(biāo)端點(diǎn)的bmAttributes是3,表示采用中斷傳輸模式。
2.1.5 添加自定義設(shè)備的描述符
在HID端點(diǎn)描述符之后添加自定義設(shè)備的接口描述符,可以復(fù)制前面的HID接口描述符,在其基礎(chǔ)上進(jìn)行修改:
① bInterfaceNumber是順序號,在前面的HID接口描述符里是0,所以輪到這個(gè)需要用1。注意這個(gè)值與后面驅(qū)動程序安裝有關(guān),在后面介紹WinUSB驅(qū)動程序安裝時(shí)會再次看到它的作用。
② bNumEndpoints是端點(diǎn)數(shù)量,自定義的監(jiān)測設(shè)備有3個(gè)端點(diǎn)(bInterfaceClass、bInterfaceSubClass、nInterfaceProtocol),改成0xff、0x00、0x00表示自定義的設(shè)備。在接口描述符后面,依次羅列這三個(gè)端點(diǎn)描述符,仿照HID端點(diǎn)描述符填寫即可。
2.1.6 修改HID報(bào)告描述符
HID鍵盤還需要一個(gè)報(bào)告描述符,因?yàn)檫@個(gè)鍵盤不需要支持特殊的按鍵和指示燈,所以可以隨便找一個(gè)現(xiàn)成的例子。替換原來的鼠標(biāo)報(bào)告描述符HID_MOUSE_ReportDesc,并注意修改程序中所有涉及到報(bào)告描述符的長度數(shù)值。
2.2 實(shí)現(xiàn)USB組合設(shè)備的固件接口程序
把修改數(shù)據(jù)之后形成的組合設(shè)備框架編譯寫入STM32F407,接到計(jì)算機(jī)上就可以看到在設(shè)備管理器窗口中會多出來三個(gè)設(shè)備:USB Composite Device、HID鍵盤和沒有驅(qū)動程序的未知設(shè)備。
2.2.1 新添加端點(diǎn)的打開與關(guān)閉
在usbd_hid_core.c中添加新端點(diǎn)的打開與關(guān)閉消息調(diào)用程序代碼。USBD_HID_Init函數(shù)中,原來有一個(gè)DCD_EP_Open,它只打開了鼠標(biāo)的IN端口。仿照樣子添加打開新定義的HID_OUT_EP、VENDOR_OUT_EP、VENDOR_IN_EP_AUDIO1和 VENDOR_IN_EP_AUDIO2端口。在USBD_HID_DeInit函數(shù)中添加DCD_EP_Close,把這幾個(gè)新端口關(guān)閉。
2.2.2 非0端點(diǎn)數(shù)據(jù)收發(fā)
非0端點(diǎn)可以進(jìn)行中斷傳輸或塊傳輸,在usbd_hid_core.c中添加自定義設(shè)備與計(jì)算機(jī)軟件塊傳輸?shù)慕涌诔绦虼a,固件庫采用函數(shù)回調(diào)的方式來添加這些功能。在數(shù)據(jù)結(jié)構(gòu)USBD_HID_cb中有一個(gè)DataOut,在那里設(shè)置一個(gè)回調(diào)函數(shù)USBD_VENDOR_DataOut (void *pdev, uint8_t epnum)。當(dāng)計(jì)算機(jī)發(fā)送數(shù)據(jù)到設(shè)備的非0端點(diǎn)時(shí),會觸發(fā)這個(gè)函數(shù)回調(diào),并傳入?yún)?shù)epnum表明數(shù)據(jù)要發(fā)送到哪個(gè)端點(diǎn),用USBD_GetRxCount庫函數(shù)可以取得本次單片機(jī)收到的數(shù)據(jù)字節(jié)數(shù)。
在數(shù)據(jù)結(jié)構(gòu)USBD_HID_cb中有一個(gè)SOF和一個(gè)DataIn,在那里設(shè)置兩個(gè)回調(diào)函數(shù),即USBD_VENDOR_SOF(void *pdev)和USBD_VENDOR_DataIn (void *pdev, uint8_t epnum)。USB總線的SOF信號會引起周期性地回調(diào)USBD_VENDOR_SOF,可以把這個(gè)函數(shù)回調(diào)作為可以向計(jì)算機(jī)上傳數(shù)據(jù)的啟動信號。每當(dāng)設(shè)備向計(jì)算機(jī)發(fā)完一組數(shù)據(jù)之后,都將回調(diào)USBD_HID_DataIn函數(shù)。因此配合運(yùn)用SOF回調(diào)結(jié)合USBD_HID_DataIn函數(shù),在它們的處理函數(shù)中再使用DCD_EP_Tx庫函數(shù),可以高速向計(jì)算機(jī)發(fā)送大批量的數(shù)據(jù)。非零端點(diǎn)數(shù)據(jù)發(fā)送中斷回調(diào)與主程序聯(lián)動流程圖如圖4所示。

圖4 非零端點(diǎn)數(shù)據(jù)發(fā)送中斷回調(diào)與主程序聯(lián)動流程圖
利用“正發(fā)送標(biāo)志”來協(xié)調(diào)運(yùn)用這兩個(gè)回調(diào)函數(shù),可以快速傳輸大量的聲音數(shù)據(jù)。
2.2.3 專用控制端點(diǎn)0的數(shù)據(jù)收發(fā)
端點(diǎn)0是特殊的控制端點(diǎn),在usbd_req.c中,有一個(gè)USBD_StdDevReq函數(shù),每個(gè)對設(shè)備EP0的控制傳輸都會調(diào)用這里。USB_SETUP_REQ 結(jié)構(gòu)保存著從計(jì)算機(jī)發(fā)來的控制數(shù)據(jù)。對于查詢少量數(shù)據(jù)信息的命令,可以直接調(diào)用USBD_CtlSendData庫函數(shù)傳送一些數(shù)據(jù)應(yīng)答到計(jì)算機(jī)。而對于執(zhí)行較慢的設(shè)置,有必要聯(lián)合運(yùn)用主程序main函數(shù)設(shè)計(jì)成異步工作方式。圖5是單片機(jī)異步控制、主程序聯(lián)動工作流程圖。

圖5 端點(diǎn)0異步控制中斷回調(diào)與主程序聯(lián)動流程圖
上位計(jì)算機(jī)把一個(gè)慢速異步設(shè)置分解成“設(shè)置”和“查詢”兩個(gè)步驟,先通知單片機(jī)進(jìn)行設(shè)置,之后需要定期查詢設(shè)置被執(zhí)行的結(jié)果。單片機(jī)收到“設(shè)置”命令之后,緩存設(shè)置參數(shù)退出EP0控制傳輸處理子程序;然后主程序取得緩存的參數(shù)執(zhí)行這個(gè)設(shè)置,把設(shè)置結(jié)論緩存起來供上位計(jì)算機(jī)進(jìn)行查詢。整個(gè)“設(shè)置”與“查詢”兩個(gè)任務(wù)過程的協(xié)調(diào)核心數(shù)據(jù)是“執(zhí)行狀態(tài)標(biāo)志”變量,0表示空閑沒有任務(wù);1表示已收到任務(wù)命令但還未執(zhí)行;2表示任務(wù)已開始執(zhí)行;3表示任務(wù)已經(jīng)執(zhí)行完畢可查詢到執(zhí)行結(jié)果。
2.2.4 HID鍵盤收發(fā)數(shù)據(jù)
前面在定義端點(diǎn)時(shí),HID鍵盤使用兩個(gè)中斷類型端點(diǎn)HID_IN_EP和HID_OUT_EP收發(fā)數(shù)據(jù)。利用HID_IN_EP端點(diǎn),可以把從網(wǎng)絡(luò)遠(yuǎn)程傳來的數(shù)據(jù)轉(zhuǎn)成鍵盤按鍵信息。
一條按鍵信息有8個(gè)字節(jié):
第一字節(jié)為SHIFT、CTRL等特殊控制鍵的位組合,每位代表一個(gè)按鍵;
第二字節(jié)為保留字節(jié);
后面字節(jié)為每一個(gè)字節(jié)都可以填入鍵盤掃描碼,支持6個(gè)鍵同時(shí)按下。
主程序可以調(diào)用DCD_EP_Tx庫函數(shù)向計(jì)算機(jī)發(fā)送鍵盤信息,一次鍵盤信息由一個(gè)按鍵通碼和一個(gè)斷碼組成。用于系統(tǒng)維護(hù)的遠(yuǎn)程鍵盤不需要支持同時(shí)多按鍵功能,也不需要特殊控制鍵。如果想要按一下回車鍵,那么發(fā)送通碼數(shù)據(jù)是{0,0,0x28,0,0,0,0,0},斷碼是8個(gè)0。
在Windows系統(tǒng)中,組合USB設(shè)備的這個(gè)HID鍵盤不需要額外的驅(qū)動程序,而自定義的USB設(shè)備必須安裝驅(qū)動程序。64位系統(tǒng)對驅(qū)動程序的要求較為嚴(yán)格,只有經(jīng)過數(shù)字簽名的驅(qū)動程序才可以正常安裝。本文介紹使用系統(tǒng)自帶的WinUSB驅(qū)動程序可以滿足自定義USB設(shè)備的需要。
3.1 WinUSB簡介
WinUSB是Windows系統(tǒng)自帶的USB驅(qū)動程序,用它可以讓自定義的USB設(shè)備在XP、Vista、Win7、Win8、Win10上得到全面的支持,不論是32位還是64位,都能兼容。驅(qū)動開發(fā)工作僅僅是再提供一個(gè)INF文件去安裝自定義的USB設(shè)備。
3.2 WinUSB驅(qū)動程序安裝
在MSDN,有一篇名為《WinUSB (Winusb.sys) 安裝》[3]的文章,里面可以找到安裝過程的介紹。除非有特殊的問題要查找,否則不需要細(xì)看那些內(nèi)容,直接從“編寫適用于WinUSB安裝的自定義INF”那段復(fù)制INF例子內(nèi)容,在其基礎(chǔ)上修改成自己的安裝程序。
對于普通的USB設(shè)備,只需找到%DeviceName% =USB_Install, USBVID_0547&PID_1002那行,改成前面在usbd_desc.c中的USBD_VID和USBD_PID就可以了。然而對于本文介紹的這種組合USB設(shè)備,還需要在PID的后面增加接口序號。在前面介紹接口描述符時(shí),自定義設(shè)備的接口號是1,所以設(shè)備名要寫成:USBVID_0547&PID_1002&MI_01。
INF文件中還有一節(jié):
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{9f543223-cede-4fa3-b376-a25ce9a30e74}"
需要注意這行與應(yīng)用程序枚舉驅(qū)動程序有關(guān),這個(gè)GUID在本文后面設(shè)計(jì)應(yīng)用程序時(shí)會用到。
應(yīng)用程序必須調(diào)用Winusb.dll與自定義的USB設(shè)備通信,其接口說明在參考文獻(xiàn)[4]中有介紹,應(yīng)用程序接口設(shè)計(jì)在參考文獻(xiàn)[5]中有較詳細(xì)的介紹,并提供了代碼。這里不重復(fù)介紹其內(nèi)容,只對容易出現(xiàn)的問題提供解決方法。
4.1 準(zhǔn)備Winusb.dll的接口H文件
為了讓應(yīng)用程序代碼適用于多種編譯環(huán)境,建議采用動態(tài)加載Winusb.dll的方法來控制自定義的USB設(shè)備。對應(yīng)的接口H文件Winusb.h可以在WDK中找到。
4.2 枚舉自定義的組合USB設(shè)備
在MSDN中介紹了用SetupDiGetClassDevs和SetupDiEnumDeviceInterfaces這兩個(gè)API來枚舉USB設(shè)備,需要注意輸入的GUID參數(shù)。本文在前面介紹INF文件提到過這行:

圖6 用控制線程強(qiáng)制退出數(shù)據(jù)讀阻塞的流程
HKR,,DeviceInterfaceGUIDs,0x10000,"{9f543223-cede-4fa3-b376-a25ce9a30e74}"
必須用這里的GUID進(jìn)行枚舉,才能正確找到這個(gè)自定義設(shè)備。在枚舉成功之后,用Setup DiGet Device Interface Detail取得設(shè)備驅(qū)動的設(shè)備路徑實(shí)例,應(yīng)用程序可以利用WM_DEVICECHANGE消息,在處理函數(shù)中枚舉設(shè)備在線情況,可以對USB的熱插拔進(jìn)行及時(shí)處理。
4.3 打開與關(guān)閉設(shè)備驅(qū)動
用API函數(shù)CreateFile打開設(shè)備,可以得到自定義設(shè)備的文件句柄。為了使用WinUSB,要求這個(gè)API的參數(shù)必須設(shè)置FILE_FLAG_OVERLAPPED標(biāo)志。
在WinUSB.dll中,所有函數(shù)都用WinUsb_開頭。WinUsb_Initialize利用設(shè)備的文件句柄創(chuàng)建一個(gè)WinUSB接口句柄,如果出錯(cuò),很可能是枚舉時(shí)用錯(cuò)了GUID。成功創(chuàng)建之后就可以調(diào)用WinUSB的其他函數(shù)與單片機(jī)通信了。在程序退出或設(shè)備撤出時(shí),必須調(diào)用CloseHandle關(guān)閉設(shè)備,用WinUsb_Free關(guān)閉WinUSB接口句柄。
4.4 控制端點(diǎn)EP0通信
本文在前面介紹單片機(jī)的控制端點(diǎn)EP0時(shí),提到過USB_SETUP_REQ 結(jié)構(gòu)。在WinUsb中有一個(gè)對應(yīng)的WINUSB_SETUP_PACKET數(shù)據(jù)結(jié)構(gòu),它們是同樣的數(shù)據(jù)結(jié)構(gòu)。也就是說,應(yīng)用程序調(diào)用WinUsb_ControlTransfer時(shí),會把WINUSB_SETUP_PACKET參數(shù)原樣送給單片機(jī),然后單片機(jī)用USBD_CtlSendData庫函數(shù)應(yīng)答的數(shù)據(jù)會填充到WinUsb_ControlTransfer的Buffer參數(shù)里返回給應(yīng)用程序。
4.5 非0端點(diǎn)塊傳輸通信
應(yīng)用程序調(diào)用WinUsb_WritePipe向單片機(jī)寫入塊數(shù)據(jù),會觸發(fā)單片機(jī)中USBD_HID_cb結(jié)構(gòu)上那個(gè)DataOut函數(shù)回調(diào)接收數(shù)據(jù)。單片機(jī)用DCD_EP_Tx庫函數(shù)發(fā)出的數(shù)據(jù)可以在應(yīng)用程序中調(diào)用WinUsb_ReadPipe讀取。
通常為簡化程序設(shè)計(jì),所以設(shè)置WinUsb_WritePipe和WinUsb_ReadPipe的Overlapped參數(shù)為NULL。在此情況下,這兩個(gè)函數(shù)都是阻塞的,如果出現(xiàn)某種情況,單片機(jī)不能提供足夠的數(shù)據(jù)供計(jì)算機(jī)讀取,或者不能接收計(jì)算機(jī)發(fā)出的數(shù)據(jù),都會導(dǎo)致計(jì)算機(jī)程序鎖死在那里,不能繼續(xù)向下執(zhí)行。圖6描述了一個(gè)在數(shù)據(jù)讀取阻塞時(shí),利用控制線程強(qiáng)制退出阻塞狀態(tài)的流程。因此有必要利用多任務(wù)把數(shù)據(jù)管道讀或?qū)懙墓δ塥?dú)立到另一個(gè)線程中,主程序線程利用控制端點(diǎn)EP0來控制單片機(jī)那里對數(shù)據(jù)的接收和發(fā)送,在特殊情況下可以通知單片機(jī)強(qiáng)制接收并丟棄數(shù)據(jù),或者胡亂發(fā)送一些填充數(shù)據(jù),這樣就可以跳出WinUsb_WritePipe和WinUsb_ReadPipe的阻塞狀態(tài)。
對整個(gè)監(jiān)測系統(tǒng)的管理就是看門狗與遠(yuǎn)程遙控管理,遠(yuǎn)程控制功能有計(jì)算機(jī)遠(yuǎn)程遙控軟件和網(wǎng)絡(luò)遠(yuǎn)程遙控硬件兩個(gè)組成部分。
5.1 遠(yuǎn)程電源管理器
計(jì)算機(jī)系統(tǒng)運(yùn)行正常是所有計(jì)算機(jī)遠(yuǎn)程遙控軟件可以正常使用的根本前提。一旦Windows系統(tǒng)死機(jī)或者進(jìn)不去了,那么再優(yōu)秀的遙控軟件也都無計(jì)可施。在這種情況下,解決的辦法就只剩下計(jì)算機(jī)斷電重啟了。
使用STM32F407固件庫中的LwIP設(shè)計(jì)一個(gè)網(wǎng)絡(luò)WEB服務(wù)器程序,實(shí)現(xiàn)遠(yuǎn)程在頁面上遙控單片機(jī)的一個(gè)I/O口電平,只需將這個(gè)I/O口連接到一個(gè)由三極管控制的繼電器上,就能實(shí)現(xiàn)對計(jì)算機(jī)電源的遙控功能。
用類似的方法可以設(shè)計(jì)網(wǎng)絡(luò)設(shè)備的遠(yuǎn)程遙控電路。然而當(dāng)網(wǎng)絡(luò)設(shè)備斷電之后,整個(gè)前端就無法再繼續(xù)遙控了,因此單片機(jī)對網(wǎng)絡(luò)的控制邏輯是斷電后延時(shí)幾分鐘再自動加電。
5.2 計(jì)算機(jī)系統(tǒng)運(yùn)行看門狗
系統(tǒng)中有兩大看門狗,一個(gè)是計(jì)算機(jī)運(yùn)行看門狗,另一個(gè)是網(wǎng)絡(luò)運(yùn)行看門狗。計(jì)算機(jī)必須定期通過USB向單片機(jī)的VENDOR_OUT_EP端點(diǎn)發(fā)出喂狗命令,否則單片機(jī)就會認(rèn)為計(jì)算機(jī)發(fā)生故障而自動關(guān)閉計(jì)算機(jī)電源,過幾分鐘自動通電再讓它重啟動。
在單片機(jī)中記錄著監(jiān)測中心服務(wù)器的IP地址,并且會定期主動聯(lián)接服務(wù)器的一個(gè)特定TCP端口。一旦單片機(jī)長時(shí)間始終無法與服務(wù)器聯(lián)接,就認(rèn)為網(wǎng)絡(luò)設(shè)備發(fā)生故障,將自動對網(wǎng)絡(luò)設(shè)備斷電,然后延遲一段時(shí)間再上電,實(shí)現(xiàn)網(wǎng)絡(luò)設(shè)備遇到故障時(shí)的復(fù)位重新啟動。
5.3 遠(yuǎn)程HID鍵盤
有時(shí)計(jì)算機(jī)會卡在系統(tǒng)啟動期間,需要現(xiàn)場操作鍵盤解決。例如64位WIN7有時(shí)發(fā)生故障會卡在“系統(tǒng)修復(fù)”界面,在這種情況下,如果沒人去按一下鍵盤回車鍵,那么就不能繼續(xù)啟動運(yùn)行。這種系統(tǒng)故障發(fā)生時(shí),因?yàn)橄到y(tǒng)沒起來,遠(yuǎn)程軟件還沒啟動,所以任何軟件辦法都失靈,只有
依靠設(shè)計(jì)在組合USB設(shè)備中的HID鍵盤來執(zhí)行遠(yuǎn)程系統(tǒng)修復(fù)了。在監(jiān)測中心利用網(wǎng)絡(luò)遠(yuǎn)程登陸單片機(jī)的WEB服務(wù)器,在頁面上點(diǎn)擊“發(fā)送回車鍵”按鈕,單片機(jī)就可以把一個(gè)回車按鍵信息的一個(gè)通碼附加上一個(gè)斷碼從USB輸入計(jì)算機(jī),就像在那個(gè)監(jiān)測點(diǎn)現(xiàn)場直接鍵入回車信息一樣。有了這樣一種遠(yuǎn)程鍵盤,即使遠(yuǎn)程無人前端進(jìn)入不了系統(tǒng),或者沒有遠(yuǎn)程遙控軟件,也可維護(hù)計(jì)算機(jī)了。

[1] 張秀娟,梁波.多功能USB組合設(shè)備的結(jié)構(gòu)設(shè)計(jì)[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2011(11).
[2] Microsoft提供的USB驅(qū)動程序[EB/OL].[2016-05-30].https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff538853(v=vs.85).aspx.
[3] WinUSB (Winusb.sys)安裝[EB/OL].[2016-05-30].https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff540283.
[4] WinUSB Functions[EB/OL].[2016-05-30].https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff540046 (v=vs.85). aspx#winusb.
[5] 編寫基于WinUSB模板的Windows 桌面應(yīng)用[EB/OL].[2016-05-30].https://msdn.microsoft.com/zh-cn/library/windows/hardware/dn376872(v=vs.85).aspx.
[6] STMicroelectronics.STM32F405xx/07xx advanced ARM-based 32-bit MCUs Reference manual,2013.
焦杰(工程師),主要研究方向?yàn)閺V播電視信號監(jiān)測與控制技術(shù);王英濤(高級工程師),主要從事調(diào)頻廣播和無線電視信號播出工作。
(責(zé)任編輯:楊迪娜 收修改稿日期:2016-09-30)
Design of USB Composite Device Interface for Remote Broadcast Monitoring
Jiao Jie1,Wang Yingtao2
(1.Radio&Television Research Institute of Jilin Province,Changchun 130041,China;2.Radio&Television Technology Center Station of Jilin Province)
In the paper,a USB composite device for broadcasting remote monitoring based on a STM32F407 microcontroller is introduced.Two device interfaces are designed by one OTG_FS circuit interface.The one is the custom USB device,the other one is the standard HID device.In addition to the radio signal receiving and monitoring,some other functions are designed,such as a power controller and a USB keyboard both from the remote network,and a watchdog of computer system is designed.For 64-bit Windows does not allow the installation of the unsigned custom device driver issues,the paper introduces WinUSB to solve it.
broadcasting monitoring;USB;composite device;WinUSB;STM32F407
TP37
A