你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

说一下基于STM32CUBE的USB键盘

[复制链接]
gaosmile 发布时间:2020-5-5 21:59
前面说了USB鼠标,这次趁热打铁,说一下USB键盘。依然只说如何修改,不说背后的原理。原因你懂的,涉及的知识点太多了。
会不会写成USB三部曲?    不知道
猜猜我下一步再写个啥?
, R; u/ J2 f! ^) X( }# `8 Y* o  |
) d1 Y2 Y$ \2 E$ ~( y, g3 m1 d
生成工程
) g% \! Y! u* e
首先,STM32CubeMX的配置部分不说了,和USB鼠标部分的一样。唯一需要注意的一点是,VID和PID这两个值要改一下,否则主机(也就是电脑)会以为你还是鼠标。' [+ L; d9 ^# R: i
微信图片_20200505215204.png

& Q& J( {' W* @' j2 `/ y
' l/ _- S6 S8 \9 B& a7 m/ H- N+ R% {
修改usbd_hid.c文件
' B3 g7 S$ z) M
其次,生成工程后打开,修改usbd_hid.c文件。配置集合(USBD_HID_CfgFSDesc)要做一些改动,首先是长度:% y: n7 S: f0 \  @
微信图片_20200505215208.png
这是个宏定义,之前是34,现在变成41.
然后是端点数,之前是1,现在改成2.
微信图片_20200505215211.png
接着是接口协议,之前是2(鼠标),现在改成1(键盘)。
再接着是报告描述符长度:
微信图片_20200505215215.png
之前是:HID_MOUSE_REPORT_DESC_SIZE,长度是74,现在改成:
HID_KEYBOARD_REPORT_DESC_SIZE,长度63.
7 t: t  z0 j7 Y5 y
还有就是端点每次发送的数据包长度:
微信图片_20200505215218.png
之前是4,不够用了,现在改成16.
4 n4 V; u$ {  C( ?. m$ i" W
最后配置集合中增加一部分端点描述符,因为USB键盘对主机来说,不光有输入,还有输出。所以,增加的这部分端点描述符,用来描述输出。
  1. " p2 }2 }9 b& C6 u% W% {
  2. /******************** Descriptor of Mouse Output endpoint ********************/1 p; _% \8 T. x/ Z% U
  3.   0x07,          /*bLength: Endpoint Descriptor size*/
    + `) B4 l, ]1 I- R& p( l
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
    9 P* P$ T6 B, b" {
  5.   0x01,- R$ R8 r2 w; o
  6.   0x03,          /*bmAttributes: Interrupt endpoint*/$ P, A$ k7 u' r$ N* c, \: x) W
  7.   0x10,
    1 @& X! n# a: H; h: O
  8.   0x00,
    4 p5 J6 n% G" h/ y! B9 C
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
复制代码
+ y2 J& @7 `) {6 L: ]

7 l. f* z% A, t. N5 B) d5 Z9 J
& |, Q8 H7 M5 ^
修改HID描述符

0 W- x" T2 p+ p* t/ R- E
修改HID描述符中的报告描述符长度:
微信图片_20200505215222.png
上面提到了,之前是鼠标描述符,长度74,现在改成键盘描述符,长度63.

9 n2 s' ~" P6 D' e. P# d
& M! X3 o* ~! J  N' t, N9 D
4 j- L7 r0 q' d. Y9 W
生成键盘的报告描述符

6 h+ N$ b7 p  P" o9 ]; a. e
把USB鼠标的报告描述符删掉,换成USB键盘的报告描述符。$ Q# ?' P+ _6 q. T% r
不会写USB键盘的报告描述符怎么办?
USB官方提供了一个USB报告描述符自动配置的工具,打开!里面有各种例程,我们直接复制一个USB键盘的报告描述符即可。
微信图片_20200505215226.png
生成.h文件如下:

  1. 1 f1 Q* A' W& j5 A1 |4 Y* a/ {
  2. __ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE]  __ALIGN_END =
    + P; `  v2 \' B% l1 y  o
  3. {6 s' z3 Z6 {2 w' r; e- p$ F
  4.     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)# I! ]1 N. V) P
  5.     0x09, 0x06,                    // USAGE (Keyboard)8 V8 M( z$ U6 ^1 r8 S
  6.     0xa1, 0x01,                    // COLLECTION (Application); A8 L' [$ M' @$ j! n
  7.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    2 S/ i+ [1 v% ]$ Y" ?
  8.     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    $ E- m% L5 B- Y1 F* X# x
  9.     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    9 h- F& S% J# b6 G1 I) a& v
  10.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)) q, e8 g$ @) A
  11.     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)1 u7 T! }+ t3 |+ T" O# J# A
  12.     0x75, 0x01,                    //   REPORT_SIZE (1), E, B2 q; A6 e) W4 U2 C/ ?; x1 K
  13.     0x95, 0x08,                    //   REPORT_COUNT (8)' z* j0 Y- R  ?/ Y) G% Z
  14.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)" V7 H5 V5 r8 o& f8 B6 F/ f
  15.     0x95, 0x01,                    //   REPORT_COUNT (1)
    - `% ^1 s! y9 D
  16.     0x75, 0x08,                    //   REPORT_SIZE (8)8 f6 u1 R. Q6 r( f6 m
  17.     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
    & |  z4 s1 F6 w  G& ~" s& I, q
  18.     0x95, 0x05,                    //   REPORT_COUNT (5)
    & \5 b  n3 R6 D  F! g& _
  19.     0x75, 0x01,                    //   REPORT_SIZE (1)
    7 q4 i/ E1 b# U
  20.     0x05, 0x08,                    //   USAGE_PAGE (LEDs)3 o( _1 [7 d  }9 p
  21.     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)7 |9 k: X% K: d; R. @
  22.     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)3 w  A& S6 |( h+ E9 l9 n5 L1 d
  23.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)" M: p7 h2 }: J* Y# C( R4 }# D1 K
  24.     0x95, 0x01,                    //   REPORT_COUNT (1)3 G0 Z6 Q4 N0 s& O( D6 Q
  25.     0x75, 0x03,                    //   REPORT_SIZE (3)
    . g1 x$ e9 `. M, f
  26.     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
    9 c$ \* ?' J( m8 q6 `
  27.     0x95, 0x06,                    //   REPORT_COUNT (6)
    - C1 T$ q3 L# ]
  28.     0x75, 0x08,                    //   REPORT_SIZE (8)
    * O( s. z4 P3 y  H9 w1 b0 T
  29.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)" f* e. Y( a% F: X
  30.     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    + f3 A* Y$ c  @+ r: N
  31.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)4 |' d3 N, b  l8 J
  32.     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))9 Q  s, p: I! S/ ]9 F
  33.     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    % }% z" Z; B3 |
  34.     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)1 j+ Y+ o5 E% u2 L
  35.     0xc0                           // END_COLLECTION9 T1 c; X4 E$ Z
  36. };
