一、USB簡介
USB(Universal Serial BUS)通用串行總線,是一個外部總線標(biāo)準(zhǔn),用于規(guī)范電腦與外部設(shè)備的連接和通訊。是應(yīng)用在 PC 領(lǐng)域的接口技術(shù)。USB 接口支持設(shè)備的即插即用和熱插拔功能。USB 是在 1994 年底由英特爾、康柏、IBM、Microsoft 等多家公司聯(lián)合提出的。
USB 發(fā)展到現(xiàn)在已經(jīng)有 USB1.0/1.1/2.0/3.0 等多個版本。目前用的最多的就是 USB1.1 和 USB2.0,USB3.0 目前已經(jīng)開始普及。
STM32F103 自帶的 USB 符合 USB2.0 規(guī)范,不過 STM32F103 的 USB 都只能用來做設(shè)備,而不能用作主機(jī)。
標(biāo)準(zhǔn) USB 共四根線組成,除 VCC/GND 外,另外為 D+,D-; 這兩根數(shù)據(jù)線采用的是差分電壓的方式進(jìn)行數(shù)據(jù)傳輸?shù)?。?USB 主機(jī)上,D-和 D+都是接了 15K 的電阻到低的,所以在沒有設(shè)備接入的時候,D+、D-均是低電平。而在 USB 設(shè)備中,如果是高速設(shè)備,則會在 D+上接一個 1.5K 的電阻到 VCC,而如果是低速設(shè)備,則會在 D-上接一個 1.5K 的電阻到 VCC。這樣當(dāng)設(shè)備接入主機(jī)的時候,主機(jī)就可以判斷是否有設(shè)備接入,并能判斷設(shè)備是高速設(shè)備還是低速設(shè)備。
STM32F103 的 MCU 自帶 USB 從控制器
,符合 USB 規(guī)范的通信連接;PC 主機(jī)和微控制器之間的數(shù)據(jù)傳輸是通過共享一專用的數(shù)據(jù)緩沖區(qū)來完成的,該數(shù)據(jù)緩沖區(qū)能被 USB 外設(shè)直接訪問。這塊專用數(shù)據(jù)緩沖區(qū)的大小由所使用的端點數(shù)目和每個端點最大的數(shù)據(jù)分組大小所決定,每個端點最大可使用 512 字節(jié)緩沖區(qū)(專用的 512 字節(jié),和 CAN 共用),最多可用于 16 個單向或 8 個雙向端點。USB 模塊同 PC 主機(jī)通信,根據(jù) USB 規(guī)范實現(xiàn)令牌分組的檢測,數(shù)據(jù)發(fā)送/接收的處理,和握手分組的處理。整個傳輸?shù)母袷接捎布瓿?,其中包?CRC 的生成和校驗。
1.1 USB HID簡介
USB HID類是USB設(shè)備的一個標(biāo)準(zhǔn)設(shè)備類,包括的設(shè)備非常多。HID類設(shè)備定義它屬于人機(jī)交互操作的設(shè)備,用于控制計算機(jī)操作的一些方面,如USB鼠標(biāo)、USB鍵盤、USB游戲操縱桿等。但HID設(shè)備類不一定要有人機(jī)接口,只要符合HID類別規(guī)范的設(shè)備都是HID設(shè)備。
USB HID設(shè)備的一個好處就是操作系統(tǒng)自帶了HID類的驅(qū)動程序,而用戶無需去開發(fā)驅(qū)動程序,只要使用API系統(tǒng)調(diào)用即可完成通信。
官方資料:http://www.usb.org/developers/hidpage
其中包含最主要的兩個說明:
- 《Device Class Definition for human interface device (HID)》【描述了 HID 的基本組成和格式】
- 《Universal Serial Bus HID Usage Tables》【對上面文檔的補充,將各種不同的 HID 設(shè)備的基本組成列舉出來】
二、新建工程
1. 打開 STM32CubeMX 軟件,點擊“新建工程”
2. 選擇 MCU 和封裝
3. 配置時鐘
RCC 設(shè)置,選擇 HSE(外部高速時鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)
選擇 Clock Configuration,配置系統(tǒng)時鐘 SYSCLK 為 72MHz
修改 HCLK 的值為 72 后,輸入回車,軟件會自動修改所有配置
4. 配置調(diào)試模式
非常重要的一步,否則會造成第一次燒錄程序后續(xù)無法識別調(diào)試器
SYS 設(shè)置,選擇 Debug 為 Serial Wire
三、USB
3.1 參數(shù)配置
在 Connectivity
中選擇 USB
設(shè)置,并勾選 Device(FS)
激活 USB 設(shè)備。
在 Parameter Settings
進(jìn)行具體參數(shù)配置。
-
Speed:
Full Speed 12MBit/s
(固定為全速) -
Low Power: 默認(rèn)
Disabled
(在任何不需要使用usb模塊的時候,通過寫控制寄存器總可以使usb模塊置于低功耗模式(low power mode ,suspend模式)。在這種模式下,不產(chǎn)生任何靜態(tài)電流消耗,同時usb時鐘也會減慢或停止。通過對usb線上數(shù)據(jù)傳輸?shù)臋z測,可以在低功耗模式下喚醒usb模塊。也可以將一特定的中斷輸入源直接連接到喚醒引腳上,以使系統(tǒng)能立即恢復(fù)正常的時鐘系統(tǒng),并支持直接啟動或停止時鐘系統(tǒng)。)
3.2 引腳配置
USB 的 DP 引腳必須上拉 1.5K 歐的電阻
,電腦才能檢測到 USB,否則檢測不到。
查看野火指南者開發(fā)板原理圖可知,需要將 PD6
配置為低電平
使能 USB。
在右邊圖中找到 PD6 引腳,選擇 GPIO_Output
。
在GPIO output level
中選擇 Low
輸出低電平。
3.3 配置時鐘
選擇 Clock Configuration
,USB 時鐘配置為 48MHz
,且來源最好是外部晶振分頻得到。
3.4 USB Device
USB有主機(jī)(Host)和設(shè)備(Device)之分。一般電腦的USB接口為主機(jī)接口,而鍵盤、鼠標(biāo)、U盤等則為設(shè)備。
部分型號的STM32芯片有1~2個USB接口。像STM32F103系列的有一個USB Device接口,STM32F407系列的有2個USB接口,既可以作為HOST,又可以作為Device,還可以作為OTG接口。
在 Middleware
中選擇 USB_DEVICE
設(shè)置,在 Class For FS IP
設(shè)備類別選擇 Custom Human Interface Device Class(HID)
自定義人機(jī)接口設(shè)備。
參數(shù)配置保持默認(rèn)。
-
CUSTOM_HID_FS_BINTERVAL(主機(jī)讀取設(shè)備數(shù)據(jù)時間間隔):
0x5
(STM32將數(shù)據(jù)發(fā)送到一個緩存區(qū),而不是直接發(fā)送到上位機(jī),而上位機(jī)每隔一端時間會來訪問緩沖區(qū)讀取數(shù)據(jù)。讀取時間間隔過快會導(dǎo)致多次數(shù)據(jù)發(fā)送,過慢會導(dǎo)致數(shù)據(jù)丟失) -
USBD_CUSTOM_HID_REPORT (Total length for Report descriptor(IN ENDPOINT))(報告描述符大?。?/strong>
2
(默認(rèn)為2,可根據(jù)自定義設(shè)備描述符的具體大小修改) -
USBD_CUSTOMHID_OUTREPORT_BUF_SIZE (Maximum report buffer size)(發(fā)送與接收數(shù)據(jù)大?。?/strong>
2
(默認(rèn)為2,HID一次最多可以發(fā)送64個字節(jié))
設(shè)備描述符保持默認(rèn)。
四、生成代碼
輸入項目名和項目路徑
選擇應(yīng)用的 IDE 開發(fā)環(huán)境 MDK-ARM V5
每個外設(shè)生成獨立的 ’.c/.h’
文件
不勾:所有初始化代碼都生成在 main.c
勾選:初始化代碼生成在對應(yīng)的外設(shè)文件。 如 GPIO 初始化代碼生成在 gpio.c 中。
點擊 GENERATE CODE 生成代碼
五、修改報告描述符
默認(rèn)報告描述表為空的,此時燒錄運行默認(rèn)代碼程序,電腦識別驅(qū)動程序錯誤,需要修改自定義設(shè)備的報告描述符。
打開工程文件夾Middlewares/USB_DEVICE/App
下usbd_custom_hid_if.c
文件
找到CUSTOM_HID_ReportDesc_FS
數(shù)組定義處。
添加如下代碼:
/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x06,0xFF,0x00, // USAGE_PAGE (Vendor Page: 0xFF00) 表示一個報文標(biāo)簽之類的用途類頁
0x09,0x01, // USAGE (Vendor Usage 1) 表示一個報告ID標(biāo)志
0xA1,0x01, // COLLECTION (Application) 表示應(yīng)用集合,要以下面最后的0xc0結(jié)束它
0x15,0x00, // LOGICAL_MINIMUM (0) 表示每個傳輸數(shù)據(jù)限定為0
0x26,0xFF,0x00, // LOGICAL_MAXIMUM (255) 表示每個傳輸數(shù)據(jù)的最大值限定為255
0x75,0x08, // REPORT_SIZE (8) 傳輸字段的寬度為8bit,表示每個傳輸?shù)臄?shù)據(jù)范圍為0~ffff ffff
0x95,0x40, // REPORT_COUNT (64)每次發(fā)送的數(shù)據(jù)長度,這里是64位
0x09,0x02, // USAGE (Vendor Usage 2) 表示一個報告ID標(biāo)志
0x81,0x02, // INPUT (Data,Var,Abs) 表示USB要輸入數(shù)據(jù)到PC的功能
0x09,0x03, // USAGE (Vendor Usage 3) 表示一個報告ID標(biāo)志
0x91,0x02, // OUTPUT (Data,Var,Abs) 表示USB設(shè)備要接收PC的數(shù)據(jù)的功能
0x0A,0x00,0xFF, // UsageS(0xFF00)
0x0B1,0x02, // feature (data, variable, absolute)
/* USER CODE END 0 */
0xC0 // END_COLLECTION 結(jié)束標(biāo)志
};
上面描述表分別定義了Input、Ouput、Feature三個報告,Input用于MCU上傳數(shù)據(jù),Output下傳數(shù)據(jù),F(xiàn)eature可用于上下傳數(shù)據(jù)。所有報告大小定義為64byte,每次最大上下傳數(shù)據(jù)量也就為64byte,另外數(shù)組USBD_CUSTOM_HID_REPORT_DESC_SIZE也要對應(yīng)修改為30。
也可借助 HID Descriptor Tool (DT) HID描述符工具根據(jù)自己需求生成,想了解更多的可以百度
《圈圈教你玩USB》
:
官網(wǎng)下載:https://usb.org/sites/default/files/documents/dt2_4.zip
百度網(wǎng)盤:https://pan.baidu.com/s/1ayjdQtc7e9NWwYJqdp0pXA?pwd=4ghb 提取碼:4ghb
- 第一部分為報文頭
- 第二部分為USB告訴PC機(jī)問我要做什么,這里主要告訴PC機(jī)我要做一個接收與發(fā)送的設(shè)備
- **INPUT:**是描述這個USB設(shè)備作為輸入的時候的數(shù)據(jù)格式
- **OUTPUT:**是描述該USB設(shè)備輸出的數(shù)據(jù)格式
- **LOGICAL_MINIMUM:**是指每個字節(jié)數(shù)據(jù)的最小值
- **LOGICAL_MAXIMUM:**是指每個字節(jié)數(shù)據(jù)的最大值
- **REPORT_COUNT:**是指定每次傳輸數(shù)據(jù)最多多少個字節(jié)
- **REPORT_SIZE:**是指定每次傳輸數(shù)據(jù)每個字節(jié)的位數(shù)
- 第三部分為結(jié)束標(biāo)志
六、修改端點大小
打開工程文件夾Middlewares/USB_Device_Library
下usbd_customhid.h
文件
要能最大上下傳 64byte(0x40
) 數(shù)據(jù),還需修改對應(yīng)上下傳端點大小為 64
。
#define CUSTOM_HID_EPIN_ADDR 0x81U
#define CUSTOM_HID_EPIN_SIZE 0x40 //0x02U Modify
#define CUSTOM_HID_EPOUT_ADDR 0x02U //0x01U Modify
#define CUSTOM_HID_EPOUT_SIZE 0x40 //0x02U Modify
ADDR中最高位代表端點的方向,1對應(yīng)IN,0對應(yīng)OUT,剩下7位為端點號,0x81代表端點1為IN Endpoint 1(EP1),這里修改為OUT的端點為Endpoint 2(EP2),兩個端點的SIZE也由2改為64。
七、修改發(fā)送緩沖區(qū)大小和報告描述符大小
打開工程文件夾Application/User/USB_DEVICE/Target
下usbd_conf.h
文件
#define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 64
/*---------- -----------*/
#define USBD_CUSTOM_HID_REPORT_DESC_SIZE 30
發(fā)送緩沖區(qū)大小USBD_CUSTOMHID_OUTREPORT_BUF_SIZE
改為最大的64byte
,另外報告描述符大小USBD_CUSTOM_HID_REPORT_DESC_SIZE
改為上面CUSTOM_HID_ReportDesc_FS
數(shù)組的大小30
。
八、添加串口打印
串口打印功能查看 STM32CubeMX學(xué)習(xí)筆記(6)——USART串口使用
九、增加上下傳數(shù)據(jù)
9.1 EP1上傳數(shù)據(jù)
添加頭文件和USB設(shè)備句柄。
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "usbd_customhid.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern USBD_HandleTypeDef hUsbDeviceFS;
/* USER CODE END PV */
添加上傳數(shù)據(jù)功能,USB 庫里已經(jīng)有寫好上傳函數(shù)USBD_CUSTOM_HID_SendReport()
,會通過Endpoint 1上傳數(shù)據(jù),調(diào)用就可以上傳數(shù)據(jù),在主循環(huán)中添加上傳數(shù)據(jù)功能。
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t bEP1_SendBuf[64] = { 0 };
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("\r\n****** USB-HID Custom Example ******\r\n\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, bEP1_SendBuf, 64) == USBD_OK)
{
bEP1_SendBuf[0]++;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
9.2 EP2下傳數(shù)據(jù)
打開工程文件夾Application/User/USB_DEVICE/App
下usbd_custom_hid_if.c
文件,找到CUSTOM_HID_OutEvent_FS()
函數(shù),添加以下代碼,實現(xiàn)對接收數(shù)據(jù)的串口打印。
/**
* @brief Manage the CUSTOM HID class events
* @param event_idx: Event index
* @param state: Event state
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
char log[250];
uint8_t i;
uint8_t len = USBD_GetRxCount(&hUsbDeviceFS, CUSTOM_HID_EPOUT_ADDR); // 第一參數(shù)是USB句柄,第二個參數(shù)的是接收的末端地址;要獲取發(fā)送的數(shù)據(jù)長度的話就把第二個參數(shù)改為發(fā)送末端地址即可
USBD_CUSTOM_HID_HandleTypeDef *hhid; // 定義一個指向USBD_CUSTOM_HID_HandleTypeDef結(jié)構(gòu)體的指針
hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData; // 得到USB接收數(shù)據(jù)的儲存地址
for(i = 0; i < len; i++)
{
sprintf(log + (i*2), "%02x", hhid->Report_buf[i]);
}
printf("%s\n", log);
return (USBD_OK);
/* USER CODE END 6 */
}
9.3 Feature Report上下傳數(shù)據(jù)
前面EP1 In和EP2 Out為中斷端點上下傳,因報告描述符中有定義Feature報告,現(xiàn)在可通過控制端點EP0來進(jìn)行Get/Set Feature Report數(shù)據(jù)傳輸。
Cube Library中沒有提供相應(yīng)的接口,這部分的代碼實現(xiàn),必須去修改原始的類命令處理。
打開工程文件夾Middlewares/USB_Device_Library
下usbd_customhid.c
文件,找到USBD_CUSTOM_HID_Setup()
函數(shù),添加以下代碼,實現(xiàn)對類命令SET_REPORT和GET_REPORT進(jìn)行處理。
case CUSTOM_HID_REQ_SET_REPORT:
//類命令的wValue高字節(jié),1-Input Report; 2-Output Report; 3-Feature Report
if(((req->wValue>>8) & 0xFF) == 0x03) //add Set Feature report
{
printf("Set Feature report\n");
hhid->IsReportAvailable = 1U;
USBD_CtlPrepareRx(pdev, hhid->Report_buf, req->wLength);
char log[250];
uint8_t i;
for(i = 0; i < req->wLength; i++)
{
sprintf(log + (i*2), "%02x", hhid->Report_buf[i]);
}
printf("%s\n", log);
}
else if(((req->wValue>>8) & 0xFF) == 0x02) //add Set out report
{
printf("Set out report\n");
// hhid->IsReportAvailable = 1U;
// USBD_CtlPrepareRx(pdev, hhid->Report_buf, req->wLength);
}
break;
//add
case CUSTOM_HID_REQ_GET_REPORT:
if(((req->wValue>>8) & 0xFF) == 0x03) //add Get Feature
{
printf("Get Feature\n");
hhid->Report_buf[0] = 0xAA;
USBD_CtlSendData(pdev, hhid->Report_buf, req->wLength);
char log[250];
uint8_t i;
for(i = 0; i < req->wLength; i++)
{
sprintf(log + (i*2), "%02x", hhid->Report_buf[i]);
}
printf("%s\n", log);
}
break;
十、查看效果
編譯工程,下載到板子上,插上USB線連接到電腦上,識別出為未指定設(shè)備。
注意: 如果設(shè)備帶有感嘆號,則參考下面
十二、注意事項
10.1 下載測試工具
-
Bus Hound
百度網(wǎng)盤:https://pan.baidu.com/s/1Q8x3gjN9tl2pW1qHcG9I-A?pwd=0yjp 提取碼:0yjp -
PortHelper
百度網(wǎng)盤:https://pan.baidu.com/s/157gd_8zBh9cBPf9qXVDnow?pwd=5cw5 提取碼:5cw5
10.2 測試上傳數(shù)據(jù)
-
Bus Hound
打開Bus Hound,在Devices頁面找到我們的HID設(shè)備,注意VID和PID與我們設(shè)置的一致,勾選該設(shè)備:
然后切換到Capture頁面,點擊Run,檢測收發(fā)數(shù)據(jù),可以看到開發(fā)板向計算機(jī)發(fā)送的數(shù)據(jù),長度為64字節(jié): -
PortHelper
查找USB,然后根據(jù)USB設(shè)備的名稱找到STM32的USB接口:
然后點擊打開USB,勾選Hex顯示,檢測收發(fā)數(shù)據(jù),可以看到開發(fā)板向計算機(jī)發(fā)送的數(shù)據(jù),長度為64字節(jié):
10.3 測試下傳數(shù)據(jù)
-
Bus Hound
在Devices頁面,選中我們自定義的HID設(shè)備后,點擊右下方的Send Commands,打開發(fā)送窗口:
選中USB選項卡,然后選中Interrupt Out,在Data Length處填入64
,即需要發(fā)送64個字節(jié);修改下方的數(shù)據(jù)為想要發(fā)送的數(shù)據(jù),這里為便于觀察,設(shè)置成全0x11
,然后點擊Run發(fā)送。
打開串口工具查看:
-
PortHelper
點擊打開USB,勾選Hex發(fā)送,修改下方的數(shù)據(jù)為想要發(fā)送的數(shù)據(jù):
打開串口工具查看:
10.4 測試Feature Report上下傳數(shù)據(jù)
-
Bus Hound
- 接收Set Feature Report數(shù)據(jù)
- 接收Set Feature Report數(shù)據(jù)
查看串口打?。?/p>
- 接收Get Feature Report數(shù)據(jù)
查看串口打?。?/p>
十一、工程代碼
鏈接:https://pan.baidu.com/s/16yaJxfE5GxKhF-wkOwiFQg?pwd=02fu
提取碼:02fu
十二、注意事項
用戶代碼要加在 USER CODE BEGIN N
和 USER CODE END N
之間,否則下次使用 STM32CubeMX 重新生成代碼后,會被刪除。
如果USB端口出現(xiàn)感嘆號設(shè)備無法啟動的問題,可適當(dāng)將堆改大,如0x400
? 由 Leung 寫于 2022 年 11 月 4 日文章來源:http://www.zghlxwxcb.cn/news/detail-627479.html
? 參考:STM32CubeMX生成STM32F072 USB 自定義HID Device
【STM32+cubemx】0018 HAL庫開發(fā):自定義usb HID設(shè)備實現(xiàn)
YIE002開發(fā)探索09-USB(HID雙向通信)
STM32 使用Cubemx 建一個USB(HID)設(shè)備下位機(jī),實現(xiàn)數(shù)據(jù)收發(fā)
STM32 基礎(chǔ)系列教程 27 - USB_HID文章來源地址http://www.zghlxwxcb.cn/news/detail-627479.html
到了這里,關(guān)于STM32CubeMX學(xué)習(xí)筆記(46)——USB接口使用(HID自定義設(shè)備)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!