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

STM32F103C8T6使用MDK 4.12中Custom_HID的修改方法

[复制链接]
STMCU小助手 发布时间:2023-1-7 11:58
STM32F103C8T6使用MDK 4.12中Custom_HID的修改方法' ?+ ~2 m* B9 x* a* y- h( R3 f, |3 B
目的,由上位机发送64字节,设备回应3个字节,功能自定。。
, b& v6 a! j5 v3 B. F( ]0 X  T+ h# J+ M* T( L; n/ ~8 `
板子使用的是最小核心板,MCU为STM32F103C8T6。
" t1 X* m2 ~0 f/ H4 a# q$ c. |USB的D-和D+分别接到PA11(USBDM)和PA12(USBDP)上,PA12(USBDP)即D+通过跳线使上拉1.5K电阻到VCC(3.3V)。
! V% `2 U4 Y& v' \8 j7 B1:打开MDK4.12,打开  r$ q7 H; d7 l- w. ~
C:\Keil\ARM\Examples\ST\STM32F10xUSBLib\Demos\Custom_HID\project目录下的Custom_HID项目文件。& [* ^; q/ H, [' N9 {

  k; Q- U' U# k( p. i2:选择菜单 Project->Options for Target 'STM3210E-EVAL': T8 h( Q7 U3 h3 F0 @  k
在Device选项卡里选择 STM32F103C8。/ m% W1 P3 b1 Q8 j: k. M/ H. h
在Output选项卡里把Create HEX File选上,取消Browse Information。! `( c2 P( D6 O' {0 z
在C/C++选项卡里的Preprocessor Symbols里的Define: USE_STM3210E_EVAL清除。% {, E2 u; V' u3 \2 Q; M- @! q# f

* c: J5 t4 M! V! j3:从Application files组中的文件由上而下逐个修改% r. \: b% Z. I! ?+ D7 S7 `( V
第一个是usb_pwr.c( L  R4 w1 h5 L- K
把PowerOn和PowerOff()面里的USB_Cable_Config(ENABLE);和USB_Cable_Config(DISABLE);这两句删除,因为我的板子上没有这个控制电路,
' Z' f& S  _  p* o6 z而是通过跳线把USBDP通过1.5K电阻接通到VCC(3.3V)的。
" Z" f' I% K- f接下来修改hw_config.c1 k, a1 A2 O  i
把
$ ?" f! [$ X" m8 I#define ADC1_DR_Address    ((u32)0x4001244C)) Q+ \( I9 r' L% W
u32 ADC_ConvertedValueX = 0;: s0 {, L# K  e9 y
u32 ADC_ConvertedValueX_1 = 0;$ A0 E! A5 a3 G
这三句删除,因为我不用ADC,外部中断和DMA,只需要跟上位机通信点亮板上连接到PB0上的一个LED。3 ^4 L5 j: h3 `8 t: F; `

! f2 K. [/ z3 ^! [; k所以还要把Set_System函数里的
& i5 j/ S/ F# u: WEXTI_Configuration();
& f7 x5 ^6 J. _4 BADC_Configuration();
4 h* ^% U/ V* c- ?) C0 o- w这两句删除。
! w6 K" T# ?  @7 a/ m4 o+ e# E* `+ Z

6 D  Q, A$ V% E" |: `; E把USB_Interrupts_Config函数里的  ?" @( o3 A7 ?5 S' H- M8 w
EXTI9_5 Interrupt; ?+ [; B$ a8 k1 \  \
EXTI15_10 Interrupt3 q& {: U) m5 ~/ X' L* |% c8 W2 P
DMA1 Channel1 Interrupt/ B! e) i! t+ J
这三个相关的语句都删除。
: b- u' a$ i2 ^
' v. H  ~2 f! d9 O8 N
把USB_Cable_Config整个函数删除。- H  r- x8 p4 n0 e' g& D# a& ^, [' k
# V$ c$ z7 t- }0 G8 j2 R6 y
把GPIO_Configuration里面的& T, P- N. q' C9 u" B  ?( M/ C( f
KEY& ]9 O) I& w' [- X, Q# L/ x
Tamper# l$ I( F+ o5 P& q) y- W) u
Potentiometer
4 T% ~+ i7 f; l% U三个相关的配置语句都删除。, n: N! D( F0 }" X2 f4 F0 C/ G
下面的LED配置只配置LED1,用来指示上位机的指令,其它都删除。
2 W. |" d% C. _8 D9 M1 K# z' s8 l# }
把- h8 \0 e" B6 G
EXTI_Configuration
9 g" j7 y0 O0 {ADC_Configuration
/ G) b/ q1 E8 v+ D这两个函数整个删除。
' o! l& R; G! H5 M7 W8 [
9 v8 e" |0 B' A+ e# T% v" r. M" {加上这句RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); 别忘了开CRC电源。计算序列号要用到的,否则序列号就会变成42949-67295,是0xffffffff,是错误的。
- Z8 b/ h* ]4 {5 z8 @( r# M. p6 l

! j+ R5 E% _4 w+ C$ ?把Get_SerialNum函数的功能改成如下" v* @/ Z, V4 N7 @0 U
目的是把96位ID作CRC运算后来做产品的序列号。4 X" Z4 ~  c) S, G  q* P9 K$ v; h
可以不要这个函数,只在usb_desc.c里定义序列号。同时其它文件里用到这个函数的地方就要删除。
" [' I8 w# d+ {- u* h' {: c* d' v2 e% f8 d" r
增加RBIT这个函数,32位位倒置程序,CRC用到的。因为STM32的CRC计算结果跟一般的CRC校验工具计算结果不同,所以要特殊处理。
; \% t2 f+ F& l; v3 M1 o/ I8 @如0 R, Y$ n1 i( N3 z
原始序列号: 39006C0658343131496705431 b) Y: L+ m) }; K& s
分成三个32位数。每一个32位按位倒置,然后给STM32计算CRC,结果跟0xffffffff异或运算后,再把32位的结果按位倒置。就对了。1 z' w& [' R7 r0 C# s
39006C06=00111001000000000110110000000110 = 01100000001101100000000010011100 = 6036009C8 D* i* Q. P" o
58343131=01011000001101000011000100110001 = 10001100100011000010110000011010 = 8C8C2C1A% l7 X: j# `, ^9 g3 F' X3 g
49670543=01001001011001110000010101000011 = 11000010101000001110011010010010 = C2A0E692+ \! J0 h; w7 i$ d) h( r. p  |

) K  _+ P. ?+ K0 V) _9 V4 GSTM32的CRC结果跟0xffffffff后为十进制4289354847=FFAA5C5F=11111111101010100101110001011111=倒过来11111010001110100101010111111111=FA3A55FF( d. E4 c& ]' m  M$ Y( J, R
$ S/ R9 B, q. u) u- e+ R6 Q
  1. __asm u32 RBIT(u32 value)
    " Y& P6 x, d. q+ N) h# N& C4 L
  2. {9 |$ [( U! n4 i; t; W
  3.     rbit r0, r0" b: ^; c8 |7 f/ ~
  4.     bx lr
    - B4 ?  ~# g" X* y  R* l, \, ^
  5. }  h+ p, ~( S) v
  6. 5 z0 _2 D7 ~, f/ j

  7. 0 F- M5 m/ C' K4 F; p
  8. void Get_SerialNum(void)
    : N9 g& f2 m* ^* B
  9. {8 |+ i& ^! [, _; C1 I& I1 _# t
  10.   u32 Device_Serial, Device_Serial0, Device_Serial1, Device_Serial2;+ p7 |0 B' Z$ `' _3 F4 W- Y
  11. 3 q' z' x; l$ L
  12. 3 K$ I" z9 S, @) d, N) \
  13.   Device_Serial0 = *(u32*)(0x1FFFF7E8);
    6 A9 ]* k. D5 d4 s" J% {
  14.   Device_Serial0 = RBIT(Device_Serial0);
    & ?- \* \" ~' c8 v

  15. " m0 g0 w6 D8 q9 s: I  U/ u

  16. 2 p* z7 ?+ y" V( p
  17.   Device_Serial1 = *(u32*)(0x1FFFF7EC);
    7 z$ c) j5 Q7 F0 O# V& s  {4 S
  18.   Device_Serial1 = RBIT(Device_Serial1);4 V$ g! v9 x1 Q; y' [

  19. + I: m- B: M6 B8 [
  20. + u- e5 ]5 {2 w+ [! ^5 n! W: |9 R* F+ i8 F
  21.   Device_Serial2 = *(u32*)(0x1FFFF7F0);9 i# `% ]! N& ?( c5 D7 F" Z
  22.   Device_Serial2 = RBIT(Device_Serial2);7 o; L8 i# n% W6 h7 n0 V+ o

  23. 3 z3 r; r- A) l% `5 B8 y7 h- C
  24. ( E. K/ A; W  V0 i; ]; _
  25. 8 S5 f6 y6 I; u( c
  26. ; g& S( r( Z. ?/ S( N' `' H
  27.   CRC_ResetDR();
    / i9 E1 B* ^$ `$ B3 G' a
  28.   Device_Serial = CRC_CalcCRC(Device_Serial0);( @( H5 j  r  ^9 u! j# c
  29.   Device_Serial = CRC_CalcCRC(Device_Serial1);/ f- D" C6 R- a1 l/ K& c" Y. s# V
  30.   Device_Serial = CRC_CalcCRC(Device_Serial2);8 K. ~3 i) q4 i% v! L( F# r

  31. * @5 @5 e0 p. ^+ g8 w1 T4 Z7 |6 |

  32. ( M5 R' Z" _9 M7 C7 Y- G: f
  33.   Device_Serial ^= 0xFFFFFFFF;& T* q3 @5 [: L2 F
  34.   Device_Serial = RBIT(Device_Serial);3 d6 H6 n( c; R9 y9 ]2 J$ f  _
  35. 5 R1 }5 p( z8 t% h& S1 o5 P% G2 K1 W

  36. - s7 n. D9 s" z
  37.   if(Device_Serial != 0)
    & I0 ~% g0 ~) {0 |
  38.   {
    3 @+ ^5 J0 ~# v5 C3 B
  39.   CustomHID_StringSerial[0] = CUSTOMHID_SIZ_STRING_SERIAL;
    % P! M7 w; `  d8 M: z
  40.   CustomHID_StringSerial[1] = USB_STRING_DESCRIPTOR_TYPE;
    ! n- Z% }4 q: `7 |
  41.   CustomHID_StringSerial[2] = (u8)(Device_Serial/(u32)1000000000)+0x30;
    3 q' {' u5 _8 X. p; k
  42.   CustomHID_StringSerial[3] = 0x00;8 h/ s: B* T1 K
  43.   CustomHID_StringSerial[4] = (u8)((Device_Serial%(u32)1000000000)/(u32)100000000)+0x30;$ a9 N' h- v' X  S% R) w( i
  44.   CustomHID_StringSerial[5] = 0x00;0 A9 j5 }3 p; }$ w% T7 j' m8 _8 H
  45.   CustomHID_StringSerial[6] = (u8)((Device_Serial%(u32)100000000)/(u32)10000000)+0x30;
    ( l9 N, k  f& W6 k% T
  46.   CustomHID_StringSerial[7] = 0x00;
    % i  R! a7 L+ w6 v
  47.   CustomHID_StringSerial[8] = (u8)((Device_Serial%(u32)10000000)/(u32)1000000)+0x30;
    7 X7 K5 M! c  a8 [/ C
  48.   CustomHID_StringSerial[9] = 0x00;
    ( i: |4 E& S0 G6 R/ v0 K5 j
  49.   CustomHID_StringSerial[10] = (u8)((Device_Serial%(u32)1000000)/(u32)100000)+0x30;
    , O  h" D2 |7 p/ b5 @
  50.   CustomHID_StringSerial[11] = 0x00;- v3 s2 _/ @( @
  51.   CustomHID_StringSerial[12] = '-';! P( U  M+ K6 _5 k
  52.   CustomHID_StringSerial[13] = 0x00;
    1 E" {- N$ v( I  A+ z$ N8 N; }
  53. ( |' q' j0 Z: ~3 S. a0 ?( F! C/ E
  54. 8 Y, U" m. n5 O7 V
  55.   CustomHID_StringSerial[14] = (u8)((Device_Serial%(u32)100000)/(u32)10000)+0x30;
    5 |5 o) F3 W; S; G5 Y3 u3 `- @( L
  56.   CustomHID_StringSerial[15] = 0x00;
    9 d4 q# S# H6 ~7 w( a: I) [
  57.   CustomHID_StringSerial[16] = (u8)((Device_Serial%(u32)10000)/(u32)1000)+0x30;
    : y0 T$ f: D( ?! I$ U) s
  58.   CustomHID_StringSerial[17] = 0x00;3 R% L9 r% C! G: K. C" F
  59.   CustomHID_StringSerial[18] = (u8)((Device_Serial%(u32)1000)/(u32)100)+0x30;
    ' r" u9 W2 K* [( X  C1 K' q6 L- l
  60.   CustomHID_StringSerial[19] = 0x00;2 V0 @# ]6 {& u' S! M$ J& q
  61.   CustomHID_StringSerial[20] = (u8)((Device_Serial%(u32)100)/(u32)10)+0x30;
    - D6 b- |& v* r- Z
  62.   CustomHID_StringSerial[21] = 0x00;; ]* M9 {3 u% z7 J/ J& V
  63.   CustomHID_StringSerial[22] = (u8)((Device_Serial%(u32)10)/(u32)1)+0x30;
    $ {5 Q1 Z5 B$ G0 ~, U$ w3 v
  64.   CustomHID_StringSerial[23] = 0x00;. X3 N# q; o0 p( F& [7 M
  65.   }   
    5 ]# a$ @5 j4 ~
  66. }
复制代码

# Q' G/ [7 x5 B/ W3 N5 L& B! v然后修改对应的 hw_config.h* \) ]7 ^8 [% k
void USB_Cable_Config (FunctionalState NewState);
* m( i! E' [% C: ?void EXTI_Configuration(void);) R$ T7 u$ z; p( X3 L
void ADC_Configuration(void);& o  B% ]) ?2 Q. B+ k
把这三条删除。, x: V$ k4 T- q+ U) a
Get_SerialNum也视情况决定要不要删除。
8 C4 k  {2 y2 {) H1 q
7 }7 b6 A/ E7 ]; e, {main.c不动。9 o5 t  x0 }  x' Q- z6 B, e

