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

说一下基于STM32CUBE的USB键盘

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

0 y5 X9 C6 |- V6 [8 D9 U
1 C% H4 L  o. g
生成工程

+ t% x, Y6 K" x6 b2 Q$ o, q
首先,STM32CubeMX的配置部分不说了,和USB鼠标部分的一样。唯一需要注意的一点是,VID和PID这两个值要改一下,否则主机(也就是电脑)会以为你还是鼠标。
1 f5 R3 L* V: f9 _- ?
微信图片_20200505215204.png
; v& q' R5 z, c, M1 i

$ n9 u# p# [3 K; |( X9 ]% d6 g1 N( v
修改usbd_hid.c文件

% R7 [0 c: [: ~# A, H9 J) H' M  F
其次,生成工程后打开,修改usbd_hid.c文件。配置集合(USBD_HID_CfgFSDesc)要做一些改动,首先是长度:
+ o$ D, [; M* {, b; z
微信图片_20200505215208.png
这是个宏定义,之前是34,现在变成41.
然后是端点数,之前是1,现在改成2.
微信图片_20200505215211.png
接着是接口协议,之前是2(鼠标),现在改成1(键盘)。
再接着是报告描述符长度:
微信图片_20200505215215.png
之前是:HID_MOUSE_REPORT_DESC_SIZE,长度是74,现在改成:
HID_KEYBOARD_REPORT_DESC_SIZE,长度63.

- Z; g- l6 `1 V/ G. R' k
还有就是端点每次发送的数据包长度:
微信图片_20200505215218.png
之前是4,不够用了,现在改成16.
, u2 q0 X* S0 f1 H2 Y7 R4 X4 M
最后配置集合中增加一部分端点描述符,因为USB键盘对主机来说,不光有输入,还有输出。所以,增加的这部分端点描述符,用来描述输出。

  1.   j2 }# F9 D5 j* p7 d! t  z
  2. /******************** Descriptor of Mouse Output endpoint ********************/
    3 b0 K: \/ W& ^! E
  3.   0x07,          /*bLength: Endpoint Descriptor size*/+ d: N. t$ J1 p
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
    . ^3 y- y  U0 S$ d; [
  5.   0x01,
    8 V6 M& T  ?3 _9 T. i* f' l& G
  6.   0x03,          /*bmAttributes: Interrupt endpoint*/
    1 N$ S0 D: |: \6 j7 u) f
  7.   0x10,
    8 i- F' D4 n7 M! r; F* n
  8.   0x00,
    ) _0 k, O& S" o3 _
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
复制代码
& P9 e3 a+ f, Y7 b) Q- W4 f
! E$ y5 U# h( j2 n9 i& [& l6 b
5 `0 o+ n# ]% m: T. K
修改HID描述符

( I1 g- q4 b1 k/ i: o9 v
修改HID描述符中的报告描述符长度:
微信图片_20200505215222.png
上面提到了,之前是鼠标描述符,长度74,现在改成键盘描述符,长度63.
4 U( W' N5 ^$ o/ @  C2 b
, _+ y  }0 w, e) L
+ f% k' V2 t# A3 D0 v( r
生成键盘的报告描述符
7 [) A8 Q  n2 _' Y: X$ Q
把USB鼠标的报告描述符删掉,换成USB键盘的报告描述符。
$ |9 C" O, ?7 P3 J( [/ d3 y
不会写USB键盘的报告描述符怎么办?
USB官方提供了一个USB报告描述符自动配置的工具,打开!里面有各种例程,我们直接复制一个USB键盘的报告描述符即可。
微信图片_20200505215226.png
生成.h文件如下:
  1. 9 @3 [5 ^( c" ]9 q
  2. __ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE]  __ALIGN_END =
    7 o. V- r; ~6 H; t
  3. {
    * }! ~* \3 E$ K' y: g
  4.     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)0 q* D) F' F+ G3 K) I
  5.     0x09, 0x06,                    // USAGE (Keyboard)
    9 X! v7 s# ~0 W- l* E
  6.     0xa1, 0x01,                    // COLLECTION (Application)8 j" q7 J4 z( B/ C5 C  o9 A
  7.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    , i) r( p2 ~! J# Z0 ^2 m- u
  8.     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    3 m, K+ m$ n0 C
  9.     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    1 S: Z! H) r7 ]& B" @  c3 o! j
  10.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)" g2 ?% |9 G/ C/ {6 y/ e- l5 P: x& Z
  11.     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)" E$ X8 l  p" \" t7 [
  12.     0x75, 0x01,                    //   REPORT_SIZE (1)
    * s. l' [- X2 v4 `" I" z
  13.     0x95, 0x08,                    //   REPORT_COUNT (8)* ~5 e6 _0 P# Z" b$ B
  14.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    6 j: i% r( H8 X+ e  M0 L2 i
  15.     0x95, 0x01,                    //   REPORT_COUNT (1)* c9 a7 R" h9 K0 U( J. |% V9 g1 }
  16.     0x75, 0x08,                    //   REPORT_SIZE (8)5 n! u% _! g& l( g: q
  17.     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs). b& @# `2 V; M+ H
  18.     0x95, 0x05,                    //   REPORT_COUNT (5)- P+ H; G) j- s+ i3 h, v
  19.     0x75, 0x01,                    //   REPORT_SIZE (1)
    0 |# _. I. X, H8 \3 C( k  f
  20.     0x05, 0x08,                    //   USAGE_PAGE (LEDs)0 ]2 N3 t1 A' C  ?7 U3 o- \
  21.     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
    5 _! |/ u; g8 u; F- p* }8 f
  22.     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
    % h( x' a% [, Z  e* [3 a6 c
  23.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    $ w3 C' }: a8 V! A4 f
  24.     0x95, 0x01,                    //   REPORT_COUNT (1)1 i1 y7 P1 C; O! T9 A+ `
  25.     0x75, 0x03,                    //   REPORT_SIZE (3)5 g# _- P7 r% H& @7 c9 h5 u
  26.     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)8 g" S$ J3 v" X! D
  27.     0x95, 0x06,                    //   REPORT_COUNT (6)
    ; o! X) B( l; ?. b
  28.     0x75, 0x08,                    //   REPORT_SIZE (8)
    ! k$ l2 y5 V, \) F/ F# `0 X: o5 Z
  29.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    % @/ i1 e2 w$ p+ A
  30.     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)3 Z* u* ~% g3 u8 A. c3 w2 u
  31.     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)" {6 q) f* p, U' A( @" h! ^3 I
  32.     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))6 I0 r( p2 V) P8 `2 f
  33.     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    # y- S3 A0 Q" u2 e4 X: E3 e
  34.     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)# V) _, s; R1 Q4 q/ t( \
  35.     0xc0                           // END_COLLECTION
    % ~$ z0 W5 ^; m( G; i  e: V
  36. };
复制代码

  j+ G$ t, C+ h

! q2 F6 i1 z/ ?
修改函数USBD_HID_Setup

& r/ g% ?8 Z3 O3 ~" a& B+ H
2 u: e3 J" [5 q/ a+ g9 Q, s
第五,函数USBD_HID_Setup中,需要修改一部分代码:
微信图片_20200505215230.png
获取报告描述符的部分,之前这里是鼠标的报告描述符信息,现在换成了键盘的。
# y  o1 `  x: U7 }1 @- V

