
1. 硬件与软件准备 硬件 : STM32F103C8T6(或其他F103系列,需支持USB) USB接口(PA11/DM, PA12/DP) 串口(可选,用于调试) 软件 : STM32CubeMX Keil MDK/STM32CubeIDE USB HID协议库(或自定义协议) 2. CubeMX配置 步骤1:创建工程 打开CubeMX,选择 STM32F103C8T6 。 配置时钟: HSE(8MHz外部晶振)→ PLL → SYSCLK 72MHz。 USB时钟需48MHz(通过PLL分频实现,72MHz / 1.5 = 48MHz)。 步骤2:启用USB 在 Connectivity 中启用 USB Device 。 选择 Human Interface Device (HID) : Middleware → USB_DEVICE → HID 。 步骤3:配置GPIO和时钟 确保PA11(DM)和PA12(DP)已自动配置为USB。 检查时钟树: PLLCLK = 72MHz(HSE 8MHz × 9)。 USBCLK = 48MHz(72MHz / 1.5)。 步骤4:生成代码 选择IDE(如Keil),生成代码。 3. 代码实现 3.1 修改HID描述符 在 usbd_hid.c 中修改报告描述符(64字节输入/输出): c 复制 __ALIGN_BEGIN static uint8_t HID_ReportDesc[] __ALIGN_END = { 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined) 0x09, 0x01, // Usage (Vendor Usage 1) 0xA1, 0x01, // Collection (Application) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8 bits) 0x95, 0x40, // Report Count (64 bytes) 0x09, 0x01, // Usage (Vendor Usage 1) 0x81, 0x02, // Input (Data, Var, Abs) 0x95, 0x40, // Report Count (64 bytes) 0x09, 0x01, // Usage (Vendor Usage 1) 0x91, 0x02, // Output (Data, Var, Abs) 0xC0 // End Collection }; 3.2 实现OTA协议 接收固件数据 (在 usbd_hid.c 中): c 复制 void USBD_HID_SendReport(uint8_t *report, uint16_t len) { if (USBD_HID_HandleTypeDef *hid = hUsbDeviceFS.pClassData) { USBD_LL_Transmit(&hUsbDeviceFS, HID_EPIN_ADDR, report, len); } } void USBD_HID_Receive(uint8_t *data, uint32_t length) { if (data[0] == OTA_HEADER) { // 检查固件头 write_to_flash(APP_ADDRESS, &data[1], length - 1); } } Flash操作 (添加 stm32f1xx_hal_flash.c): c 复制 void write_to_flash(uint32_t addr, uint8_t *data, uint32_t len) { HAL_FLASH_Unlock(); FLASH_EraseInitTypeDef erase = { .TypeErase = FLASH_TYPEERASE_PAGES, .PageAddress = APP_ADDRESS, .NbPages = (len + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE }; uint32_t page_error; HAL_FLASHEx_Erase(&erase, &page_error); for (uint32_t i = 0; i < len; i += 2) { uint16_t val = *(uint16_t*)(data + i); HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr + i, val); } HAL_FLASH_Lock(); } 跳转函数 (在 main.c 中): c 复制 void jump_to_app(void) { void (*app_reset_handler)(void) = (void (*)(void))(*((uint32_t*)(APP_ADDRESS + 4))); __disable_irq(); HAL_RCC_DeInit(); HAL_DeInit(); __set_MSP(*(__IO uint32_t*)APP_ADDRESS); app_reset_handler(); } 3.3 主循环逻辑 c 复制 while (1) { if (ota_complete) { jump_to_app(); } HAL_Delay(100); } 4. 上位机工具(Python示例) python 复制 import hid device = hid.device() device.open(0x0483, 0x5750) # STM32默认VID/PID # 发送固件 with open("firmware.bin", "rb") as f: data = f.read() chunk_size = 64 for i in range(0, len(data), chunk_size): chunk = data[i:i+chunk_size] device.write([0x00] + list(chunk)) # HID报告ID为0x00 5. 测试步骤 编译烧录 :将Bootloader代码烧录到STM32F103。 发送固件 : 运行Python脚本发送 .bin 文件。 MCU接收后写入Flash(地址 0x08004000,避开Bootloader)。 跳转验证 :重启后自动运行新固件。 6. 常见问题 USB枚举失败 : 检查PA11/PA12引脚连接。 确认时钟配置(USBCLK=48MHz)。 Flash写入错误 : 确保地址对齐(半字写入,2字节)。 关闭写保护(HAL_FLASH_Unlock())。 兼容性 : STM32F103的USB仅支持全速模式(12Mbps)。 7. 优化建议 校验机制 :添加CRC校验固件完整性。 双Bank升级 :STM32F103无双Bank,可设计备份分区。 调试输出 :通过串口打印日志(如HAL_UART_Transmit)。
所在话题
参与活动
-
滴滴押注社区团购,明确“投入不设上限,要做市场第一”
线下 2020-10-16 -
滴滴押注社区团购,明确“投入不设上限,要做市场第一”
网络 2020-10-16 -
滴滴押注社区团购,明确“投入不设上限,要做市场第一”
网络 2020-10-16 -
滴滴押注社区团购,明确“投入不设上限,要做市场第一”
网络 2020-10-16 -
滴滴押注社区团购,明确“投入不设上限,要做市场第一”
线下 2020-10-16 -
滴滴押注社区团购,明确“投入不设上限,要做市场第一”
线下 2020-10-16