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

说一下基于STM32CUBE的USB键盘

[复制链接]
gaosmile 发布时间:2020-5-5 21:59
前面说了USB鼠标,这次趁热打铁,说一下USB键盘。依然只说如何修改,不说背后的原理。原因你懂的,涉及的知识点太多了。
会不会写成USB三部曲?    不知道
猜猜我下一步再写个啥?
6 ~- K9 k. z( F9 T* z! y( ^( g

7 `3 B. \, J" L. ^, S% @, f
生成工程

* U( m& r  r2 j
首先,STM32CubeMX的配置部分不说了,和USB鼠标部分的一样。唯一需要注意的一点是,VID和PID这两个值要改一下,否则主机(也就是电脑)会以为你还是鼠标。
, `5 T- ^' Y/ `" n* p8 S9 a
微信图片_20200505215204.png
* I) I7 b1 I/ b% A) o
, g" e; V: C* g2 X1 H1 [& `3 s7 q
修改usbd_hid.c文件

+ u2 d) O& S0 P! v2 V- a
其次,生成工程后打开,修改usbd_hid.c文件。配置集合(USBD_HID_CfgFSDesc)要做一些改动,首先是长度:
( X8 ?- [  \3 n* `7 q6 [8 ~, `. |5 u
微信图片_20200505215208.png
这是个宏定义,之前是34,现在变成41.
然后是端点数,之前是1,现在改成2.
微信图片_20200505215211.png
接着是接口协议,之前是2(鼠标),现在改成1(键盘)。
再接着是报告描述符长度:
微信图片_20200505215215.png
之前是:HID_MOUSE_REPORT_DESC_SIZE,长度是74,现在改成:
HID_KEYBOARD_REPORT_DESC_SIZE,长度63.
9 L% c2 u  I' F% `0 S+ N
还有就是端点每次发送的数据包长度:
微信图片_20200505215218.png
之前是4,不够用了,现在改成16.

  I/ k+ M7 P) W# H% T
最后配置集合中增加一部分端点描述符,因为USB键盘对主机来说,不光有输入,还有输出。所以,增加的这部分端点描述符,用来描述输出。
  1. ' T( O$ t! @, m$ F( ~
  2. /******************** Descriptor of Mouse Output endpoint ********************/
    ! a  T1 X7 }1 C- F% o+ z4 |6 v0 L* k
  3.   0x07,          /*bLength: Endpoint Descriptor size*/+ u6 Z" O9 v! {6 l0 Z
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
    & M# R- l$ i8 S6 h; R$ g6 U3 j
  5.   0x01,
    . d3 k* B" A- p" V5 |5 _
  6.   0x03,          /*bmAttributes: Interrupt endpoint*/
      X1 y9 w( y1 n  j* y0 s- B
  7.   0x10,2 n. R4 g2 a" z  Q2 n9 k8 u
  8.   0x00,
    0 c/ F# i" y5 j! Z" e) v( L
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
复制代码

5 o4 |4 `- `  B8 f+ e6 h8 n
1 ~" I% h; R& o5 n
  L* b# ?7 O9 ~! T" G7 X
修改HID描述符
: R. x( r, E% x9 g2 \
修改HID描述符中的报告描述符长度:
微信图片_20200505215222.png
上面提到了,之前是鼠标描述符,长度74,现在改成键盘描述符,长度63.

; |( ]0 A6 t. x4 |  Y: ?

8 E  z+ C& f/ A! d

/ j- s1 e+ y1 N8 G  g
生成键盘的报告描述符

1 A' B  ~! F! E1 I+ H( V
把USB鼠标的报告描述符删掉,换成USB键盘的报告描述符。
0 A# P, p& w8 J
不会写USB键盘的报告描述符怎么办?
USB官方提供了一个USB报告描述符自动配置的工具,打开!里面有各种例程,我们直接复制一个USB键盘的报告描述符即可。
微信图片_20200505215226.png
生成.h文件如下:
  1. 6 Q% S' `9 e) u, e9 E' S+ N5 ~
  2. __ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE]  __ALIGN_END =
    9 p5 A- R: x7 ]# `3 C
  3. {
    0 u9 [! ]1 t) S! }9 I
  4.     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)* L2 Y2 Y" f2 a6 V7 `
  5.     0x09, 0x06,                    // USAGE (Keyboard)/ v8 l" j, r6 s9 V5 U% r
  6.     0xa1, 0x01,                    // COLLECTION (Application)/ ], j3 I) D; d' }' H& \3 T% F! x
  7.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)6 l; p7 `  t: l: y. ~) L; X( P9 o% ?
  8.     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0 G7 Y3 b' V, S6 y# k8 T; I
  9.     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    8 {6 Q5 L3 `5 J1 r/ Q) L7 _
  10.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    2 C' R# d$ k+ W! h; z1 j) k# \; z
  11.     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)  C3 l$ l2 u/ C! D- K; Y3 a
  12.     0x75, 0x01,                    //   REPORT_SIZE (1)
    - v: S9 L' K! B5 Z* L1 K
  13.     0x95, 0x08,                    //   REPORT_COUNT (8)
    8 N. V. B2 }- n4 `4 I
  14.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    $ R% \8 Z# v! N, _" q8 R& A
  15.     0x95, 0x01,                    //   REPORT_COUNT (1)
    , ?. z+ R7 f; B9 U5 f
  16.     0x75, 0x08,                    //   REPORT_SIZE (8); D9 ?9 r1 ^3 n- J$ Z& K
  17.     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
    3 B: Z( U+ R2 G: i  I8 v
  18.     0x95, 0x05,                    //   REPORT_COUNT (5)
    ) }% H/ y( _& e& O$ f) k# y
  19.     0x75, 0x01,                    //   REPORT_SIZE (1)+ t7 _; o; p3 z& j6 ]7 K
  20.     0x05, 0x08,                    //   USAGE_PAGE (LEDs)& Y/ k- z* i% b3 |: Q. f
  21.     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock); N% J: R7 J5 G- F
  22.     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
    ) F. `" K2 K, x" r4 P
  23.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)$ D  o4 r7 I/ `7 u
  24.     0x95, 0x01,                    //   REPORT_COUNT (1)
    6 a7 W; h8 O/ N
  25.     0x75, 0x03,                    //   REPORT_SIZE (3)
    5 Z: H: w0 S6 T7 n# G
  26.     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
      p2 T+ b3 @7 j7 z( P9 b0 W+ c
  27.     0x95, 0x06,                    //   REPORT_COUNT (6)
    4 O  D( r+ R8 Q3 _8 O# {
  28.     0x75, 0x08,                    //   REPORT_SIZE (8)
    : H2 {3 f9 N! d/ W4 J! M
  29.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)5 M8 m0 q, y9 {; x7 C
  30.     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    8 x( @0 _$ ]2 P2 V: K
  31.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)$ {# {1 n6 ^/ g1 ~
  32.     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated)): }6 A/ z5 x1 P
  33.     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    2 [. I4 O8 B  {  [; S: P
  34.     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)& r& H% y+ V$ ]/ @; v
  35.     0xc0                           // END_COLLECTION: I- ~: H1 f( y  W
  36. };
复制代码
/ ~. M% Q; D3 k8 T$ h1 e- h

9 P) ]$ x# e1 Q2 ?% d
修改函数USBD_HID_Setup
' I/ u6 S) Z* n0 \8 z6 I9 W
! m7 A0 T8 Y6 @3 c
第五,函数USBD_HID_Setup中,需要修改一部分代码:
微信图片_20200505215230.png
获取报告描述符的部分,之前这里是鼠标的报告描述符信息,现在换成了键盘的。

- v) o/ e7 u2 J7 ?5 w  B+ [- O
# v" S' t9 W8 [+ D
修改main.c文件
) u$ p( r7 y/ V4 @* G
3 N3 K0 M  S2 d; ^7 ~
main.c文件中,添加头文件,并定义相关的数组:
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">3 A: M! a' w1 z" O& |  ~
  2. /* Private includes ----------------------------------------------------------*/
    5 t% a, q8 U4 l. G
  3. /* USER CODE BEGIN Includes */+ `( R0 I& B/ T. {$ v" N2 q" `, I
  4. #include "usbd_hid.h"# D' v% T  _9 v: b! `
  5. /* USER CODE END Includes */! {5 H' }' Y5 Z5 m

  6. 3 i5 G% h: b5 E

  7. / j4 i1 i* x/ p$ j8 G
  8. /* Private typedef -----------------------------------------------------------*/+ w( s1 z. o5 Z8 z
  9. /* USER CODE BEGIN PTD */
    + X2 }$ a! l$ }* S) G
  10. uint8_t KeyBoard[8] = {0,0,4,0,0,0,0,0};5 ~  U( f. a9 [: N: r+ E8 p# h8 i
  11. uint8_t KeyBoard01[8] = {0,0,0,0,0,0,0,0};
    # J7 |7 O* Y$ T  A4 P! E* }
  12. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">
    & Q- v' a% _% Y0 [, O  p
  13. </font></font>
复制代码
$ B$ f+ p8 _/ o& ^: N6 F
修改主函数
( S; U2 C9 X4 t

  Q- O  f& R+ A- e
第七,主函数中循环发送英文字母A~Z。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
    & d0 u  o# t5 x* k/ n9 X6 T2 h6 F6 H
  2. while (1)
    " v4 G: x5 b& ^7 F4 R* K% \+ C9 J
  3.   {
    , }+ h( z" t3 \- \: _# K: J
  4.     /* USER CODE END WHILE */7 e( L8 S5 G  ~) X  ^! x% R
  5. 8 i* P1 a: s7 \, k7 A/ y8 j4 e/ n7 D
  6. . p) Y* F9 p) |
  7.     /* USER CODE BEGIN 3 */5 A1 r' x7 ]7 Q9 [
  8.     if(KeyBoard[2] >= 29)6 h2 |& c* r0 c8 K. j! N
  9.     {
      W& {7 w+ v8 A8 ]0 P
  10.       KeyBoard[2] = 4;
    7 y& U5 ]* h$ Q! l$ x4 \
  11.     }* n+ M( E9 p" D1 b
  12.     else
    6 r3 e1 Z0 C( B9 X, p3 N% V- {2 y
  13.     {/ [3 Q6 w2 a, }2 Y  o
  14.       KeyBoard[2]++;
    " {0 C7 J! \4 g  O8 @9 U
  15.     }4 M! V2 z0 H$ ^
  16.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));: n, [! [% Z( Z4 R9 S: N4 f6 W$ V
  17.     HAL_Delay(15);) J9 R4 N  \1 y; A: F3 m
  18.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard01));) G" Y& Q: ]' y. \5 p- y  I: @
  19.     HAL_Delay(15);
      Y. \- T8 e+ ~" \
  20.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    6 `0 X/ _" N' y2 s; ], J6 a1 v
  21.     HAL_Delay(1000);
    ( b/ N* F) [2 z. m7 D  e: r
  22.   }</font></font></font>
    9 V! r/ \/ G: u* s
复制代码

, A2 c( M; M) w, U) p$ Q% l0 C

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

0 ~$ p( P# W$ Y) |7 D# f6 H* `
最后,保存、编译、下载、上电!新建一个TXT文档,看键盘自动输出字母,爽不爽?
微信图片_20200505215238.png
( V- t" V' ~+ x2 ?3 _/ a
: y& y( |5 e% U- A/ b2 {

$ m! ]( h" h) X6 L' P5 J基于STM32CUBE的USB鼠标键盘二合一

3 W8 w$ K( k- V/ ]; a' ?! P4 `
- {0 z  h5 D& v# g1 r  m/ \- ]
& f% J& A! c$ {9 ^
首先,在5.3.0版本的STM32CubeMX上选择STM32F103C8T6芯片。具体操作和USB鼠标的操作一样,这里就不重复了。
1 j6 b. B1 ]' c% d) Y8 `6 m3 X, {, x
同理,VID和PID要和之前的设备不一样。设置完成以后,直接生成工程。. a& }" W6 E2 Q
微信图片_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 C7 J5 |+ X! t
  2. /******************** Descriptor of Mouse Output endpoint ********************/
    6 i* N4 I8 v  g9 I  \6 E
  3.   0x07,          /*bLength: Endpoint Descriptor size*/. o2 M! W6 o! P( D
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
    : |* O7 f4 Y! _7 {% K; `2 e
  5.   0x01,4 t- e- p/ x9 c6 U
  6.   0x03,          /*bmAttributes: Interrupt endpoint*/- u1 n$ R* F" L2 ~6 Q; b
  7.   0x10,, D+ P1 X8 Z+ O1 W/ t) g
  8.   0x00,
    7 `6 b0 z6 g) A  f
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */</font></font></font>" X- D! d; X% Q: A1 C5 F
复制代码

: M% ]2 I' v1 S/ d( c

( g) c$ h: T/ `* Y8 a
第三,修改HID描述符中,报告描述符的长度:
微信图片_20200505215252.png
之前这里是鼠标的报告描述符,长度有74.现在变成了117.
为什么是117?
看下文!

/ ?% b7 ^5 Z. I$ s7 n) p
第四,修改报告描述符。STM32CubeMX工具自动生成的工程里,报告描述符是鼠标的。现在我们要实现的是键盘与鼠标二合一,要修改的核心位置就是报告描述符这里。

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

, ?; E/ i- v5 {
这样的话,对USB主机(也就是电脑)来说,它收到的数据,有可能是鼠标的数据,也有可能是键盘的数据。那,怎么区分?
5 g+ o( P8 y  L6 b
方法就是分别在键盘与鼠标的报告描述符中放一个报告ID,键盘的报告ID是1,鼠标的报告ID是2.    两个报告描述符,一个长65,一个长62,加起来117.

* K2 `" H  e8 [5 S$ r$ m5 V7 {; x
向USB主机发送数据的时候,数组的第一个元素是报告ID,后面才是键盘数据或鼠标数据。实现前面两节的例程的时候,USB键盘我们定义了一个8元素的数组,USB鼠标我们定义了一个4元素的数组。现在我们只需要一个数组,它同一时间,只发送一种数据,所以大小为8,然后,还要包含报告ID,所以变成9.
在USB协议中,报告ID默认是数组的第一个元素。明白了这一点,我们可以去修改main.c文件了。
, b. Y+ u- L) L5 i! b
第五,添加头文件,并定义相关的数组。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
    , i& s" y7 P6 E# P; C
  2. /* Private includes ----------------------------------------------------------*/
    $ a9 J9 ^+ u$ @/ l, Y
  3. /* USER CODE BEGIN Includes */
    : m- d' L3 k* \8 H$ @
  4. #include "usbd_hid.h"- k* M2 C- c* p; _6 {) y
  5. /* USER CODE END Includes */) }9 g; u& W) c+ h3 E1 _

  6. % ~( y, p" D" e4 A6 H$ e& Q
  7.   ~% c7 x8 t3 B; n8 o& A
  8. /* Private typedef -----------------------------------------------------------*// I" b; A: Y7 p7 \4 K1 p+ v
  9. /* USER CODE BEGIN PTD */! E) p0 ]) X* z/ u6 H
  10. uint8_t KeyBoard[9] = {1,0,0,4,0,0,0,0,0};
    " O- {- T* x! Y" n8 z
  11. uint8_t KeyBoard01[9] = {1,0,0,0,0,0,0,0,0};  ]5 Y, F8 w9 X: q4 x
  12. uint8_t Mouse[9] = {2,0,0,0,0,0,0,0,0};
    # S& O0 G$ r! X0 E6 ?  \8 S1 R& F
  13. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">
    , O9 @1 @4 H) D0 z
  14. </font></font>