, E# F7 `8 s9 C! W
修改main.c文件
( @, U: }7 R- [
  ^. {, x* s, P/ S$ m
main.c文件中,添加头文件,并定义相关的数组:
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
    ' |: B1 A0 l# [" r
  2. /* Private includes ----------------------------------------------------------*/
    ! u2 P4 U' g( K% \/ h! D4 a: L& F
  3. /* USER CODE BEGIN Includes */
    " ]' ]# ]7 {( Y! s
  4. #include "usbd_hid.h"1 v' t' O( s% I, ?% Q7 x. V
  5. /* USER CODE END Includes */1 W4 u$ Z5 C: H0 R

  6. $ N& ]: O; U3 g7 I, ?  E1 L0 p
  7. 8 b+ l/ M& d8 m* V& {) R4 X1 p
  8. /* Private typedef -----------------------------------------------------------*/
    : [4 ~9 S8 {: U
  9. /* USER CODE BEGIN PTD */3 z* K, R, g5 V" F! M3 M0 f
  10. uint8_t KeyBoard[8] = {0,0,4,0,0,0,0,0};
    + Q1 N* _. f( l9 o9 k
  11. uint8_t KeyBoard01[8] = {0,0,0,0,0,0,0,0};
      K7 O6 b5 w+ D/ J) d
  12. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">
    6 ~+ j+ V7 O9 Q( m" C5 Q4 y
  13. </font></font>
复制代码
0 r4 A  L5 ~& K
修改主函数
9 b5 j+ b# J8 r3 d

. \- K  C3 d* V+ Z
第七,主函数中循环发送英文字母A~Z。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">  Z# {3 `; |! `+ }
  2. while (1)+ ]" h: T3 D0 ~1 Q7 o' V6 ^) a& L" Z
  3.   {2 d( R/ P! h9 _
  4.     /* USER CODE END WHILE */
    ) F$ x' b0 e. C. ?! C8 t& f
  5. 8 ~3 g2 {+ v3 b

  6. $ x. I( l: b: [* v( C
  7.     /* USER CODE BEGIN 3 */
    ( P5 D4 I% ]0 e% _* Q# ^( ^
  8.     if(KeyBoard[2] >= 29)" U) a! \2 T$ a8 a
  9.     {& G4 M6 e% m" A
  10.       KeyBoard[2] = 4;
    & s  y7 `5 d8 p& K
  11.     }1 @* n" @/ F7 j
  12.     else  s2 I' C, z$ K
  13.     {$ W3 ~3 O' j7 {
  14.       KeyBoard[2]++;
    ; p, s7 M, K6 {
  15.     }3 w1 w+ O0 l3 H
  16.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
      u+ V. ]* K' @( Z2 `
  17.     HAL_Delay(15);/ X' h' g. S' J- V, H6 |
  18.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard01));
      ]( Y+ I3 C$ |  P- w: Y
  19.     HAL_Delay(15);
    , ]# b% @# W& a' {7 r; l
  20.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    7 `7 r$ `) m. Y% K) x0 O
  21.     HAL_Delay(1000);) [4 X$ h% m! q6 B, }8 \/ w
  22.   }</font></font></font>7 m2 f, ^7 e9 F8 i  ?# y
复制代码
0 t2 [; V# J) s/ ?2 F

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

4 |- c& S% ~) ~9 g. G1 ]- X
最后,保存、编译、下载、上电!新建一个TXT文档,看键盘自动输出字母,爽不爽?
微信图片_20200505215238.png

: x9 J8 l0 v! P! B  e

" w& E1 G" C; i, [
9 |+ O9 Q# t% C' Q
基于STM32CUBE的USB鼠标键盘二合一

$ i, D; B0 I8 K0 S: c
" q4 r( ~( e5 ~0 {4 t1 E% c& n3 e
% F2 a* ~7 R& E" t0 ]
首先,在5.3.0版本的STM32CubeMX上选择STM32F103C8T6芯片。具体操作和USB鼠标的操作一样,这里就不重复了。
/ k& b& w' w" V. M% Z# m
同理,VID和PID要和之前的设备不一样。设置完成以后,直接生成工程。0 D$ K" L  w/ G1 L1 Q& I
微信图片_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">
    * L" l- A: ~" L' k+ J: n) S& `/ U
  2. /******************** Descriptor of Mouse Output endpoint ********************// s( x- r9 A/ |6 ?7 r( w4 a
  3.   0x07,          /*bLength: Endpoint Descriptor size*/" Y# B. m# `7 o; t+ P
  4.   USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
    5 y4 ]5 u2 n8 s6 \0 s8 @
  5.   0x01,2 k/ X/ l, A3 s
  6.   0x03,          /*bmAttributes: Interrupt endpoint*// {' S9 a( p$ u2 E
  7.   0x10,
    ( _" @1 V. E( y) e
  8.   0x00,
    8 r; s* k0 k3 ?% A' j3 G" k9 d* q, r  C
  9.   HID_FS_BINTERVAL,          /*bInterval: Polling Interval */</font></font></font>7 ?" D. C0 h. E& ]; i
复制代码
# G$ z( U2 b  l7 |

5 H+ g! k. V$ P9 d6 y& E: f9 s& o
第三,修改HID描述符中,报告描述符的长度:
微信图片_20200505215252.png
之前这里是鼠标的报告描述符,长度有74.现在变成了117.
为什么是117?
看下文!

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

- Z) R- O3 p3 h; W) r
简单来说,就是把前面两个例程中的报告描述符合二为一。一个数组里面,上面放键盘的报告描述符,下面放鼠标的报告描述符。

! E( m* v* h; i4 F/ I4 _/ M# z
这样的话,对USB主机(也就是电脑)来说,它收到的数据,有可能是鼠标的数据,也有可能是键盘的数据。那,怎么区分?
) @" }8 D- H' B8 z- R' {  U8 Y' L
方法就是分别在键盘与鼠标的报告描述符中放一个报告ID,键盘的报告ID是1,鼠标的报告ID是2.    两个报告描述符,一个长65,一个长62,加起来117.
) \# y' I3 w% T6 R) u5 ^  A
向USB主机发送数据的时候,数组的第一个元素是报告ID,后面才是键盘数据或鼠标数据。实现前面两节的例程的时候,USB键盘我们定义了一个8元素的数组,USB鼠标我们定义了一个4元素的数组。现在我们只需要一个数组,它同一时间,只发送一种数据,所以大小为8,然后,还要包含报告ID,所以变成9.
在USB协议中,报告ID默认是数组的第一个元素。明白了这一点,我们可以去修改main.c文件了。
4 E9 Z8 ^# `) r" h: T4 ?/ Q
第五,添加头文件,并定义相关的数组。
  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">* x9 p( I" C7 z  m7 T2 b
  2. /* Private includes ----------------------------------------------------------*/, F& v4 {0 w+ v$ K' L
  3. /* USER CODE BEGIN Includes */
    3 [0 k" F. A* L4 q1 w( u3 q& c
  4. #include "usbd_hid.h"
    % ?4 V: p1 x# t2 O4 _
  5. /* USER CODE END Includes */
    ( h5 _/ ], q, E* @9 s; q
  6. * O. V& y, J, D3 w8 R/ p1 I/ }
  7. 1 k. M' l, g# X  Q) U
  8. /* Private typedef -----------------------------------------------------------*/; _9 Y7 C; I4 A- i$ }+ u; i, s: \
  9. /* USER CODE BEGIN PTD */8 w: g3 c! j5 i
  10. uint8_t KeyBoard[9] = {1,0,0,4,0,0,0,0,0};* o2 Q6 H$ H* @8 v- `$ p
  11. uint8_t KeyBoard01[9] = {1,0,0,0,0,0,0,0,0};
    6 |* e' b3 t1 C) p! U. J! e
  12. uint8_t Mouse[9] = {2,0,0,0,0,0,0,0,0};
    ; f* I6 K% S; h5 r
  13. extern USBD_HandleTypeDef hUsbDeviceFS;</font></font></font><font color="#001000"><font style="background-color:rgb(255, 255, 255)">1 w$ P7 Y: t( v
  14. </font></font>
复制代码

! j. f, G* f2 R
) Z. W7 k+ a& x4 z5 T# j+ r3 I# R+ h
KeyBoard 数组第一个元素是1,Mouse 数组第一个元素是2,这两个值分别对应键盘和鼠标的报告ID。KeyBoard01这个数组是为了表示键盘没有被按下的状态。

0 q9 N  d+ K/ j1 N0 k
第六,修改主函数。循环输出a到z字母,同时,鼠标左键每隔1秒触发一下。

  1. " p+ T! O4 @; T, K8 ]+ ~# {) ?
  2.    /* USER CODE BEGIN 3 */
    ; a" ~- G& k' l0 U4 s
  3.     if(KeyBoard[3] >= 29)
    # G3 D6 @6 p. a* P
  4.     {5 L8 |; ^3 [; N# ?' h9 n
  5.       KeyBoard[3] = 4;9 @+ N* K! ~+ ]" A- A2 B
  6.     }% s' F8 K% z. g# }/ S  {
  7.     else! Y- u0 j1 r& \. `# o+ R
  8.     {8 L0 J1 M1 z& u6 S% w) ~* J2 N
  9.       KeyBoard[3]++;) W+ I+ K/ Y( l
  10.     }
    - C3 o' m2 H/ d  \2 {% t* y3 I
  11.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    ) G5 H5 s' r) X% K
  12.     HAL_Delay(15);
    7 Y* P( |2 k( a4 g
  13.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard,sizeof(KeyBoard));
    5 h/ M1 k, @$ {5 M8 C
  14.     HAL_Delay(15);
    5 }! c; R+ O$ G2 j
  15.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&KeyBoard01,sizeof(KeyBoard));
    + R9 c% \4 u0 k' y' Y4 C
  16.     HAL_Delay(1000);; y7 r: A$ k# J# \" `

  17. " {7 x" m. K9 y" r
  18.     Mouse[1] = 0x01;
    2 t9 i3 J) S& a- u% Q9 C& Z, m. \& g
  19.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));& b3 L6 j5 ~, d8 Q& k/ {# r& m  N
  20.     HAL_Delay(1000);
    : E9 N. X' ~6 x3 [' @) T
  21.     Mouse[1] = 0x00;
    / `* e: g# s. |# h
  22.     USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&Mouse,sizeof(Mouse));2 f# i# P! f9 \0 G
  23.     HAL_Delay(1000);
复制代码
# b4 p; ]. |( V  \+ g* ?% l7 E& W
' f4 H1 s9 U0 P+ E6 {9 u/ [# _
最后,保存、编译、下载、上电!新建一个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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版