请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2023-1-7 11:58
STM32F103C8T6使用MDK 4.12中Custom_HID的修改方法
0 O# m' N  ^! S
目的,由上位机发送64字节,设备回应3个字节,功能自定。。
7 f" v1 R0 a9 j8 A7 |! C/ s) t: _/ ^- i; k& ~( H2 G
板子使用的是最小核心板,MCU为STM32F103C8T6。
! u8 }# K$ v  T7 x2 dUSB的D-和D+分别接到PA11(USBDM)和PA12(USBDP)上,PA12(USBDP)即D+通过跳线使上拉1.5K电阻到VCC(3.3V)。  E& a  b; L" r  ^2 o$ z
1:打开MDK4.12,打开
+ ?' ~( u4 U8 `4 w+ DC:\Keil\ARM\Examples\ST\STM32F10xUSBLib\Demos\Custom_HID\project目录下的Custom_HID项目文件。
. y/ g( l- Y7 E: m$ b' y3 s
3 w) t! T: D2 L0 _( I- ~9 X2:选择菜单 Project->Options for Target 'STM3210E-EVAL'; n& r: b$ e5 }- ]4 ^
在Device选项卡里选择 STM32F103C8。2 L1 b- H! f3 l& h# ?. K
在Output选项卡里把Create HEX File选上,取消Browse Information。' j3 o. B* b3 C) S" k, n
在C/C++选项卡里的Preprocessor Symbols里的Define: USE_STM3210E_EVAL清除。
, ]+ a, x, d: k6 f: P
1 O" o& Q1 P' M/ _4 }3:从Application files组中的文件由上而下逐个修改3 N: @& w1 c; X/ y$ m) ~
第一个是usb_pwr.c) y. O9 d3 K) ^1 s8 Z
把PowerOn和PowerOff()面里的USB_Cable_Config(ENABLE);和USB_Cable_Config(DISABLE);这两句删除,因为我的板子上没有这个控制电路,
( X/ O; J2 `! d% W而是通过跳线把USBDP通过1.5K电阻接通到VCC(3.3V)的。
& n$ B9 h! o1 q" E% @# @& e接下来修改hw_config.c: a/ b  i! E+ l/ C' \: B, i

: b! f/ G4 Y! Y6 |#define ADC1_DR_Address    ((u32)0x4001244C)
8 {& Y# N' m9 q( r" \6 v, pu32 ADC_ConvertedValueX = 0;. J& k) a0 `9 x( ^8 {( y* Z4 T1 g- z
u32 ADC_ConvertedValueX_1 = 0;9 j4 [7 W+ r5 R" j$ n
这三句删除,因为我不用ADC,外部中断和DMA,只需要跟上位机通信点亮板上连接到PB0上的一个LED。2 b2 ]. }2 w" w9 |+ Y7 ~3 o
4 x7 o! u  u/ T2 B
所以还要把Set_System函数里的& b' @- Y% s7 ^3 q( M6 ]" T
EXTI_Configuration();
: x: e1 O. A9 ^) g' nADC_Configuration();
" G' O, @. S5 k$ Q) B  l这两句删除。" J  N) \+ F7 u8 m- }$ ~

$ ~, O6 ?* B) ~5 c: B8 ~3 D# A8 J把USB_Interrupts_Config函数里的
) z- a) D8 q6 k/ ^7 XEXTI9_5 Interrupt# X+ R' A! g$ K0 i; R
EXTI15_10 Interrupt& \2 N# U" I# }5 E9 t0 A
DMA1 Channel1 Interrupt" t5 S5 x# Y3 l2 X7 T. V
这三个相关的语句都删除。  ^! j3 K8 R: t. Y& n+ }! S