2 ]! @9 ^5 g7 g0 j$ R接下来修改 stm32f10x_it.c. u7 X* n! v6 q/ g: D1 @  X/ W* s
把u8 Send_Buffer[2]; 这句删除。9 F" e- k( ]6 G0 p' M
+ b9 O8 d% ?. h9 D; m
把
: F: y* f6 K0 y# D4 D* R* sextern u32 ADC_ConvertedValueX;
+ K5 j6 I, K( k; o& hextern u32 ADC_ConvertedValueX_1;
$ x' s2 e- m' K8 D" x删除。
2 ^  C2 A7 J/ ^

1 [) i% C& \0 ^( }把- Z( P8 W5 R. V0 Y
DMA1_Channel1_IRQHandler
* K9 K! a8 k7 \9 NEXTI9_5_IRQHandler
9 ?- I8 s5 S- p3 v. ^EXTI15_10_IRQHandler
+ m+ @6 o4 f& l0 Q" F这三个函数清空,是清空里面的内容,保留一个空的函数。' v" M( Z: h% m2 j# r
, ?" I) ?/ l( T9 h4 l! U6 @" R
接下来改 usb_desc.c
) [4 b2 ^! x+ h把报告描述符改成自已的:1 @* i) u5 M" @, D) d( k, a% _9 y' \
  1. /* CustomHID_ConfigDescriptor */& G) N4 T/ P- A* P2 D# d
  2. const u8 CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =% v4 U7 l0 g" N, X$ j- w
  3.   {    & ^9 l( B, H* Y
  4.     0x05, 0x01,                    // USAGE_PAGE(User define)
    $ U/ ?1 k% l, v& Q9 U
  5.     0x09, 0x00,                    // USAGE(User define)3 b6 I2 k, y2 {$ |
  6.     0xa1, 0x01,                    // COLLECTION (Application)
    6 m: ~8 }( t0 M# x
  7.     0x19, 0x00,                    //   USAGE_MINIMUM(0)
    . A- @/ Y4 z/ L5 G
  8.     0x29, 0xFF,                    //   USAGE_MAXIMUM(255)5 Y# M* ]  W9 a  g+ ^* G
  9.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    * D7 `6 h3 u( b, x" y
  10.     0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)
    3 ^/ S3 Q% ?3 o: L& v
  11.     0x75, 0x08,                    //   REPORT_SIZE (8)
    9 [4 [  p% M1 W7 Z/ Q
  12.     0x95, 0x03,                    //   REPORT_COUNT (3)$ V/ U% I7 a. n' E1 Z' M* [; P
  13.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)! _* l4 h$ O4 t# ^

  14. + Z8 J3 v3 m  A! M5 g1 ^) x( ~

  15. 8 ~2 K) j. s1 N: Q6 _
  16.     0x05, 0x02,                    // USAGE_PAGE(2): K0 ?) x: ]# h6 [. B# ]7 X6 I4 A
  17.     0x19, 0x00,                    //   USAGE_MINIMUM (0)
    6 Y& Z. T4 {. C8 F- ~$ Q
  18.     0x29, 0xFF,                    //   USAGE_MAXIMUM (255)% j0 i# D' u4 R6 z! |
  19.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    ' \) c, s% u9 h) q% t5 \, k7 t: K
  20.     0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)
    & P  V8 @; m( s; S& {* n( W3 b
  21.     0x95, 0x40,                    //   REPORT_COUNT (8)* k2 s- b, F0 c& o8 z
  22.     0x75, 0x08,                    //   REPORT_SIZE (64)
    8 q0 S  s, [& I1 O) g: M  V2 u  {3 C
  23.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs), ?9 {( {/ [5 N2 ^; @8 n" g

  24. : |* E6 c8 ?8 s, l9 Z

  25. 6 O$ I$ q3 P; |6 c  H
  26.     0xc0            /*     END_COLLECTION              */, K; ]. n3 Z# t3 Z% T. _
  27. 6 a. h  ?6 f7 x% c

  28. / ]4 i: S. Q1 |, E. b
  29.   }; /* CustomHID_ReportDescriptor */
复制代码

4 K8 K- M/ U3 W! Y然后更改配置描述符中的输入输出端点的最大包数。输入端点改成3个字节,输出端点改成64字节。
) b9 d+ N2 z4 n" d
( m  x% s. `7 Q/ v# p( o& e. ?) s( o
再来改下面三个字符串描述符,使用的是UNICODE格式的,用记事本写好保存为UNICODE格式文件,再用十六进制编辑器打开就看到了。/ P" c8 }% J& c8 ~; y- \7 H3 w' G; K+ A

+ g6 c. I9 W. m3 a改完以上的数据,还要更改usb_desc.h里的定义的大小。(注意字节数还包括描述符长度及标识),如上面的报告描述符大小应改成$ m" B  Z0 ~) ?2 U
#define CUSTOMHID_SIZ_REPORT_DESC 37
. g* C7 V8 X, W3 ^

: Y- [! [5 j  M, g9 L接下来改usb_endp.c
, H0 l2 Q7 I9 |4 @  r% v# n$ c! w把! V/ x: l+ r9 m- H# N
u8 Receive_Buffer[2];
- b  x' q7 k; z! {  y+ N改成
0 T2 c2 V+ q& m; ]& W8 Fu8 Receive_Buffer[64]; //因本例中要求上位机发来64字节。: x5 z0 Q2 Z& O' h; c7 V

; A8 M! {3 k$ o2 \+ C2 ~# T  v然后是EP1_OUT_Callback这个函数的修改,根据上位机发来的数据,作出相应回应。7 N' ?. V! t- C3 o$ `

9 T; Z* H) Z& d5 Wusb_istr.c不用改。
5 \0 G, P  @0 i$ ?- Z
, o8 j6 ^5 Z& C# k8 s0 F$ ~

% A' E2 t  n: \! M然后改usb_prop.c
* ?. d+ b7 K% k2 y把CustomHID_Reset函数里的
' T; ?: I" N2 _: B/ Q5 S5 e  SetEPTxCount(ENDP1, 2);# j* }3 o0 r: W4 {, ?9 ?8 j
  SetEPRxCount(ENDP1, 2);  t8 s% n* I: U
改成
% _" e; n  j0 ^% q  SetEPTxCount(ENDP1, 3);# S( p& a% R  q5 t
  SetEPRxCount(ENDP1, 64);
5 k1 W2 l1 i" Y5 N5 M* A

$ a# o7 n; q, c  U% RCustomHID_init函数里调用了Get_SerialNum函数,如果使用usb_desc.c里定义的产品序列号,这里也不用了。。9 F9 @1 E& |6 ^. R1 y" s) G

# r6 g/ a- r& d' z还要修改platform_config.h; N1 E- a+ O9 ~8 }' ]
把修改LED引脚,USB引脚的定义。
& P0 l7 Q9 z6 b5 p1 Q2 N9 I& M( K1 y+ I( ^- R) H
终于改完了。。
% D- @/ ~. Y& o8 e; w  w

0 E7 |, @* b2 }2 p6 n2 a6 D5 g以下是记录下来的发送程序段。+ a9 d: q/ V! z! _- @+ B
u8 Send_Buffer[3];. n7 U' z( S  S( M; ]$ [
Send_Buffer[0] = 0xxx;
. y. y1 E% A2 ?4 gSend_Buffer[1] = 0xxx;9 w8 G# [+ s$ ~- h2 n0 F
Send_Buffer[2] = 0xxx;
6 T9 }  O7 y! v1 L. e& l' D. OUserToPMABufferCopy(Send_Buffer, ENDP1_TXADDR, 3);4 V% X0 p* r' Q) F9 q! ~
SetEPTxValid(ENDP1);8 d' U+ `6 \  F/ ~) ~- E/ o
" W$ }9 p/ _% w: V
最后要还说一说跟上位机通信要注意的地方,上位机程序要限制只能用运行一个实例,可以用互斥量。运行多个程序会导致USB不知应该跟哪个- e% J: e; S0 t9 `
2 j- j! ^! |( c$ z! s* J7 U3 a2 h
程序通信,数据会错误。$ S( I) J; |5 A( S3 O9 W
注意程序关闭再打开后要获得设备的状态。而设备复位后也要通知上位机,以保证两者状态一致。& ?, r$ H# h. |: ?0 e2 n
上位机程序的读写缓冲都要比设备定义的大一个字节(开始位置,0x00)。这个字节由电脑发到设备中会被去掉,所以设备端不用管。8 q' F* l3 `& d- u+ x
电脑接收到的数据也比设备发来的多一个字节,也要处理掉。。。
1 N* i, R" S5 b还有ANSI跟UNICODE的处理,要清楚。如字符串描述符中的字符串的显示等。6 D3 d, P! B. ^
$ X* B  }& V8 P6 e/ s
, u) `) X& u6 k$ E5 I
转载自:xqhrs232
2 }* y! J0 m% a8 s( u3 @- ~

: x( V% ]3 j! [0 Q) O9 `3 |9 F1 G7 `0 K6 S
赞 收藏 评论0 发布时间:2023-1-7 11:58

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版