日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何让CDC类USB设备批量接收64字节以上数据

發(fā)布時間:2024/3/13 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何让CDC类USB设备批量接收64字节以上数据 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

很多STM32開發(fā)者在實(shí)現(xiàn)CDC類虛擬串口與PC主機(jī)通信過程中,有時會遇到點(diǎn)麻煩而不得其解。那就是當(dāng)主機(jī)端單次發(fā)送的數(shù)據(jù)不超過64字節(jié)時,接收正常。一旦發(fā)送數(shù)據(jù)量大于64字節(jié)時就接收失敗,總是出現(xiàn)丟包現(xiàn)象,似乎只能接收64字節(jié)以內(nèi)的數(shù)據(jù)。網(wǎng)上有人干脆建議主機(jī)每次發(fā)送不要超過64字節(jié),當(dāng)然,也有人提及要作分包處理但沒具體實(shí)現(xiàn)代碼可以參考。

作為CDC類的USB設(shè)備,到底能不能正確接收來自主機(jī)64字節(jié)以上的批量數(shù)據(jù)呢?

其實(shí)是可以的,只是當(dāng)我們一次傳輸?shù)臄?shù)據(jù)大于當(dāng)前端點(diǎn)所支持的最大包長時【這里端點(diǎn)使用BULK傳輸,一般最大包長默認(rèn)設(shè)置為64字節(jié)】,USB模塊會做分包傳輸,將一批數(shù)據(jù)傳輸分成多個處理[或稱事務(wù)],即多個transaction來完成,每個Transaction里的數(shù)據(jù)包傳輸?shù)淖畲髷?shù)據(jù)量為64字節(jié)。

原理性的東西,這里不多啰嗦了,網(wǎng)上有成堆的介紹資料【當(dāng)然,或許有點(diǎn)亂】。當(dāng)我們弄清整個原理后,就可以自行組織接收處理代碼了。下面我利用HAL庫,基于STM32F429芯片演示實(shí)現(xiàn)過程,重點(diǎn)在接收處理代碼。我使用STM32F429 Discovery開發(fā)板,使用HS USB模塊并令其工作在FS MODE,這樣我們就可以方便地使用片內(nèi)USB FS PHY

我使用STM32CubeMx工具進(jìn)行配置,生成基于STM32 HAL庫的工程。使用ST提供的STM32CubeIDE進(jìn)行編譯調(diào)試。有關(guān)配置就不截圖了。

另外,我還配置了1個按鍵并開啟相應(yīng)外部中斷。每發(fā)生按鍵事件時,F429 USB設(shè)備向PC主機(jī)發(fā)送一段打招呼的字符串,并通過串口助手顯示出來。如下圖所示:

我在main.c文件里額外定義了下面幾個變量:

其中,Flag_KeyPressedFlag_DataReceived分別表示按鍵操作和收到從主機(jī)發(fā)過來的數(shù)據(jù)的情況。Rx_buffer【】數(shù)組用來存放接收來自主機(jī)的全部數(shù)據(jù),這里的定義長度為512字節(jié)【你具體使用時按需設(shè)置】。下圖是Main.c里的主循環(huán)代碼截圖:

主循環(huán)里檢查按鍵標(biāo)志和收到數(shù)據(jù)的標(biāo)志,如有按鍵發(fā)生,則向主機(jī)發(fā)送前面提到的打招呼的字符串;如有收到來自主機(jī)的數(shù)據(jù),則向主機(jī)回送過去。

今天的重點(diǎn)是討論USB設(shè)備如何從主機(jī)接收64字節(jié)以上的數(shù)據(jù)。基于現(xiàn)有HAL庫,對于USB設(shè)備的接收,我們只需關(guān)注一個USB中斷接收回調(diào)函數(shù),那就是CDC_Receive_HS()函數(shù)。該函數(shù)在usbd_cdc_if.c文件里。我具體編寫的函數(shù)代碼如下面兩幅截圖所示。

代碼很簡單。 我在庫代碼的基礎(chǔ)上增加了橙色方框內(nèi)的代碼。基本功能就是,先讀取當(dāng)前收到的數(shù)據(jù)長度【SinglePackLength】,分整包和非整包兩種情況鑒別后再處理。若是接收的整包數(shù)據(jù),繼續(xù)等待接收下一包;若是非整包,視為此次傳輸結(jié)束,并設(shè)置收到標(biāo)志Flag_DataReceived為非0值,然后在主循環(huán)里將收到的數(shù)據(jù)回送給主機(jī)。

其中,Max_Pack_Size是當(dāng)前CDCBULK傳輸端點(diǎn)的最大傳輸包長,這里為64字節(jié)。

Num_Rx_Data表示接收到數(shù)據(jù)個數(shù),Num_Out_Pack表示接收到的數(shù)據(jù)個數(shù),Num_PacketNum_Out_Pack內(nèi)容一樣,不過,Num_Packet等于0還表示準(zhǔn)備開始新一輪傳輸?shù)慕邮铡_@里多定義Num_Out_Pack,一個重要目的是便于調(diào)試時查看結(jié)果。

基于上面的接收處理代碼,我們來驗(yàn)證結(jié)果:

借助PC端的串口助手向STM32F429 USB設(shè)備發(fā)送了5個字符,我們通過STM32CubeIDE調(diào)試環(huán)境可以清晰地從上圖看到設(shè)備收到的數(shù)據(jù)個數(shù)為5,數(shù)據(jù)包個數(shù)為1。顯然沒問題。那個Rx_buffer數(shù)組是我用來存放接收數(shù)據(jù)的,若在調(diào)試窗口打開,數(shù)據(jù)較多列表顯示會很長,這里就沒打開了。事實(shí)上接收的數(shù)據(jù)內(nèi)容也是沒問題的。

下圖是借助PC端的串口助手向STM32F429 USB設(shè)備發(fā)送了305個字符的接收情況:

顯然,對于305個字符,PC主機(jī)端要分成5包才能發(fā)送完畢,即4整包【每包64字節(jié)】再加1個非完整包。所以USB設(shè)備接收結(jié)果也正好是5包,即上圖中Num_Out_pack的數(shù)據(jù),接收到的數(shù)據(jù)量為305,即上圖中Num_Rx_Data的數(shù)據(jù)。同樣,結(jié)果OK。

下圖是PC端剛好發(fā)送一個完整包64字節(jié)數(shù)據(jù)的USB設(shè)備接收情況,也一切正常。

也就是說,使用我上面編寫的接收處理代碼,對主機(jī)發(fā)送的數(shù)據(jù)的個數(shù)不再局限于64字節(jié)以內(nèi)了。當(dāng)然,具體應(yīng)用時我們還可以根據(jù)主機(jī)端單次傳輸數(shù)據(jù)的大小情況及提取數(shù)據(jù)的方式適當(dāng)調(diào)整這里的Rx_buffer[]數(shù)組大小。【注:上面測試時我臨時關(guān)閉了設(shè)備端的數(shù)據(jù)回送功能,是為了避免截圖里的數(shù)據(jù)混亂,讓人分不清原數(shù)據(jù)和回顯數(shù)據(jù)】

有人可能在上面的接收代碼里看到了一個變量Wait_Rx_Dly。剛開始,代碼里是沒有這個變量的。后來我在測試主機(jī)發(fā)送64字節(jié)整包數(shù)據(jù)時,發(fā)現(xiàn)了一個小問題【最終到底算不算問題,或許要視具體應(yīng)用場景而定,我這里稍作了點(diǎn)處理】。

問題是這樣的:

主機(jī)每發(fā)送164字節(jié)數(shù)據(jù)時,設(shè)備端接收沒有問題,但只要主機(jī)端每次發(fā)送64字節(jié)完整數(shù)據(jù)包過來,不論相隔時間多久,設(shè)備端依然接收,且總在前次結(jié)果上累加,除非主機(jī)端發(fā)一個非64字節(jié)數(shù)據(jù)包過來,設(shè)備接收就總是視為同一次傳輸。比方像下面截圖所示:

上圖就是PC主機(jī)端借助串口助手分四次且每次發(fā)送64字節(jié)數(shù)據(jù)時USB設(shè)備的接收情況。從圖上不難看出,4次數(shù)據(jù)都匯集在一起了,關(guān)鍵還沒完,還在等待后續(xù)數(shù)據(jù)過來。我是希望一次傳輸做一次處理,于是我讓設(shè)備每收到一個完整數(shù)據(jù)包,就重新給定一個延時,比方3~5ms,用變量Wait_Rx_Dly來記錄延時值,在某毫秒定時中斷里對該變量做減1操作。若延時到了還沒有收到數(shù)據(jù)或延時過程中收到非完整包則視為本次傳輸結(jié)束,然后去處理剛才收到的數(shù)據(jù)。

我順便使用了HAL庫里自帶的systick中斷函數(shù)來做這個延時管理。當(dāng)接收處理代碼加上這個延時管理后,就不會出現(xiàn)不同傳輸批次的數(shù)據(jù)在一塊了。問題得以解決。

另外,我上面分享的接收處理代碼也有很好的通用性,并不局限于Bulk傳輸。我們知道,不同傳輸類型的端點(diǎn)的最大包長往往并不一樣,如果使用上面的參考代碼,我們只需調(diào)整那個最大包長參數(shù)【Max_Pack_Size】,并適當(dāng)調(diào)整Rx_buffer[]數(shù)組的大小就可以使用了。數(shù)據(jù)個數(shù)、傳輸包個數(shù)這些變量都可以保留使用。

那段接收處理代碼很簡單,看懂了都可以自行組織編寫。順便說下,我使用的STM32F4系列的Cube庫版本為STM32F4xx HAL?V1.8.1。好,今天的話題就分享到這里,希望幫到有需要的人。祝君好運(yùn)!

往期話題閱讀鏈接【點(diǎn)擊即可閱讀】:

1、話說STM32外設(shè)復(fù)位

2、CubeMx初始配置順序與DMA傳輸異常

3、遠(yuǎn)程修改STM32 TIMER占空比的方案續(xù)1

4、兩份基于STM32 FDCAN開發(fā)的資料

5、定時器輸出指定個數(shù)脈沖的幾種方式

總結(jié)

以上是生活随笔為你收集整理的如何让CDC类USB设备批量接收64字节以上数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。