复制代码
: t9 I  b  o2 c* F4 A  s

1 z( l0 y6 N6 m# i/ `- ^+ f
修改函数USBD_HID_Setup
+ h% T* ?" A" k: ~

5 F1 {! R9 d1 y8 L6 O
第五,函数USBD_HID_Setup中,需要修改一部分代码:
微信图片_20200505215230.png
获取报告描述符的部分,之前这里是鼠标的报告描述符信息,现在换成了键盘的。
* h5 J* y) x6 @7 @' _
6 X: Z. ?5 Q8 u
修改main.c文件
% e8 y( o% Q6 i' g
. }: h  p4 f/ _2 K
main.c文件中,添加头文件,并定义相关的数组:
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
    / R0 e2 z; b& X) S8 k; D
  2. /* Private includes ----------------------------------------------------------*/
    : _2 K- ]4 o6 E% A
  3. /* USER CODE BEGIN Includes */
    3 F! A( b. \! O: v
  4. #include "usbd_hid.h"8 m( H, j+ A/ \, R, p
  5. /* USER CODE END Includes *// ], R3 S# [4 J! z  }: g' N
  6. + X' K$ |. P6 e$ O
  7. , {9 D6 ~5 \, v/ H- `! |4 l
  8. /* Private typedef -----------------------------------------------------------*/
    : @# i* H" b' _
  9. /* USER CODE BEGIN PTD */6 `; T: ~' P, M$ k' C
  10. uint8_t KeyBoard[8] = {0,0,4,0,0,0,0,0};
    ( p! S4 j7 z4 x  F: @
  11. uint8_t KeyBoard01[8] = {0,0,0,0,0,0,0,0};
    " D$ Z' ?7 ?$ Q! M; ]: _
  12. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">
    1 }: T+ i# h3 Q$ I; O) _4 m
  13. </font></font>
复制代码
6 i  @5 G& A* H! O
修改主函数
  f3 G* o2 X9 w* k; j3 T6 o9 Q1 l7 Z
3 g! k% x& z6 V3 a8 W, n, ?( O; `" n7 g
第七,主函数中循环发送英文字母A~Z。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">8 ?# I3 M, l7 p% p' l. q
  2. while (1)/ \+ S9 ~2 j& w0 L8 W
  3.   {; w! K4 \8 i9 o
  4.     /* USER CODE END WHILE */
    7 r5 a5 T7 p6 ^7 G1 |
  5. $ l  v& o6 g$ ?8 a. c8 T8 z0 O
  6. ) J' ], `# ]( H
  7.     /* USER CODE BEGIN 3 */
    / z  n/ o: I) \4 e0 Z7 C' b
  8.     if(KeyBoard[2] >= 29)
    # ~4 }( O& C! [; e" u
  9.     {; ~1 p7 m4 h& f! T
  10.       KeyBoard[2] = 4;6 s" X5 m7 Y0 N, }2 n( z+ C, m
  11.     }7 L8 u# ~5 R6 u; y
  12.     else1 n# n3 J6 o8 G5 E/ t
  13.     {% M$ n9 O7 \! J# \( W2 g) W+ W
  14.       KeyBoard[2]++;, H/ G9 K) s1 k8 |
  15.     }
    / |; C, _. M& b8 n9 |
  16.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    + |3 @7 F( a% c) z3 @
  17.     HAL_Delay(15);
    / s! j: `. |- ]2 L
  18.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard01));" ~" |1 e+ w; R$ |/ ?
  19.     HAL_Delay(15);
    * n+ i( X8 A6 j4 r
  20.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));- x$ ]9 ~4 m! K5 H2 @4 V; Y
  21.     HAL_Delay(1000);: ~- k1 Z& X& X/ \3 d! H: W
  22.   }</font></font></font>: M0 x. p5 ^6 V! L6 \
复制代码
$ {. s  s, M* R1 B6 I4 i

1 S2 C3 ^' z: m
为什么4~29对应英文字母A~Z?
USB官网的文件hut1_12v2中,对键盘的每个按键对应的值,都有一个详细的定义,看第53页,我这里截一部分图:
微信图片_20200505215234.png
# U3 ?, l9 t( F4 d
最后,保存、编译、下载、上电!新建一个TXT文档,看键盘自动输出字母,爽不爽?
微信图片_20200505215238.png

% a. d" M- T' \: e' l; u( S8 J7 a; s

2 f3 Y0 S' O# P) ]1 F, F' ^

' \/ l& a8 \% I* p8 C2 w' j基于STM32CUBE的USB鼠标键盘二合一

( A' Q) `3 [: Q
  x# V+ _/ C2 u  G" G5 l
; t" Q7 k3 h1 I. }
首先,在5.3.0版本的STM32CubeMX上选择STM32F103C8T6芯片。具体操作和USB鼠标的操作一样,这里就不重复了。
0 `* m8 N9 H* v4 R
同理,VID和PID要和之前的设备不一样。设置完成以后,直接生成工程。
6 q1 R2 s6 M1 z8 h2 k4 p5 s
微信图片_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">
    - U  g$ v3 c# R! }5 W' C: c
  2. /******************** Descriptor of Mouse Output endpoint ********************/
    5 n& i5 }& f) S+ M
  3.   0x07,          /*bLength: Endpoint Descriptor size*/
    0 ?  m7 {( `! M7 Y3 `) D1 |; U
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/0 c& @5 v: L5 `
  5.   0x01,
    $ e& k1 f, \3 w( |2 H$ ~
  6.   0x03,          /*bmAttributes: Interrupt endpoint*/9 H. I+ s+ B, g8 r
  7.   0x10,
    9 u7 B+ g* w' U# [7 o
  8.   0x00,
    " u5 @2 x. L4 Z
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */</font></font></font>
    4 T( `+ c$ S7 L2 ^3 c' K4 X
复制代码

" I) Z( U' b. p' X
+ j! O4 U4 B+ d
第三,修改HID描述符中,报告描述符的长度:
微信图片_20200505215252.png
之前这里是鼠标的报告描述符,长度有74.现在变成了117.
为什么是117?
看下文!

5 V! z5 a0 y- [8 c5 X! M. q% C* i
第四,修改报告描述符。STM32CubeMX工具自动生成的工程里,报告描述符是鼠标的。现在我们要实现的是键盘与鼠标二合一,要修改的核心位置就是报告描述符这里。
) h* B9 d8 \1 ?# O4 r! x
简单来说,就是把前面两个例程中的报告描述符合二为一。一个数组里面,上面放键盘的报告描述符,下面放鼠标的报告描述符。
7 N3 U9 j+ f9 ^! ^: [
这样的话,对USB主机(也就是电脑)来说,它收到的数据,有可能是鼠标的数据,也有可能是键盘的数据。那,怎么区分?

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

0 q- F/ M  o6 R; k, C/ @
向USB主机发送数据的时候,数组的第一个元素是报告ID,后面才是键盘数据或鼠标数据。实现前面两节的例程的时候,USB键盘我们定义了一个8元素的数组,USB鼠标我们定义了一个4元素的数组。现在我们只需要一个数组,它同一时间,只发送一种数据,所以大小为8,然后,还要包含报告ID,所以变成9.
在USB协议中,报告ID默认是数组的第一个元素。明白了这一点,我们可以去修改main.c文件了。
; M) x' E9 W( q& G* K
第五,添加头文件,并定义相关的数组。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
    8 d% k; Y% ~* t% M4 x3 o
  2. /* Private includes ----------------------------------------------------------*/
    0 X# N$ K. S7 u% K
  3. /* USER CODE BEGIN Includes */- N7 D5 I# S. a2 R# P/ S3 ^
  4. #include "usbd_hid.h"
    8 w( _9 x* i5 Q, U
  5. /* USER CODE END Includes */5 E+ z" V0 M7 ^5 y

  6. : I1 {) x0 s; [  j+ T9 L: @8 o$ M
  7. + _# O  L7 u7 Y( h  ^+ J
  8. /* Private typedef -----------------------------------------------------------*/$ F% I/ `& _" v3 A* N
  9. /* USER CODE BEGIN PTD */4 Z0 H) F. @- I
  10. uint8_t KeyBoard[9] = {1,0,0,4,0,0,0,0,0};
    , k# v" ^) q2 r  B! \$ u: H
  11. uint8_t KeyBoard01[9] = {1,0,0,0,0,0,0,0,0};! S& A$ w1 I- Z) E4 Z: v" c
  12. uint8_t Mouse[9] = {2,0,0,0,0,0,0,0,0};
      J, p% n; I1 s1 G; {
  13. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">) N" a& Y7 n% ?8 N
  14. </font></font>
复制代码

" N2 `6 R( n- {' S1 m4 T7 r

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

3 Y( L( F+ ?8 Q3 @5 R
第六,修改主函数。循环输出a到z字母,同时,鼠标左键每隔1秒触发一下。

  1. 3 C: J$ B  @2 ?. k0 |6 Q
  2.    /* USER CODE BEGIN 3 */8 E/ p2 O  C! J2 S" t$ T
  3.     if(KeyBoard[3] >= 29)5 z9 a: _4 k, O% }, {
  4.     {  j0 {' p0 W7 U4 P/ i& l
  5.       KeyBoard[3] = 4;; W1 ?: @6 ~, t" T  k. }5 X1 P
  6.     }
    7 Y6 Y% J) L. d
  7.     else/ Y0 N1 u+ x( K: z% Y& R' T& m: {4 i
  8.     {
    4 U0 f1 x1 u- D% q+ ~, Z- K
  9.       KeyBoard[3]++;; k  a( h; P. R7 w# s5 V
  10.     }$ p5 [. g* @/ g1 z( x
  11.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    . T& J. I8 I9 Y* Z/ `! w
  12.     HAL_Delay(15);( e4 [: u0 O* a# ?
  13.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard));7 _* ?% q! f5 F
  14.     HAL_Delay(15);
    " J* A/ O5 B; U: t5 O; D9 N' [  p
  15.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    5 x' H2 o  s- k, l) K( U
  16.     HAL_Delay(1000);
    % H0 S  E/ z6 V8 Q, W$ O. a

  17. & c5 L. d6 m4 ~
  18.     Mouse[1] = 0x01;: X8 `0 {9 G0 @7 ^' c
  19.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));
    8 c' W4 x, v9 @- U
  20.     HAL_Delay(1000);
      `* a" C; |1 t
  21.     Mouse[1] = 0x00;
    : k* X; ~3 k8 R  O, B
  22.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));
    * q* Q8 n  s6 K4 I' W6 ]1 x
  23.     HAL_Delay(1000);
复制代码

; I& @' j5 e8 D6 Q) ]0 _6 O/ o0 s. x

, u9 J9 h7 ]$ f
最后,保存、编译、下载、上电!新建一个TXT文档,可以看到字母自动输出,同时鼠标左键每隔1秒被触发一下。
收藏 1 评论3 发布时间:2020-5-5 21:59

举报

3个回答
李康1202 回答时间:2020-5-6 09:03:15
谢谢分享!
于慈 回答时间:2020-5-12 09:52:47
感谢分享
scnullg 回答时间:2020-11-16 14:54:50
厉害,谢谢分享
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版