复制代码
6 `& J% q; q" m. r" s1 e/ G
; d4 I) G5 z" a$ B
KeyBoard 数组第一个元素是1,Mouse 数组第一个元素是2,这两个值分别对应键盘和鼠标的报告ID。KeyBoard01这个数组是为了表示键盘没有被按下的状态。
. N9 {9 @" e7 ]5 ?5 g: K$ s
第六,修改主函数。循环输出a到z字母,同时,鼠标左键每隔1秒触发一下。

  1. 2 ~9 r/ p3 l: s$ T
  2.    /* USER CODE BEGIN 3 */
    + D/ y1 }6 ?7 B9 l
  3.     if(KeyBoard[3] >= 29)
    ' ^  o3 r) x3 N2 F
  4.     {( z1 L5 ^; B' ]+ ?# w7 J
  5.       KeyBoard[3] = 4;
    ( t* w" K/ H& Q$ w4 {
  6.     }& \# e4 p" ?/ Z& U( {* j
  7.     else
    , V7 A4 v, _3 a/ N2 V' z9 W' S
  8.     {
    8 F. t( b% h2 s* M7 Q
  9.       KeyBoard[3]++;; y! T3 Z9 O! x
  10.     }
    $ Y# a# `" ?4 K" H
  11.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    ' A3 H( h$ C# }2 J1 E
  12.     HAL_Delay(15);3 C& m4 [5 l: Z
  13.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard));/ l' Z9 S/ }, }6 N. @2 |  k
  14.     HAL_Delay(15);- e0 N- P6 ~3 U9 g* e  {
  15.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));3 `; F! e5 g  f2 g. u, t7 w  f
  16.     HAL_Delay(1000);" h$ v- N4 j& h' S- D8 o7 s2 S
  17. 2 Y7 L; T- P7 E; t/ W; S. m- W7 E
  18.     Mouse[1] = 0x01;
    1 z4 S- j: t1 I) g, S
  19.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));0 Q2 M8 R: T5 b2 p# k3 z+ k
  20.     HAL_Delay(1000);% {) [. W8 |  p) |% O6 r
  21.     Mouse[1] = 0x00;
      F: v6 s2 L" |5 ?/ I) u' k& x/ ?
  22.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));
    7 a2 ?# g. X4 F. ^# s/ J
  23.     HAL_Delay(1000);
复制代码

% e* X4 k& ^& p. o. X

7 d- \- F, Q* Y$ I; G
最后,保存、编译、下载、上电!新建一个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 手机版