搜索
查看: 1400|回复: 3

[分享] 说一下基于STM32CUBE的USB键盘

[复制链接]

该用户从未签到

2586

主题

2613

帖子

0

蝴蝶豆

版主

最后登录
2021-3-16
发表于 2020-5-5 21:59:13 | 显示全部楼层 |阅读模式
前面说了USB鼠标,这次趁热打铁,说一下USB键盘。依然只说如何修改,不说背后的原理。原因你懂的,涉及的知识点太多了。
会不会写成USB三部曲?    不知道
猜猜我下一步再写个啥?


生成工程

首先,STM32CubeMX的配置部分不说了,和USB鼠标部分的一样。唯一需要注意的一点是,VID和PID这两个值要改一下,否则主机(也就是电脑)会以为你还是鼠标。
微信图片_20200505215204.png


修改usbd_hid.c文件

其次,生成工程后打开,修改usbd_hid.c文件。配置集合(USBD_HID_CfgFSDesc)要做一些改动,首先是长度:
微信图片_20200505215208.png
这是个宏定义,之前是34,现在变成41.
然后是端点数,之前是1,现在改成2.
微信图片_20200505215211.png
接着是接口协议,之前是2(鼠标),现在改成1(键盘)。
再接着是报告描述符长度:
微信图片_20200505215215.png
之前是:HID_MOUSE_REPORT_DESC_SIZE,长度是74,现在改成:
HID_KEYBOARD_REPORT_DESC_SIZE,长度63.

还有就是端点每次发送的数据包长度:
微信图片_20200505215218.png
之前是4,不够用了,现在改成16.

最后配置集合中增加一部分端点描述符,因为USB键盘对主机来说,不光有输入,还有输出。所以,增加的这部分端点描述符,用来描述输出。

  1. /******************** Descriptor of Mouse Output endpoint ********************/
  2.   0x07,          /*bLength: Endpoint Descriptor size*/
  3.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  4.   0x01,
  5.   0x03,          /*bmAttributes: Interrupt endpoint*/
  6.   0x10,
  7.   0x00,
  8.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
复制代码



修改HID描述符

修改HID描述符中的报告描述符长度:
微信图片_20200505215222.png
上面提到了,之前是鼠标描述符,长度74,现在改成键盘描述符,长度63.



生成键盘的报告描述符

把USB鼠标的报告描述符删掉,换成USB键盘的报告描述符。
不会写USB键盘的报告描述符怎么办?
USB官方提供了一个USB报告描述符自动配置的工具,打开!里面有各种例程,我们直接复制一个USB键盘的报告描述符即可。
微信图片_20200505215226.png
生成.h文件如下:

  1. __ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE]  __ALIGN_END =
  2. {
  3.     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  4.     0x09, 0x06,                    // USAGE (Keyboard)
  5.     0xa1, 0x01,                    // COLLECTION (Application)
  6.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
  7.     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
  8.     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
  9.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  10.     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
  11.     0x75, 0x01,                    //   REPORT_SIZE (1)
  12.     0x95, 0x08,                    //   REPORT_COUNT (8)
  13.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  14.     0x95, 0x01,                    //   REPORT_COUNT (1)
  15.     0x75, 0x08,                    //   REPORT_SIZE (8)
  16.     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
  17.     0x95, 0x05,                    //   REPORT_COUNT (5)
  18.     0x75, 0x01,                    //   REPORT_SIZE (1)
  19.     0x05, 0x08,                    //   USAGE_PAGE (LEDs)
  20.     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
  21.     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
  22.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
  23.     0x95, 0x01,                    //   REPORT_COUNT (1)
  24.     0x75, 0x03,                    //   REPORT_SIZE (3)
  25.     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
  26.     0x95, 0x06,                    //   REPORT_COUNT (6)
  27.     0x75, 0x08,                    //   REPORT_SIZE (8)
  28.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  29.     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
  30.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
  31.     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
  32.     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
  33.     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
  34.     0xc0                           // END_COLLECTION
  35. };
复制代码


修改函数USBD_HID_Setup


第五,函数USBD_HID_Setup中,需要修改一部分代码:
微信图片_20200505215230.png
获取报告描述符的部分,之前这里是鼠标的报告描述符信息,现在换成了键盘的。


修改main.c文件


main.c文件中,添加头文件,并定义相关的数组:
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. /* Private includes ----------------------------------------------------------*/
  3. /* USER CODE BEGIN Includes */
  4. #include "usbd_hid.h"
  5. /* USER CODE END Includes */


  6. /* Private typedef -----------------------------------------------------------*/
  7. /* USER CODE BEGIN PTD */
  8. uint8_t KeyBoard[8] = {0,0,4,0,0,0,0,0};
  9. uint8_t KeyBoard01[8] = {0,0,0,0,0,0,0,0};
  10. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">
  11. </font></font>
复制代码

修改主函数


第七,主函数中循环发送英文字母A~Z。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. while (1)
  3.   {
  4.     /* USER CODE END WHILE */


  5.     /* USER CODE BEGIN 3 */
  6.     if(KeyBoard[2] >= 29)
  7.     {
  8.       KeyBoard[2] = 4;
  9.     }
  10.     else
  11.     {
  12.       KeyBoard[2]++;
  13.     }
  14.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
  15.     HAL_Delay(15);
  16.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard01));
  17.     HAL_Delay(15);
  18.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
  19.     HAL_Delay(1000);
  20.   }</font></font></font>
复制代码


为什么4~29对应英文字母A~Z?
USB官网的文件hut1_12v2中,对键盘的每个按键对应的值,都有一个详细的定义,看第53页,我这里截一部分图:
微信图片_20200505215234.png