/ V2 Q% c$ U  T! r$ d9 \1 v; y  D把USB_Cable_Config整个函数删除。
9 y: b+ m( b' U& j' {5 s1 Q7 q

+ s- L% K( P- I$ Q. b; O把GPIO_Configuration里面的/ E. {7 y% D4 M+ Q' Q  _: L
KEY
; T2 c% {- I6 P5 r4 g% l, b# Y6 ?Tamper; b) j. f3 X5 z$ L1 R( U. U
Potentiometer4 e* I4 f3 C- K3 \1 H2 q
三个相关的配置语句都删除。
9 g5 {" K5 v; @& L. r下面的LED配置只配置LED1,用来指示上位机的指令,其它都删除。
( A0 D' h+ [# L6 P- y
8 ]) \3 ~: y5 {/ I$ y5 C7 y
% P4 ?! B8 v+ U( o) \' CEXTI_Configuration7 `& |7 f, D& `- p
ADC_Configuration  Y- ]2 \: Q+ o- h( m
这两个函数整个删除。
/ P( x) C7 I4 `5 e: P0 E0 q/ o7 S3 S' T1 M6 c+ ?
加上这句RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); 别忘了开CRC电源。计算序列号要用到的,否则序列号就会变成42949-67295,是0xffffffff,是错误的。( U. S) G0 q) J9 x8 {& ?( k
8 K$ L) w! F9 J# a# ?
把Get_SerialNum函数的功能改成如下
1 @# `# {) [* u: C7 z5 x目的是把96位ID作CRC运算后来做产品的序列号。
1 U4 ?4 u/ C' O5 U, R可以不要这个函数,只在usb_desc.c里定义序列号。同时其它文件里用到这个函数的地方就要删除。
) t1 k! B7 V/ M: U' L. w% K5 {+ `
增加RBIT这个函数,32位位倒置程序,CRC用到的。因为STM32的CRC计算结果跟一般的CRC校验工具计算结果不同,所以要特殊处理。: p# L/ L( [7 C1 P2 i% _
) L* W! M7 h7 I! E
原始序列号: 39006C065834313149670543
# w8 `6 B% x8 D分成三个32位数。每一个32位按位倒置,然后给STM32计算CRC,结果跟0xffffffff异或运算后,再把32位的结果按位倒置。就对了。  d' R2 M, X# X2 ^9 G- m: ]7 v
39006C06=00111001000000000110110000000110 = 01100000001101100000000010011100 = 6036009C
% O! C" a* \) {" T& F7 p58343131=01011000001101000011000100110001 = 10001100100011000010110000011010 = 8C8C2C1A0 |% E+ `0 R+ m" B, }7 [: c" ?7 l2 s5 P
49670543=01001001011001110000010101000011 = 11000010101000001110011010010010 = C2A0E692
1 W* _% t- K; n. v/ M$ y$ `* x$ A: V# x6 E0 c% y  c
STM32的CRC结果跟0xffffffff后为十进制4289354847=FFAA5C5F=11111111101010100101110001011111=倒过来11111010001110100101010111111111=FA3A55FF
+ }. _; l( ?# g$ C
& z" W3 Y, U+ ?2 l7 w/ K
  1. __asm u32 RBIT(u32 value)
    ( I0 b" `! t' I4 o4 ^% x! `
  2. {+ L0 t$ o2 u- y) X
  3.     rbit r0, r0
    . `8 e' L' A. z" g5 i
  4.     bx lr
    & e% f) @) f1 {6 o' Z4 x$ M/ [
  5. }6 e" z1 @' X0 x# {/ O

  6. ' U2 |' Z2 _1 m  D& g

  7. % d9 W2 g- x% z' y7 S+ B
  8. void Get_SerialNum(void)3 t/ g' L( D- y+ K3 V, R
  9. {6 J2 B$ I/ h' c) R2 y
  10.   u32 Device_Serial, Device_Serial0, Device_Serial1, Device_Serial2;& f, M3 |* s: g7 o, f$ s
  11. 0 D4 E8 {) [7 `& B

  12. ( Z8 E& f" W3 Q8 @
  13.   Device_Serial0 = *(u32*)(0x1FFFF7E8);: v# m  f; X* v  z1 `( I
  14.   Device_Serial0 = RBIT(Device_Serial0);# |, }8 s- f  j5 s* ]; [; |
  15. 3 `& X5 |  B: G1 ^% r- I5 n

  16. # X3 n2 J$ A& f" B# t
  17.   Device_Serial1 = *(u32*)(0x1FFFF7EC);
    ; _# |& h9 W7 N5 \1 M7 t
  18.   Device_Serial1 = RBIT(Device_Serial1);, X! j/ E; B/ k/ c
  19. ' w7 f8 C2 k2 S

  20. 2 t  b' t2 y; {' T$ D3 T
  21.   Device_Serial2 = *(u32*)(0x1FFFF7F0);/ f+ ?7 I4 T0 y# O
  22.   Device_Serial2 = RBIT(Device_Serial2);
    , `/ C2 ?9 K% F* G/ W( ~7 l
  23. . G/ I6 s; k. ^+ V

  24. ) V! b) j. G# K- z4 v8 u
  25.   `; q5 f, ]) `( Y9 o1 j9 q4 W/ s
  26. * [: }1 R- W& h% H- Q3 B) C
  27.   CRC_ResetDR();! j, M/ e1 h! f7 `$ p/ B
  28.   Device_Serial = CRC_CalcCRC(Device_Serial0);
    % N( }- }" O$ e. |% V
  29.   Device_Serial = CRC_CalcCRC(Device_Serial1);2 t" s) v3 I" L$ \; D
  30.   Device_Serial = CRC_CalcCRC(Device_Serial2);
    " [$ S# z6 ]2 O- M- Q/ y" t1 I
  31. 0 M  _  t& @8 W5 X* `' z
  32. 7 v1 P* T5 K& c' q, P5 S# o
  33.   Device_Serial ^= 0xFFFFFFFF;4 @$ Z; u2 v9 l# z3 F3 k
  34.   Device_Serial = RBIT(Device_Serial);7 k% D4 J0 O% ^# ]
  35. 3 r% W9 @" a3 S7 M) r' i5 b

  36. : J0 Z: y5 R, Y, }+ e
  37.   if(Device_Serial != 0)! h- M' N) l& M  t" q/ J! q9 g
  38.   {
    / X; N/ z" p! D0 E% e4 L4 a
  39.   CustomHID_StringSerial[0] = CUSTOMHID_SIZ_STRING_SERIAL;
    2 i; h7 ]* N2 O
  40.   CustomHID_StringSerial[1] = USB_STRING_DESCRIPTOR_TYPE;% L: G7 ^1 @$ n2 ?: k: J; T
  41.   CustomHID_StringSerial[2] = (u8)(Device_Serial/(u32)1000000000)+0x30;1 u2 u' ?) B; M" g- M
  42.   CustomHID_StringSerial[3] = 0x00;
    1 U: ~2 ]: D1 [& }1 B9 E! t
  43.   CustomHID_StringSerial[4] = (u8)((Device_Serial%(u32)1000000000)/(u32)100000000)+0x30;
    " A2 o9 N' r5 e7 a6 L
  44.   CustomHID_StringSerial[5] = 0x00;. [: R7 y& u, x: B& S
  45.   CustomHID_StringSerial[6] = (u8)((Device_Serial%(u32)100000000)/(u32)10000000)+0x30;7 j7 o+ j+ x; u1 `7 w
  46.   CustomHID_StringSerial[7] = 0x00;
      Z) a: J# l( E6 u. D( d
  47.   CustomHID_StringSerial[8] = (u8)((Device_Serial%(u32)10000000)/(u32)1000000)+0x30;& I. m. R% L9 C) f0 Z
  48.   CustomHID_StringSerial[9] = 0x00;7 g( G0 `% D/ z3 s. j- c6 x/ j% _
  49.   CustomHID_StringSerial[10] = (u8)((Device_Serial%(u32)1000000)/(u32)100000)+0x30;$ N$ T, |" q# s4 t! r% F
  50.   CustomHID_StringSerial[11] = 0x00;
    " G; }  F5 t* S9 H4 B6 a& Z
  51.   CustomHID_StringSerial[12] = '-';
    + ^3 u. p, F4 x+ v8 B& t( }0 @' n
  52.   CustomHID_StringSerial[13] = 0x00;
    4 {+ f4 x+ W2 K' t4 `* }) C" o
  53. 1 ~! Q  _- b: X9 u0 D
  54. 5 r# ], {( K; O5 u* x" |5 J
  55.   CustomHID_StringSerial[14] = (u8)((Device_Serial%(u32)100000)/(u32)10000)+0x30;
    8 i% v) R, u$ L7 O5 }
  56.   CustomHID_StringSerial[15] = 0x00;5 ?0 a7 c4 U# m/ y& L
  57.   CustomHID_StringSerial[16] = (u8)((Device_Serial%(u32)10000)/(u32)1000)+0x30;9 [; n# p) E' s3 R0 R6 r
  58.   CustomHID_StringSerial[17] = 0x00;. ]3 l' c# H1 Z3 \
  59.   CustomHID_StringSerial[18] = (u8)((Device_Serial%(u32)1000)/(u32)100)+0x30;* A+ H0 Y4 a4 K% P: Q
  60.   CustomHID_StringSerial[19] = 0x00;
    & g; G6 i$ u: Y+ o: s
  61.   CustomHID_StringSerial[20] = (u8)((Device_Serial%(u32)100)/(u32)10)+0x30;- n, b0 [- j& ?8 `
  62.   CustomHID_StringSerial[21] = 0x00;
    3 O3 \, j1 |7 g6 U& {. a
  63.   CustomHID_StringSerial[22] = (u8)((Device_Serial%(u32)10)/(u32)1)+0x30;1 @2 \/ E$ l1 T7 V1 [+ O
  64.   CustomHID_StringSerial[23] = 0x00;. r% g6 ]- f; `# ^9 q+ K. p  g( h
  65.   }   8 D- e& J5 Y( h8 i( T. j
  66. }
复制代码
8 V2 @% }  s' L1 [2 W; f
然后修改对应的 hw_config.h* k' n/ E" \" o, m0 X: [
void USB_Cable_Config (FunctionalState NewState);
3 G, M4 |! p! y  V" k$ svoid EXTI_Configuration(void);
7 B# }4 n5 T( L3 w' Mvoid ADC_Configuration(void);+ p# N8 A5 g/ e8 d
把这三条删除。8 K1 J" z. g% F: ?
Get_SerialNum也视情况决定要不要删除。# r7 Z4 }( n2 @# E* n. Y
7 R6 `4 B; t: D# Y8 {9 d
main.c不动。
! p: G) z9 G" G( q( k/ ]
3 D" J8 ]3 i0 y2 u" K接下来修改 stm32f10x_it.c
- X* h7 L; T% D5 c# {- h) I把u8 Send_Buffer[2]; 这句删除。3 {  m. U2 d* k* s; L# Y8 r6 X

! W3 G$ }: {; B7 [
) H- r" x6 S: Z% Y2 I8 f2 eextern u32 ADC_ConvertedValueX;
) n# u  W' x9 h9 a  _- J! aextern u32 ADC_ConvertedValueX_1;
4 A* O8 k. b: e$ F删除。
# D3 ~# ?) }& R& L
7 X2 F- H8 c% @2 ^, x

9 |: w8 U. G+ w! t- g! gDMA1_Channel1_IRQHandler2 ?; T( c1 c) b
EXTI9_5_IRQHandler1 t1 ]4 j) @/ f# ]8 x. m
EXTI15_10_IRQHandler) N) N2 c# B. L- o/ k% B& J
这三个函数清空,是清空里面的内容,保留一个空的函数。
0 [" M  t: w* a8 k" u4 w- W

. G0 p5 |- n% J0 s# |接下来改 usb_desc.c
7 y* `# t8 ~0 O+ I6 v+ h把报告描述符改成自已的:( a: q4 W+ _8 e: G9 e- j$ f
  1. /* CustomHID_ConfigDescriptor */" m; H% h0 C+ K; C( o9 ~+ d
  2. const u8 CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =
    & q5 M" Q$ U1 ^9 V
  3.   {   
    7 }/ V1 L' V- c, ]& O5 B, d2 G
  4.     0x05, 0x01,                    // USAGE_PAGE(User define)
    8 c  R+ P3 D) q# T- ~) V
  5.     0x09, 0x00,                    // USAGE(User define)
    0 a( V! x/ Q6 C- b% J- ^
  6.     0xa1, 0x01,                    // COLLECTION (Application)! ]. X% O$ \# v2 v  _1 l8 Q: G
  7.     0x19, 0x00,                    //   USAGE_MINIMUM(0)- F# g' c& I/ E9 g( ]/ J* J
  8.     0x29, 0xFF,                    //   USAGE_MAXIMUM(255)
    & F: C$ M7 ]; u; u0 @, {
  9.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    ' ~  \+ D0 w7 u/ m7 x, y: _: d
  10.     0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)
    ( b, |/ u8 c/ W$ }- c
  11.     0x75, 0x08,                    //   REPORT_SIZE (8). S5 w& `4 Y) g+ B
  12.     0x95, 0x03,                    //   REPORT_COUNT (3)1 u1 h# x" ]4 M* b
  13.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    ) T. u9 T1 U3 R  X8 `

  14. 5 c8 u; z5 M* W7 A0 }8 D7 D

  15. + G/ L( ?; h' S: s4 p
  16.     0x05, 0x02,                    // USAGE_PAGE(2); d2 y' p5 b* p' {9 L
  17.     0x19, 0x00,                    //   USAGE_MINIMUM (0)' n1 O& |' q8 T! ?) b5 [9 h
  18.     0x29, 0xFF,                    //   USAGE_MAXIMUM (255)
    2 N6 J0 w% Y' D( v9 B0 r5 v
  19.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)6 j& {  N8 B- w5 z3 _; y
  20.     0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)/ v& ^  F, b. [0 w" Z9 C
  21.     0x95, 0x40,                    //   REPORT_COUNT (8)1 v7 W$ _' J5 o# Y- ]
  22.     0x75, 0x08,                    //   REPORT_SIZE (64)
    # ]7 W8 q& ~" U) X9 L; H( T
  23.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)! q# v' M( C' O/ j, i
  24. ; ^7 n2 F' R5 c% W2 }# B) i
  25. 3 w+ m: V) H4 o3 m$ u) _0 M
  26.     0xc0            /*     END_COLLECTION              */- o/ w, I5 Y  x6 \5 h5 E
  27. 0 K; I8 K( z' P. Q

  28. 2 P0 n3 a& F3 s7 F
  29.   }; /* CustomHID_ReportDescriptor */
复制代码
* w* o) d- D" k/ B! {
然后更改配置描述符中的输入输出端点的最大包数。输入端点改成3个字节,输出端点改成64字节。
& ]- ~% V( ]7 s4 L; z

$ q  K) b( a5 v3 H6 v* _$ K) F再来改下面三个字符串描述符,使用的是UNICODE格式的,用记事本写好保存为UNICODE格式文件,再用十六进制编辑器打开就看到了。
8 c! V0 \& b3 @. d! z& h
! I9 W& T- l' j  f; \" s改完以上的数据,还要更改usb_desc.h里的定义的大小。(注意字节数还包括描述符长度及标识),如上面的报告描述符大小应改成
3 ]# n9 p5 w" a1 M#define CUSTOMHID_SIZ_REPORT_DESC 37
3 l' r7 }: j( |, d% x' {1 B  C
8 T, \+ \, G5 ]7 R& n& J# \! n
接下来改usb_endp.c
( x4 L, a. L' E
! O/ E& h3 |2 p7 L% uu8 Receive_Buffer[2];
" u1 J- A! M5 w4 s* A改成
6 V6 o5 f/ \5 _0 E# b7 x7 Lu8 Receive_Buffer[64]; //因本例中要求上位机发来64字节。
0 C$ u7 f# F2 _2 {1 t, Z
7 q; h, |$ c! e% z( e* d
然后是EP1_OUT_Callback这个函数的修改,根据上位机发来的数据,作出相应回应。8 |) N! P2 l5 ~5 i
5 `4 X7 C7 J/ G
usb_istr.c不用改。
7 ?( z. f1 X, O: J
7 c) z0 `& C  s. d: ~4 a- j% O

; Z) t0 B. o( ~% i" j! K然后改usb_prop.c
5 z3 g$ G/ W: J3 {% P4 x把CustomHID_Reset函数里的
3 A$ l; z6 _( u- v+ w  SetEPTxCount(ENDP1, 2);
& @* J$ b* e, e; Q# z* |1 X3 Y  SetEPRxCount(ENDP1, 2);
8 N+ V, Q4 L0 z2 t0 r# r9 s" A改成& x- S& O8 {. T( z7 A0 e
  SetEPTxCount(ENDP1, 3);) O. o, `8 A1 G9 y! B( ^5 ]7 h
  SetEPRxCount(ENDP1, 64);1 p! a) b* S# N  E3 m7 x

