概述
本文是使用HAL库的USB驱动
由于官方cubeMX天生的hal库做组合装备时过于繁琐
以是这里使用某大神的插件,可以集成在cubeMX里自动天生组合装备
有小bug会覆盖天生文件里自己写的内容,以是天生一次后注意生存
插件安装
下载地址 https://github.com/alambe94/I-CUBE-USBD-Composite/releases/tag/V01.00.03
下载pack文件
打开cubeMX
点击这个 之后选择下载的文件 安装
出现这个即为安装成功
天生代码
打开USB 设为装备模式,打开中断
注意设置时钟树
USB需要较为精确的时钟 建议用外部晶振
选择库文件
现在打勾的这俩必选
别的根据需要选择
根据需要选择,注意要在上步开启的库文件中选
在初始化后参加这个函数
MX_USB_DEVICE_Init();
可以去usbd_desc.c里设置VID/PID 某些名称等参数,差别装备有些许差别
虚拟串口(CDC)
概述
串口名是由PC的驱动来决定的,没法在STM32端设置
设置
打开这个
可以在这里设置虚拟的串口数目
注意一个串口要占用2个IN端点和一个OUT端点
也可以设置AL94.I-CUBE-USBD-COMPOSITE_conf.h文件中的_USBD_CDC_ACM_COUNT设置虚拟的CDC串口数目
发送
开始发送
类型名称功能uint8_tch通道uint8_t *Buf缓冲区地址uint16_tLen发送数目uint8_t输出已经发送的数目- uint8_t CDC_Transmit(uint8_t ch, uint8_t *Buf, uint16_t Len)
复制代码 发送完成
类型名称功能uint8_tcdc_ch通道uint8_t *Buf缓冲区地址uint32_tLen发送数目uint8_tepnum端点号uint8_t错误码- int8_t CDC_TransmitCplt(uint8_t cdc_ch, uint8_t *Buf, uint32_t *Len, uint8_t epnum)
复制代码 接收
类型名称功能uint8_tcdc_ch通道uint8_t *Buf缓冲区地址uint32_tLen发送数目int8_t错误码 接收到数据会自动调用这函数
- int8_t CDC_Receive(uint8_t cdc_ch, uint8_t *Buf, uint32_t *Len)
复制代码 在这个函数里调用这俩句,来接收下个数据包
- USBD_CDC_SetRxBuffer(cdc_ch, &hUsbDevice, &Buf[0]);
- USBD_CDC_ReceivePacket(cdc_ch, &hUsbDevice);
复制代码 控制函数
类型名称功能uint8_tcdc_ch通道uint8_tcmd命令类型uint8_t *pbuf命令缓冲区uint16_tlength长度int8_t错误码- int8_t CDC_Control(uint8_t cdc_ch, uint8_t cmd, uint8_t *pbuf, uint16_t length)
复制代码 在cmd为CDC_SET_LINE_CODING时收到来自主机的命令
具体内容天生的函数中有注释
人体工学装备(HID)
概述
全部使用自定义HID装备
根据差别装备设置描述符即可
HID间的复合直接复制就行
eg:鼠标+键盘 直接把鼠标的描述符和键盘的描述符写到一起即可
建立工程
设置
在 usbd_customhid.h中
名称功能CUSTOM_HID_STR_DESCHID描述CUSTOM_HID_EPIN_SIZE输入缓冲大小(一般设为64)CUSTOM_HID_EPOUT_SIZE输出缓冲大小(一般设为64)USBD_CUSTOMHID_OUTREPORT_BUF_SIZEHID缓冲区(一般设为64)CUSTOM_HID_FS_BINTERVAL包间隔时间 在usbd_custom_hid_if.c中
CUSTOM_HID_ReportDesc 设置HID描述符 USBD_CUSTOM_HID_REPORT_DESC_SIZE 同时也要设置配置符大小
APIs
发送数据
类型名称功能USBD_HandleTypeDef *pdevUSB句柄uint8_t *report缓冲区uint16_tlen数据长度uint8_t错误码- uint8_t USBD_CUSTOM_HID_SendReport(USBD_HandleTypeDef *pdev,uint8_t *report, uint16_t len);
复制代码 接收数据回调
usbd_custom_hid_if.c
类型名称功能uint8_tevent_idxuint8_tstateuint8_t错误码- int8_t CUSTOM_HID_OutEvent(uint8_t event_idx, uint8_t state)
复制代码 在内部调用以获取数据
- USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)HZ_DAP_USB_Handle.pClassData_HID_Custom;
- // hhid->Report_buf;
- USBD_CUSTOM_HID_ReceivePacket(&HZ_DAP_USB_Handle);
复制代码 鼠标
鼠标的配置描述符
- 0x05, 0x01,
- 0x09, 0x02,
- 0xa1, 0x01,
- 0x85, 0x02, // 报告ID (2)
- 0x09, 0x01,
- 0xa1, 0x00,
- 0x05, 0x09,
- 0x19, 0x01,
- 0x29, 0x03,
- 0x15, 0x00,
- 0x25, 0x01,
- 0x95, 0x03,
- 0x75, 0x01,
- 0x81, 0x02,
- 0x95, 0x01,
- 0x75, 0x05,
- 0x81, 0x03,
- 0x95, 0x03,
- 0x75, 0x08,
- 0x05, 0x01,
- 0x09, 0x30,
- 0x09, 0x31,
- 0x09, 0x38,
- 0x15, 0x81,
- 0x25, 0x7f,
- 0x81, 0x06,
- 0xc0,
- 0xc0
复制代码 需要发送的命令 寄义
位置功能Bit0陈诉IDBit1[0]左键(0未按1按下)Bit1[1]右键(0未按1按下)Bit1[2]中键(0未按1按下)Bit2x轴(正右负左 -127~127)Bit3y轴(正下负上 -127~127)Bit4滚动(正上负下 -127~127) 这个函数是自己封装的
- extern USBD_HandleTypeDef hUsbDevice;
- /**
- * @brief 控制鼠标
- * @param key_l 左键(仅bit0 0未按1按下)
- * @param key_r 右键(仅bit0 0未按1按下)
- * @param key_m 中键(仅bit0 0未按1按下)
- * @param x x轴(正右负左 -127~127)
- * @param y y轴(正下负上 -127~127)
- * @param ec 滚动(正上负下 -127~127)
- * @author HZ12138
- * @date 2025-03-28 20:17:39
- */
- void HZ_Mouse_set(uint8_t key_l, uint8_t key_r, uint8_t key_m, int8_t x, int8_t y, int8_t ec)
- {
- uint8_t buf[5];
- key_l &= 0x01;
- key_r &= 0x01;
- key_m &= 0x01;
- buf[0] = 0x02; // 报告ID 鼠标是0x02
- buf[1] = (key_m << 2) | (key_r << 1) | (key_l << 0);
- buf[2] = (uint8_t)x;
- buf[3] = (uint8_t)y;
- buf[4] = (uint8_t)ec;
- USBD_CUSTOM_HID_SendReport(&hUsbDevice, buf, 5);
- }
复制代码 键盘
描述符
0x85后面跟的是陈诉ID 0保留
- 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
- 0x09, 0x06, // USAGE (Keyboard)
- 0xa1, 0x01, // COLLECTION (Application)
- 0x85, 0x01, // 报告ID (1)
- 0x05, 0x07, // USAGE_PAGE (Keyboard)
- 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
- 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
- 0x15, 0x00, // LOGICAL_MINIMUM (0)
- 0x25, 0x01, // LOGICAL_MAXIMUM (1)
- 0x75, 0x01, // REPORT_SIZE (1)
- 0x95, 0x08, // REPORT_COUNT (8)
- 0x81, 0x02, // INPUT (Data,Var,Abs)
- 0x95, 0x01, // REPORT_COUNT (1)
- 0x75, 0x08, // REPORT_SIZE (8)
- 0x81, 0x03, // INPUT (Cnst,Var,Abs)
- 0x95, 0x05, // REPORT_COUNT (5)
- 0x75, 0x01, // REPORT_SIZE (1)
- 0x05, 0x08, // USAGE_PAGE (LEDs)
- 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
- 0x29, 0x05, // USAGE_MAXIMUM (Kana)
- 0x91, 0x02, // OUTPUT (Data,Var,Abs)
- 0x95, 0x01, // REPORT_COUNT (1)
- 0x75, 0x03, // REPORT_SIZE (3)
- 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
- 0x95, 0x06, // REPORT_COUNT (6)
- 0x75, 0x08, // REPORT_SIZE (8)
- 0x15, 0x00, // LOGICAL_MINIMUM (0)
- 0x25, 0x65, // LOGICAL_MAXIMUM (101)
- 0x05, 0x07, // USAGE_PAGE (Keyboard)
- 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
- 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
- 0x81, 0x00, // INPUT (Data,Ary,Abs)
- 0xc0 // END_COLLECTION
复制代码 数据内容
Bit2~8 发送的是按下的键号 如果不按下写0即可
位置功能Bit0陈诉IDBit1[0]左CTRL(0未按1按下)Bit1[1]左SHIFT(0未按1按下)Bit1[2]左ALT(0未按1按下)Bit1[3]左GUI(0未按1按下)Bit1[4]右CTRL(0未按1按下)Bit1[5]右SHIFT(0未按1按下)Bit1[6]右ALT(0未按1按下)Bit1[7]右GUI(0未按1按下)Bit2保留(0x00)Bit3按键1Bit4按键2Bit5按键3Bit6按键4Bit7按键5Bit8按键6 封装的发送按键函数和单个按键按下函数
- extern USBD_HandleTypeDef hUsbDevice;
- /**
- * @brief 发送按键
- * @param keys 按键
- * @param key_num 数量最大6个
- * @param ctrl_l 如名(0未按1按下)
- * @param shift_l 如名(0未按1按下)
- * @param alt_l 如名(0未按1按下)
- * @param gui_l 如名(0未按1按下)
- * @param ctrl_r 如名(0未按1按下)
- * @param shift_r 如名(0未按1按下)
- * @param alt_r 如名(0未按1按下)
- * @param gui_r 如名(0未按1按下)
- * @author HZ12138
- * @date 2025-03-28 22:52:09
- */
- void HZ_KeyBoard_set(uint8_t *keys, uint8_t key_num,
- uint8_t ctrl_l, uint8_t shift_l, uint8_t alt_l, uint8_t gui_l,
- uint8_t ctrl_r, uint8_t shift_r, uint8_t alt_r, uint8_t gui_r)
- {
- uint8_t buf[9];
- ctrl_l &= 0x01;
- shift_l &= 0x01;
- alt_l &= 0x01;
- gui_l &= 0x01;
- ctrl_r &= 0x01;
- shift_r &= 0x01;
- alt_r &= 0x01;
- gui_r &= 0x01;
- buf[0] = 0x01;
- buf[1] = (gui_r << 7) | (alt_r << 6) | (shift_r << 5) | (ctrl_r << 4) |
- (gui_l << 3) | (alt_l << 2) | (shift_l << 1) | (ctrl_l << 0);
- buf[2] = 0x00;
- for (int i = 0; i < key_num; i++)
- buf[3 + i] = keys[i];
- USBD_CUSTOM_HID_SendReport(&hUsbDevice, buf, 9);
- }
- /**
- * @brief 发送单个按键
- * @param key 按键值
- * @author HZ12138
- * @date 2025-03-28 22:52:12
- */
- void HZ_KeyBoard_one_key(uint8_t key)
- {
- uint8_t temp[6];
- temp[0] = key;
- HZ_KeyBoard_set(temp, 6, 0, 0, 0, 0, 0, 0, 0, 0);
- }
复制代码 键码对应表,使用HID码
按键名称HID码虚拟键码ESC41 [0X29]27 [0x1B]F158 [0X3a]112 [0x70]F259 [0X3b]113 [0x71]F360 [0X3c]114 [0x72]F461 [0X3d]115 [0x73]F562 [0X3e]116 [0x74]F663 [0X3f]117 [0x75]F764 [0X40]118 [0x76]F865 [0X41]119 [0x77]F966 [0X42]120 [0x78]F1067 [0X43]121 [0x79]F1168 [0X44]122 [0x7A]F1269 [0X45]123 [0x7B]Esc41 [0X29]27 [0x1B]Back (回退)42 [0X2a]8 [0x08]Tab43 [0X2b]9 [0x09]CapLck (大小写)57 [0X39]20 [0x14]Enter (回车)40 [0X28]13 [0x0D]Space (空格)44 [0X2c]32 [0x20]Scroll71 [0X47]145 [0x91]Pause(暂停)72 [0X48]19 [0x13]Insert (插入)73 [0X49]45 [0x2D]PrintScr (截屏)70 [0X46]44 [0x2C]Delete (删除)76 [0X4c]46 [0x2E]Home (首页)74 [0X4a]36 [0x24]End (末端)77 [0X4d]35 [0x23]PageUp (上一页)75 [0X4b]33 [0x21]PageDn (下一页)78 [0X4e]34 [0x22]Left (左)80 [0X50]37 [0x25]Up (上)82 [0X52]38 [0x26]Right (右)79 [0X4f]39 [0x27]Down (下)81 [0X51]40 [0x28]Num0 (小键盘)98 [0X62]96 [0x60]Num1 (小键盘)89 [0X59]97 [0x61]Num2 (小键盘)90 [0X5a]98 [0x62]Num3 (小键盘)91 [0X5b]99 [0x63]Num4 (小键盘)92 [0X5c]100 [0x64]Num5 (小键盘)93 [0X5d]101 [0x65]Num6 (小键盘)94 [0X5e]102 [0x66]Num7 (小键盘)95 [0X5f]103 [0x67]Num8 (小键盘)96 [0X60]104 [0x68]Num9 (小键盘)97 [0X61]105 [0x69]NumAdd (加号)87 [0X57]107 [0x6B]NumSub (减号)86 [0X56]109 [0x6D]NumMult (乘号)85 [0X55]106 [0x6A]NumDiv (除号)84 [0X54]111 [0x6F]NumDecim (点)99 [0X63]110 [0x6E]NumLock (数字锁定键)83 [0X53]144 [0x90]Ctrl1 [0X01]17 [0x11]LCtrl (左CTR)1 [0X01]162 [0xA2]RCtrl16 [0X10]163 [0xA3]Shift2 [0X02]16 [0x10]LShift2 [0X02]160 [0xA0]RShift32 [0X20]161 [0xA1]Alt4 [0X04]18 [0x12]LAlt4 [0X04]164 [0xA4]RAlt64 [0X40]165 [0xA5]WIN8 [0X08]91 [0x5B]LWIN8 [0X08]91 [0x5B]RWIN128 [0X80]92 [0x5C]A4 [0X04]65 [0x41]B5 [0X05]66 [0x42]C6 [0X06]67 [0x43]D7 [0X07]68 [0x44]E8 [0X08]69 [0x45]F9 [0X09]70 [0x46]G10 [0X0a]71 [0x47]H11 [0X0b]72 [0x48]I12 [0X0c]73 [0x49]J13 [0X0d]74 [0x4A]K14 [0X0e]75 [0x4B]L15 [0X0f]76 [0x4C]M16 [0X10]77 [0x4D]N17 [0X11]78 [0x4E]O18 [0X12]79 [0x4F]P19 [0X13]80 [0x50]Q20 [0X14]81 [0x51]R21 [0X15]82 [0x52]S22 [0X16]83 [0x53]T23 [0X17]84 [0x54]U24 [0X18]85 [0x55]V25 [0X19]86 [0x56]W26 [0X1a]87 [0x57]X27 [0X1b]88 [0x58]Y28 [0X1c]89 [0x59]Z29 [0X1d]90 [0x5A]039 [0X27]48 [0x30]130 [0X1e]49 [0x31]231 [0X1f]50 [0x32]332 [0X20]51 [0x33]433 [0X21]52 [0x34]534 [0X22]53 [0x35]635 [0X23]54 [0x36]736 [0X24]55 [0x37]837 [0X25]56 [0x38]938 [0X26]57 [0x39] 大容量存储(MSC)
建立工程
设置
usbd_msc.h 中的 MSC_MEDIA_PACKET 要设为扇区(sector)大小
w25Qxx为4096 SD卡为512
STORAGE_LUN_NBR为虚拟磁盘卷数目 一般把一个装备设为一个卷 设置这个可以虚拟出多个磁盘
usbd_storage_if.c 的STORAGE_BLK_NBR 为最小操作单元数目(一般写扇区数目)
usbd_storage_if.c 的 STORAGE_BLK_SIZ 为最小操作单元大小 (一般写扇区大小) 单元(Byte)
这俩相乘即可得到总大小 单元(Byte)
注意这俩的blk所指的块与FLASH的差别,也是我写成最小操作单元的缘故原由
可以修改这个末了三项来更改表现名称
usbd_storage_if.c的STORAGE_Inquirydata
APIs
存储读取(必写)
描述名称功能uint8_tlun卷标uint8_t *buf缓冲区uint32_tblk_addr最小操作单元起始地址(*STORAGE_BLK_SIZ后得到Byte起始地址 )uint16_tblk_len最小操作单元的数目(*STORAGE_BLK_SIZ后得到Byte数目 )int8_t输出错误码 在usbd_storage_if.c 中
需要根据自己内容填写
- int8_t STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
复制代码 存储写入(必写)
描述名称功能uint8_tlun卷标uint8_t *buf缓冲区uint32_tblk_addr最小操作单元起始地址(*STORAGE_BLK_SIZ后得到Byte起始地址 )uint16_tblk_len最小操作单元的数目(*STORAGE_BLK_SIZ后得到Byte数目 )int8_t输出错误码 在usbd_storage_if.c 中
需要根据自己内容填写
- int8_t STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |