You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

STM32F103C8通过USB向PC发送Hat Switch数据失败求助

排查自定义HID游戏手柄Hat Switch无法识别的问题

我来帮你解决这个方向帽(Hat Switch)无法被PC识别的问题——这在自定义HID设备开发里是个典型的「报告结构匹配」坑,咱们一步步拆解问题所在,再给出可行的修复方案。

问题核心分析

从你提供的HID描述符和代码来看,按钮数据能正常工作说明基础的HID通信没问题,但Hat Switch失效主要是报告结构体的格式和HID描述符定义不匹配,具体有两个关键问题:

1. 位字段顺序与编译器依赖

你定义的gamepad_report_t里用了位字段来存储Hat Switch的4个bit,但C语言的位字段存储顺序是由编译器决定的(比如有些从高位到低位,有些反之)。这就导致你设置的hs0-hs3可能和HID描述符要求的bit顺序完全相反,PC收到数据后无法解析成正确的Hat方向。

2. 报告长度与常量字段缺失

根据你的HID描述符,整个输入报告的总长度应该是3字节

  • 前2字节:14个按钮(14bit) + 2bit常量(凑满16bit)
  • 第3字节:Hat Switch的4bit数据 + 4bit常量(凑满8bit)

但你的原结构体没有包含那4个必需的常量bit,而且编译器可能会自动填充结构体到4字节(因为内存对齐),导致你发送了多余的字节,PC无法识别这个不符合描述符的报告。

修复方案

推荐两种可靠的实现方式,避免编译器依赖,严格匹配HID描述符:

方案一:用字节数组定义报告(最稳妥)

直接用字节数组来构造报告,完全掌控每个字节的bit,避免位字段的不确定性:

#include <string.h>

uint8_t gamepad_report[3] = {0}; // 严格对应3字节报告长度

int main() {
    while (1) {
        // 每次发送前重置报告,避免残留数据
        memset(gamepad_report, 0, sizeof(gamepad_report));
        
        // 设置Button5按下(对应第1字节的bit4,Button1对应bit0)
        gamepad_report[0] |= (1 << 4);
        // 设置Hat Switch为向右(对应第3字节的低4位,值1)
        // 方向对应:0=上,1=右,2=下,3=左,0xF=中立(Null状态)
        gamepad_report[2] = 0x01;
        
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
        // 发送3字节报告,严格匹配描述符长度
        USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, gamepad_report, sizeof(gamepad_report));
        HAL_Delay(500);
    }
}

方案二:用带打包属性的结构体

如果偏好结构体的可读性,可以使用编译器的打包属性强制结构体大小为3字节,并明确每个字段的位置:

// 用__attribute__((packed))禁止编译器自动填充,确保结构体大小为3字节
typedef struct {
    uint8_t btn1_btn8;    // 按钮1-8:bit0=Btn1,bit1=Btn2,...,bit7=Btn8
    uint8_t btn9_btn14;   // 按钮9-14:bit0=Btn9,...,bit5=Btn14;bit6-7固定为0
    uint8_t hat : 4;      // Hat Switch数据:0=上,1=右,2=下,3=左,0xF=中立
    uint8_t reserved : 4; // 必须设为0,对应描述符里的常量字段
} __attribute__((packed)) gamepad_report_t;

gamepad_report_t gamepad_report = {0};

int main() {
    while (1) {
        // 重置字段
        gamepad_report.btn1_btn8 = 0;
        gamepad_report.btn9_btn14 = 0;
        gamepad_report.hat = 0;
        gamepad_report.reserved = 0;
        
        // 设置Button5按下
        gamepad_report.btn1_btn8 |= (1 << 4);
        // 设置Hat Switch向右
        gamepad_report.hat = 1;
        
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
        USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, &gamepad_report, sizeof(gamepad_report));
        HAL_Delay(500);
    }
}

额外验证建议

修复后可以用PC端的HID检测工具(比如HIDView)查看设备发送的报告数据,确认:

  • 按钮按下时,对应字节的bit位正确置1
  • Hat Switch切换方向时,第3字节的低4位对应0/1/2/3,中立时为0xF
  • 报告总长度始终是3字节

内容的提问来源于stack exchange,提问作者rololo

火山引擎 最新活动