/ j# M0 p& ]- \3 OCustomHID_init函数里调用了Get_SerialNum函数,如果使用usb_desc.c里定义的产品序列号,这里也不用了。。
) _' W" F3 S8 P+ n7 q
1 j* f! i9 X. M( o4 K9 V! I7 b
还要修改platform_config.h
2 W: k" H( d0 g! V% b/ q; l( G把修改LED引脚,USB引脚的定义。
/ i/ s/ E3 m6 u# ~) w! c# f# c$ A
& y2 x7 \' R0 ]5 _( @# R终于改完了。。* o+ x5 t& Q/ H9 w9 Q' O  s

; r5 z" D8 \  r( P+ w$ J以下是记录下来的发送程序段。) d. }2 T0 P+ O5 M
u8 Send_Buffer[3];
+ C4 }% Z8 F& d6 ESend_Buffer[0] = 0xxx;0 ?  q0 }5 n6 k1 j" g
Send_Buffer[1] = 0xxx;
! Z( I. C6 Z% G* \Send_Buffer[2] = 0xxx;
0 F5 p1 m  x9 `0 O# X4 |UserToPMABufferCopy(Send_Buffer, ENDP1_TXADDR, 3);
. b& p: [# N* x% \) E/ q6 |SetEPTxValid(ENDP1);
( k; |/ [' g: h# ^. G
% ~7 b" |" l2 ^/ V9 @: p2 H
最后要还说一说跟上位机通信要注意的地方,上位机程序要限制只能用运行一个实例,可以用互斥量。运行多个程序会导致USB不知应该跟哪个3 L/ y- J/ A5 B4 q4 g: b  [

5 k$ y# d1 M% D5 C: a. w8 ~  i$ e2 U程序通信,数据会错误。6 ]' `) {% E0 ^, k7 W8 f
注意程序关闭再打开后要获得设备的状态。而设备复位后也要通知上位机,以保证两者状态一致。8 e5 f$ m: ?( q% j6 \7 h' ?0 R
上位机程序的读写缓冲都要比设备定义的大一个字节(开始位置,0x00)。这个字节由电脑发到设备中会被去掉,所以设备端不用管。
0 S- B& g) J4 \1 B) l电脑接收到的数据也比设备发来的多一个字节,也要处理掉。。。- P3 j1 b1 o, F
还有ANSI跟UNICODE的处理,要清楚。如字符串描述符中的字符串的显示等。
# G6 Z" e+ L/ _$ u& {- D' U& B9 K! E2 x. }
1 z; S- R7 X& h& L5 Z5 \; x, w0 Z; z
转载自:xqhrs232
' {1 l( d$ E* _! \& l  i
' b% `, K3 i7 E0 p9 V( @, e

+ Q, p& W8 D8 b; |$ Q+ l! x
收藏 评论0 发布时间:2023-1-7 11:58

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版