這里記錄一下如何做一個USB下位機,這里主要分3部分:1、建立工程;2、添加報文描述符;3、數據的傳輸。這里就不講USB的理論知識了,有想要了解的百度一下就可以了。
建立工程:工程建立參考:https://www.cnblogs.com/libra13179/p/7193375.html
1、首先打開USB
2、接著把USB設置為下圖HID模式
3、選擇外部時鐘
4、配置時鐘樹
5、配置USB設置
下面的USB設置就有點講究了,
USBD_CUSTOM_HID_REPORT_DESC_SIZE 這個是指報告描述符所用的字節數為34(默認為2);USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 表示輸入輸出端點一次傳輸數據大小最大為64個字節(默認為2)
【 補充:現在新版本的STM32Cumebx在這個配置里還多了一項CUSTOM_HID_FS_BINTERVAL,這個是指數據傳輸的最小時間間隔(ms)這里修改為跟下面USB傳輸部分中修改時間間隔一致 】
6、確認后,生成代碼
補充:生成代碼的時候注意把堆的大小改大一點,不然容易出現設備識別出來出現感嘆號的情況
最后生成項目
添加報文描述符:
這里只是建立了一個工程,你編譯不會有錯,不過PC還是無法識別你這個是USB設備的,因為缺少了關鍵的報文描述符,這里我就說一下報文描述符怎么寫,這個你可以直接用HID descriptor Tool軟件生成,如下圖,下圖就是一個報文的基本要素了,該描述符主要作用是告訴PC機一下USB的信息,簡單來說就是告訴PC我有什么用。
HID descriptor Tool 百度云下載鏈接:https://pan.baidu.com/s/1BbEV3pak0KgVXD8GHtzLow ;提取碼:nalw 。
這里我說一下這個報文的要素,第一部分你可以理解為報文頭;第二部分你可以理解為USB告訴PC機問我要做什么,這里主要告訴PC機我要做一個接收與發送的設備,USAGE~INPUT這里是描述這個USB設備作為輸入的時候的數據格式,下一個USAGE~OUTPUT是描述該USB設備輸出的數據格式,其中LOGICAL_MINIMUM是指每個字節數據的最小值,LOGICAL_MAXIMUM是指每個字節數據的最大值,REPORT_COUNT是指定每次傳輸數據最多多少個字節,REPORT_SIZE是指定每次傳輸數據每個字節的位數;第三部分是結束標志。
============================================================
下面我插入一個對報文描述符進行一個簡單的描述:
標簽解析舉例(Usage :0x50, 0x01):
(Usage Page標簽0x0?)0x05=0000 0101 :
0x05表示前綴,0x01為數據部分,0x05轉換成二進制,就是0000 01 01,按照HID類協議5.3 generic item format的定義,這個字節被分成3個部分:
bit0~bit1代表的是這個前綴后面跟的數據長度,這里就是后面0x01的長度,兩位可以表示最大4字節的數據,即bsize
bit2~bit3代表的是這個前綴的類型,總共可以有三種類型:0=main,1=global,2=local,3=reserved;
bit4~bit7代表前tag,一般分為input(二進制的1000 00 nn,即bit4~bit7=1000,代表一個tag,bit2~bit3=00,代表main,bit0~bit1=nn,代表這個前綴后面還有nn所代表的數據),output(二進制的 1001 00 nn),feature(1011 00 nn),collection(1010 00 nn),end collection(1100 00 nn)
即:
0000:Usage Page
01: bType,全局(bType=0:主項目;bType=1:全局項目;bType=2:區域項目)
01:bSzie,1字節(bSzie為項目所需數據字節數目,bSzie可為1、2、4,注意bSzie不可為3)
(Page ID)0x01: 表示該Page為Generalic Desktop Controls(Usage ID 0為保留。ID 1到0x1F為”top level” collection保留,這些ID雖然對于Application不是必須,但可以用于識別通用設備類型)
Usage = (usage page:usage ID):其將數據的操控與它的用途作一對一的對應,所以解讀報告后就可以知道每個數據作何種操作。所以“傳輸的數據”和“操作”只是一事件的兩種描述方式。用途是以一個32位卷標(稱作usage tag)來表示,高16位稱作usage page(用途類頁),低16位稱為usage ID(用途識別名),文件universal serial Bus HID Usage Table完整列出所有的usage pages(用途類頁)和usage ID(用途識別名),使用者必須遵照文件的規范來聲明操作的用途。用途卷標只是報告描述符諸多標簽的一個,利用這些卷標取可以清楚完整的描述符操作的用途。
這里其實說的并不清楚,因為作者有點懶就不細說了,想了解更多的可以百度《圈圈教你玩USB》,這里說的比我好。
==============================================================================
言歸正傳,我們生成了報文描述符后,保存為.h文件,我對這些報文做了一些很淺顯的解析,可能表達不夠準確,打開可以看到如下代碼所示:
char ReportDescriptor[34] =
{ //這里34就是前面建立工程第五點說的,報文描述符大小
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1) 表示一個報文標簽之類的用途類頁
0x09, 0x01, // USAGE (Vendor Usage 1) 表示一個報告ID標志
0xa1, 0x01, // COLLECTION (Application) 表示應用集合,要以下面最后的0xc0結束它
0x09, 0x01, // USAGE (Vendor Usage 1)同下同名解析
0x15, 0x00, // LOGICAL_MINIMUM (0) 同下同名解析
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 同下同名解析
0x95, 0x40, // REPORT_COUNT (64) 同下REPORT_COUNT
0x75, 0x08, // REPORT_SIZE (8) 同下REPORT_SIZE
0x81, 0x02, // INPUT (Data,Var,Abs) 表示USB要輸入數據到PC的功能
0x09, 0x01, // USAGE (Vendor Usage 1) 每個功能的一個卷標志
0x15, 0x00, // LOGICAL_MINIMUM (0) 表示每個傳輸數據限定為0
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 表示每個傳輸數據的最大值限定為255
0x95, 0x40, // REPORT_COUNT (64) 每次接收的數據長度,這里是64位
0x75, 0x08, // REPORT_SIZE (8) 傳輸字段的寬度為8bit,表示每個傳輸的數據范圍為0~ffff ffff
0x91, 0x02, // OUTPUT (Data,Var,Abs) 表示USB設備要接收PC的數據的功能
0xc0 // END_COLLECTION 結束標志
};
到這里我們就可以下一步了,打開剛才建立的工程,在 usbd_custom_hid_if.c 文件里,找到 CUSTOM_HID_ReportDesc_FS 這個函數,把剛才生成的報文文件覆蓋掉函數里面的文件,代碼如下:
/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x40, // REPORT_COUNT (64)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x95, 0x40, // REPORT_COUNT (64)
0x75, 0x08, // REPORT_SIZE (8)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
};
然后再修改將usbd_conf.h做對應修改:
#define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 64
#define USBD_CUSTOM_HID_REPORT_DESC_SIZE 34
同時修改usbd_customhid.h文件中的發送與接收長度為64
#define CUSTOM_HID_EPIN_SIZE 0x40
#define CUSTOM_HID_EPOUT_SIZE 0x40
到這里基本就算做出一個USB設備了,我們編譯下載程序看看。
========================【注意】===========================================
如果電腦顯示了這個USB設備,但是有黃色感嘆號,說明USB枚舉成功,可是驅動安裝失敗,這時我們可以libusb自帶的inf-wizard工具生成USB驅動程序,libusb官網下載鏈接為https://sourceforge.net/projects/libusb-win32/,或者可以去百度云盤下載( 鏈接:https://pan.baidu.com/s/10GUwwhPZTYONBYbOutVBzA ;提取碼:lf87 )。
下載好文件后解壓,找到下圖的inf-wizar工具打開。
打開后該工具可以掃描你電腦的USB設備,并獲取設備的PID、VID。
根據 PID/VID 找到你自己的USB設備,選擇它點擊Next。
保持默認配置,Next即可,最后你自己選擇你的USB設備驅動的安裝路徑,你可以自己在C盤建立個文件夾安裝在里面即可。
===============================================================
USB數據傳輸:參考http://www.stm32cube.com/article/138
關于數據傳輸,HID設備是采用輪詢方式傳輸的,ST默認20ms速度實在不敢恭維,還得要改一下枚舉時的聲明(這里修改跟CUSTOM_HID_FS_BINTERVAL一致,舊版STM32Cumebx中沒有這項配置修改可以直接修改usbd_conf.h文件里的CUSTOM_HID_FS_BINTERVAL),修改usbd_customhid.c文件(如果是新版STM32cubemx生成的工程的話,已經可以直接在工程里修改CUSTOM_HID_FS_BINTERVAL了,該宏就是這里使用的宏,如果你是用新版STM32Cubemx,并在里面修改了CUSTOM_HID_FS_BINTERVAL,這里不做修改都行,因為新版生成的項目這里直接就是使用CUSTOM_HID_FS_BINTERVAL的宏,你修改了CUSTOM_HID_FS_BINTERVAL的宏這里就跟著修改了)。
__ALIGN_BEGIN static uint8_t USBD_CUSTOM_HID_CfgDesc[USB_CUSTOM_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
....
....
0x20, /*bInterval: Polling Interval (20 ms)*/
/* 34 */
....
....
0x20,/* bInterval: Polling Interval (20 ms) */
/* 41 */
}
這兩個地方隨心來改,最小可以改到0x01。這就快很多啦。到這里數據傳輸準備工作就做好了,下面我們先來說一下USB發送:
先定義個發送BUFF:
uint8_t send_buf[64] = {//定義一個USB的發送BUFF
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64};
再包括發送函數頭文件以及聲明一個外部定義:
#include 'usbd_customhid.h' //包括發送函數頭文件
extern USBD_HandleTypeDef hUsbDeviceFS; //外部聲明USB的句柄
現在可以在main函數里添加發送代碼了,我這里設置按一下按鍵就發送一次,同時led亮1s:
while (1)
{
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(GPIOE,k1_Pin)==0)
{
//按鍵消抖
while(HAL_GPIO_ReadPin(GPIOE,k1_Pin)==0);
//點亮指示燈
HAL_GPIO_WritePin(GPIOE,led1_Pin,GPIO_PIN_RESET);
上一篇:STM32使用HAL庫實現ADC單通道轉換
下一篇:STM32 Cubemx 輸出可調頻率與占空比的PWM
推薦閱讀最新更新時間:2025-04-10 10:47




設計資源 培訓 開發板 精華推薦
- DC1620A-P,LTC2142-12 演示板,12 位 65 Msps 雙路 ADC,DDR LVDS 輸出,5-140MHz
- DC1627A-B,旨在顯示 LTC4226CUD-2 寬工作范圍雙通道熱插拔控制器的熱插拔功能的演示電路
- NCL30085FLYGEVB:功率因數校正 3 步調光評估板
- RLC諧振電路研究
- inDART-HCS08D: In-Circuit, Real-Time Debugger/Programmer for NXP S08 Family
- LT1304CS8-5 演示板、DC/DC 轉換器、2-3 節電池至 5V @ 200mA
- 5路隔離電源
- 基于ACEPACK?2電源模塊的工業驅動系統套件
- LT6658BHMSE-2.5 遞歸參考應用的典型應用電路(VOUT1 為 VIN 和 VIN2 供電)
- 使用 AD7400A 隔離式 Sigma-Delta 調制器的模數隔離器、ADuM5000 隔離式 DC 至 DC 轉換器
- UWB芯片圈大動作:三星連發兩款,國產新秀訂單超千萬顆
- 3DGS:革新自動駕駛仿真場景重建的關鍵技術
- 合見工軟助力開芯院RISC-V開發再升級,UVHS支持第三代昆明湖16核CPU突破驗證挑戰
- 仿真驅動、數據自造:巧用合成數據重構智能座艙
- 從元器件到測試系統:Pickering品英集團55年為用戶構建自動測試全生命周期降本增效生態
- 多模態自動駕駛混合渲染HRMAD:將NeRF和3DGS進行感知驗證和端到端AD測試
- 汽車芯片國產化:挑戰中崛起,巨頭引領產業鏈共進
- 汽車芯片邁向艙駕融合時代
- 2025智能座艙技術圖譜,從多模態交互到車路云一體化的演進路徑
- 從“功能堆疊”到“體驗共生”,智能座艙的架構重構與算力革命