最后,保存、编译、下载、上电!新建一个TXT文档,看键盘自动输出字母,爽不爽?
微信图片_20200505215238.png



基于STM32CUBE的USB鼠标键盘二合一



首先,在5.3.0版本的STM32CubeMX上选择STM32F103C8T6芯片。具体操作和USB鼠标的操作一样,这里就不重复了。
同理,VID和PID要和之前的设备不一样。设置完成以后,直接生成工程。
微信图片_20200505215241.png
第二,修改usbd_hid.c中的配置集合(USBD_HID_CfgFSDesc)。如下图所示,框住的地方是个宏定义。配置集合的长度,由之前的34,变为41.
微信图片_20200505215244.png
端点个数,由1变成2.
接口协议,由2(鼠标)变成1(键盘)。
有的小伙伴会奇怪,我们不是鼠标键盘二合一吗?怎么还是键盘?
作为一个技术人员,我们要学会透过现象看本质。虽然表明上是鼠标与键盘二合一,但实际上是以键盘功能为主,而鼠标以一个附属功能加入到了键盘里。所以,这里虽然选的是键盘,但最终的效果是键盘鼠标功能都有。
微信图片_20200505215248.png
好了,继续!
跟USB键盘的部分一样,配置集合最下面,增加一个输出端点的描述符:
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. /******************** Descriptor of Mouse Output endpoint ********************/
  3.   0x07,          /*bLength: Endpoint Descriptor size*/
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  5.   0x01,
  6.   0x03,          /*bmAttributes: Interrupt endpoint*/
  7.   0x10,
  8.   0x00,
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */</font></font></font>
复制代码


第三,修改HID描述符中,报告描述符的长度:
微信图片_20200505215252.png
之前这里是鼠标的报告描述符,长度有74.现在变成了117.
为什么是117?
看下文!

第四,修改报告描述符。STM32CubeMX工具自动生成的工程里,报告描述符是鼠标的。现在我们要实现的是键盘与鼠标二合一,要修改的核心位置就是报告描述符这里。

简单来说,就是把前面两个例程中的报告描述符合二为一。一个数组里面,上面放键盘的报告描述符,下面放鼠标的报告描述符。

这样的话,对USB主机(也就是电脑)来说,它收到的数据,有可能是鼠标的数据,也有可能是键盘的数据。那,怎么区分?

方法就是分别在键盘与鼠标的报告描述符中放一个报告ID,键盘的报告ID是1,鼠标的报告ID是2.    两个报告描述符,一个长65,一个长62,加起来117.

向USB主机发送数据的时候,数组的第一个元素是报告ID,后面才是键盘数据或鼠标数据。实现前面两节的例程的时候,USB键盘我们定义了一个8元素的数组,USB鼠标我们定义了一个4元素的数组。现在我们只需要一个数组,它同一时间,只发送一种数据,所以大小为8,然后,还要包含报告ID,所以变成9.
在USB协议中,报告ID默认是数组的第一个元素。明白了这一点,我们可以去修改main.c文件了。

第五,添加头文件,并定义相关的数组。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. /* Private includes ----------------------------------------------------------*/
  3. /* USER CODE BEGIN Includes */
  4. #include "usbd_hid.h"
  5. /* USER CODE END Includes */


  6. /* Private typedef -----------------------------------------------------------*/
  7. /* USER CODE BEGIN PTD */
  8. uint8_t KeyBoard[9] = {1,0,0,4,0,0,0,0,0};
  9. uint8_t KeyBoard01[9] = {1,0,0,0,0,0,0,0,0};
  10. uint8_t Mouse[9] = {2,0,0,0,0,0,0,0,0};
  11. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">
  12. </font></font>
复制代码


KeyBoard 数组第一个元素是1,Mouse 数组第一个元素是2,这两个值分别对应键盘和鼠标的报告ID。KeyBoard01这个数组是为了表示键盘没有被按下的状态。

第六,修改主函数。循环输出a到z字母,同时,鼠标左键每隔1秒触发一下。

  1.    /* USER CODE BEGIN 3 */
  2.     if(KeyBoard[3] >= 29)
  3.     {
  4.       KeyBoard[3] = 4;
  5.     }
  6.     else
  7.     {
  8.       KeyBoard[3]++;
  9.     }
  10.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
  11.     HAL_Delay(15);
  12.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard));
  13.     HAL_Delay(15);
  14.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
  15.     HAL_Delay(1000);

  16.     Mouse[1] = 0x01;
  17.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));
  18.     HAL_Delay(1000);
  19.     Mouse[1] = 0x00;
  20.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));
  21.     HAL_Delay(1000);
复制代码


最后,保存、编译、下载、上电!新建一个TXT文档,可以看到字母自动输出,同时鼠标左键每隔1秒被触发一下。
回复

使用道具 举报

该用户从未签到

12

主题

1392

帖子

45

蝴蝶豆

金牌会员

最后登录
2021-8-25
发表于 2020-5-6 09:03:15 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

该用户从未签到

0

主题

1

帖子

0

蝴蝶豆

初级会员

最后登录
2020-7-10
发表于 2020-5-12 09:52:47 | 显示全部楼层
感谢分享
回复

使用道具 举报

该用户从未签到

0

主题

7

帖子

0

蝴蝶豆

新手上路

最后登录
2020-11-16
发表于 2020-11-16 14:54:50 | 显示全部楼层
厉害,谢谢分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-4-28 20:13 , Processed in 0.170789 second(s), 35 queries .

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表