串口调试在项目中被使用越来越多,串口资源的紧缺也变的尤为突出。很多本本人群,更是深有体会,不准备一个USB转串口工具就没办法进行开发。本章节来简单概述STM32低端芯片上的USB虚拟串口的移植。在官方DEMO中已经提供了现成的程序,这里对修改方法做简单说明。 2 q# K5 f* v& _2 E4 t: u2 n
$ E9 }3 `# M9 V7 h( D; a, m f
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下: Projects\Virtual_COM_Port文件夹下,复制红线部分 图1 2 H& D' `! e) W; k0 \
$ p6 c2 P& I5 b图2 " A4 K, C4 R7 d* J/ e
n/ A/ K* c' U9 h/ P# j, F我为了方便演示统放在usb/src文件夹下: 图3 1 d+ f! C- }. A9 b. V; r5 ^
0 R% |1 D, m% n; d; ?现在复制USB的库文件,这些文件不需要我们修改: 图4
# W1 |' ?1 s; H, |/ I9 `
2 M5 }+ v. o9 L7 G) \3 ~+ `上图中的文件统一放在usb/lib文件夹下: 图5
% u0 ]/ H A3 p# g- G/ G
* ]! _ p7 p; _5 M3 E' _% L2 o! m* B, o- k, j. G
好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:
y1 B4 z( l0 d0 a( Z4 ~" I
2 K. r" G" o* R$ B- I. f' @; `
图6 由上图可知,PC通过虚拟串口发送数据到STM32 usb口,STM32再通过usart1发送数据到PC串口。我们做项目时,只用USB虚拟串口即可。所以我们现在需要把串口发送部分删除。把USB做为一个COM口来使用。我们要如何使用这个USB口呢?demo中是把USB发送数据做了一个缓存,先把要发送的数据存入缓存中,然后由USB自动发送出去。而接收部分是直接通过串口透传。我们在应用时就需要用到两个FIFO,1是发送,这个和demo方式是样;2是接收,接收也做一个缓存,我们通过查询来判断是否收到新数据。这下大家应该明白为什么使用两个FIFO了。 我这里有写好的FIFO库函数可直接使用Queue.c文件。 现在开始修改: 1,stm32_it.c 更名为usb_it.c删除无用代码,只保留usb中断函数,和唤醒函数。代码如下: 代码1 - 1 /* Includes ------------------------------------------------------------------*/
+ ]$ m2 g3 Y! \( h, g. w2 ~ - 2 #include "hw_config.h"+ _3 V/ l( Q# M4 g9 ~9 \' m' j% ]
- 3 #include "usb_lib.h"
8 {/ M1 }: g% X - 4 #include "usb_istr.h"! j7 \( i- w+ W# ?
- 5
) D- I' h" @9 R! v6 |, }" v - 6 * _: o* }1 J% b! M' s5 w$ D
- 7 /*******************************************************************************
8 a7 Z# i' h, `2 H& M/ n" D - 8 * Function Name : USB_IRQHandler8 v1 Z( L) l" o- M: B3 a+ r
- 9 * Description : This function handles USB Low Priority interrupts
' p0 G- g5 L* y4 N - 10 * requests.
' v! k2 u0 N4 F! j& a - 11 * Input : None1 q$ v# F* N4 R1 s- u" [5 l
- 12 * Output : None
1 w. i4 Z/ f! e - 13 * Return : None* W. X9 z- a+ g9 q& G3 |' N' y
- 14 *******************************************************************************/
6 O+ J: s, ^! ~6 f, b7 l - 15 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)|| defined (STM32F37X)& u% f" o4 v) f1 G( N/ _
- 16 void USB_LP_IRQHandler(void)* L6 J4 d% M! N0 v8 t" y
- 17 #else
5 R0 R% R: @' S1 ?4 D - 18 void USB_LP_CAN1_RX0_IRQHandler(void)6 x- }6 H4 Q. ^! y' X- y
- 19 #endif
) g2 {. `( S3 ?6 s) S' n* c - 20 {
% l7 Q+ v# Y, j* N9 j" Q' V8 z - 21 USB_Istr();
3 R* s( s5 n' w+ K& A. H - 22 }
. e9 `) O0 t1 ~. r" g" K - 23
" S3 |7 M" H( n+ r! l2 N - 24 /*******************************************************************************3 g* D. N+ | C( d
- 25 * Function Name : USB_FS_WKUP_IRQHandler, l3 M* p- M) }- w4 e
- 26 * Description : This function handles USB WakeUp interrupt request.* s+ R% B$ e( K i# e ^
- 27 * Input : None
6 [3 J. H4 ?7 t* i" B( p - 28 * Output : None
8 Q: ^+ m. Z& X' `9 Q% _$ [( Y - 29 * Return : None
: }( C3 ?/ j" a - 30 *******************************************************************************// Z5 H$ ^: ]+ A/ T4 V4 i* L
- 31 - Z) x7 b$ |1 ~% y& Q7 @0 u% c7 K
- 32 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)' Y" z0 b3 {0 N0 L$ U4 O
- 33 void USB_FS_WKUP_IRQHandler(void)+ O8 l" B. Q) v% @9 Z
- 34 #else7 r B7 a# K8 ?; O& I) W. v
- 35 void USBWakeUp_IRQHandler(void)
9 S, \$ x& f7 j1 Q - 36 #endif2 P" B x; I; I$ v. L/ q6 t
- 37 {. N a: C2 y$ ?4 Y7 a+ ?4 G' B' x/ O
- 38 EXTI_ClearITPendingBit(EXTI_Line18);. C6 Y9 h S; ?+ [- q( _2 U5 r& r
- 39 }
复制代码
- O+ H" L4 P8 S/ P4 x, O( {+ t2,修改代码hw_config.c删除无用代码,新建立2组,读FIFO和写FIFO的函数。后面会用到。 代码如下: 代码2 - 1 /* Includes ------------------------------------------------------------------*/& Z! d6 P, s/ p1 ~4 a
- 2
+ `% a6 b4 Y( d* p: S+ Z& f - 3 #include "usb_lib.h"
5 N p6 T; Z/ f. A3 Y2 x7 d" L3 \: M& ? - 4 #include "usb_prop.h"' t, T; A1 {" f ~% C) q$ x) q
- 5 #include "usb_desc.h"
0 m8 Z6 U" q. x - 6 #include "hw_config.h"
- U( x! n! g6 P - 7 #include "usb_pwr.h"
7 x. Q0 ~9 D! n& r& A- j - 8 #include "Queue.h"$ W, n0 z c5 O; H; q4 U& D0 P2 q, n. m+ a
- 9 $ S, N9 p/ {8 O( G1 q3 R8 Q
- 10
8 ^ r; x1 P. S - 11 /* Private typedef -----------------------------------------------------------*/
, B+ A- E- I& ?$ I# o x& \ - 12 /* Private define ------------------------------------------------------------*/- X' J% a- p3 x6 q, P
- 13 /* Private macro -------------------------------------------------------------*/# @ [: R5 G( z9 j- T+ Q& z% P
- 14 /* Private variables ---------------------------------------------------------*/
# m8 L5 O `+ T; o; o - 15 ErrorStatus HSEStartUpStatus;
9 n0 Y( Y' _% V" H/ x/ ~ - 16 USART_InitTypeDef USART_InitStructure;- T6 E6 `0 h) H5 W0 `7 h
- 17 EXTI_InitTypeDef EXTI_InitStructure; U3 Y9 }7 N V, L
- 18
3 Z4 m6 n1 w& Z8 w8 h1 Q7 m - 19 ; a1 x1 w2 Q2 }& |/ n; N6 k
- 20 #define USB_COM_RX_BUF_SIZE (1024 + 256)
. L: m; z' A5 L3 p- J4 F - 21 #define USB_COM_TX_BUF_SIZE (1024 + 256)
" f& \6 I$ [; ^3 ?/ ` - 22 . s6 M& d3 `, ]+ i6 r9 k
- 23 static QUEUE8_t m_QueueUsbComRx = {0};
9 f( n7 ~9 J# c1 o; b - 24 static QUEUE8_t m_QueueUsbComTx = {0};( T; }8 a& R. t" r# x' T# u
- 25 static uint8_t m_UsbComRxBuf[USB_COM_RX_BUF_SIZE] = {0}; 0 o7 b9 h+ m* H1 i0 k9 Z" H
- 26 static uint8_t m_UsbComTxBuf[USB_COM_TX_BUF_SIZE] = {0}; 9 ~3 v% |+ l/ f0 `- T* I
- 27 . T4 E9 l/ l. e4 h& H
- 28 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len); V2 H k: n: f
- 29 /* Extern variables ----------------------------------------------------------*/
+ h, G! E" ~1 d& |8 t6 Z( E9 C - 30 ' g3 X0 ^" W L
- 31 extern LINE_CODING linecoding;
, } r7 v6 ^) l( Q& [, | - 32 # p. c+ D* n. V
- 33 /* Private function prototypes -----------------------------------------------*/5 T5 m: I1 P3 W" Y
- 34 /* Private functions ---------------------------------------------------------*/# A1 W/ g4 d; @
- 35 /*******************************************************************************
1 U) o9 D+ M+ B* j" N6 Q4 t& x - 36 * Function Name : Set_System
1 F$ C$ X0 i6 }" ~, V% D C - 37 * Description : Configures Main system clocks & power# J) x; n8 v y$ r/ D
- 38 * Input : None.
$ W1 m. X1 j0 D; B2 U - 39 * Return : None. T# f! I' j& G0 f
- 40 *******************************************************************************/( x+ p1 ?( T* L7 s) p$ u$ D
- 41 void Set_System(void)1 H) e+ b# }# x: H
- 42 {1 j0 [3 r* J/ O& h
- 43 GPIO_InitTypeDef GPIO_InitStructure;! q2 n, |. R3 `& O, ~4 j
- 44
+ b$ P3 Y; N+ w" G$ m - 45 QUEUE_PacketCreate(&m_QueueUsbComRx, m_UsbComRxBuf, sizeof(m_UsbComRxBuf));
5 Y* D/ ^7 J& F0 x3 [5 Q5 M - 46 QUEUE_PacketCreate(&m_QueueUsbComTx, m_UsbComTxBuf, sizeof(m_UsbComTxBuf));0 P" ~5 A% l6 k; Q& n+ t; ~
- 47 6 L9 f; P& N0 T! A" k
- 48 /* Enable USB_DISCONNECT GPIO clock */
4 f9 I( R! l4 H; q - 49 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);! J9 B1 X7 O: z9 |
- 50 ) H5 t5 L/ @ `6 f& o& M
- 51 /* Configure USB pull-up pin */
- n2 J! l! [. t( L. s: W- q" |+ x - 52 GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
* r9 d) z/ | ^& `3 ]# i% O9 Z5 O - 53 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
; s( v% Q2 z( x( Y; v4 ~ - 54 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
3 x2 e& j1 V# @9 v - 55 GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);- ]" A$ M+ R0 F& X, G7 s
- 56 ; _* T( Q! P. y
- 57 /* Configure the EXTI line 18 connected internally to the USB IP */! L, M, b: \* L% D
- 58 EXTI_ClearITPendingBit(EXTI_Line18);
5 ?& D6 d0 H& f- W% S( e: O - 59 EXTI_InitStructure.EXTI_Line = EXTI_Line18; * {/ d+ ^' @! c/ g+ H
- 60 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;- F8 q) X+ w4 @4 u" N
- 61 EXTI_InitStructure.EXTI_LineCmd = ENABLE;. l5 E% X- r, F$ U2 s% R
- 62 EXTI_Init(&EXTI_InitStructure);
* y3 V4 I( v6 {5 s, T - 63 9 B% Y: V+ ~5 T" `9 S
- 64 ! k* g0 n- ^9 {- a" A
- 65 }
! V6 m% M& N2 N% }- H - 66
; c5 M; ^ Q( K$ m n6 F4 h - 67 /*******************************************************************************$ N/ `7 J4 G3 ~! m% v
- 68 * Function Name : Set_USBClock9 j+ @3 ]: N9 ~+ i9 x
- 69 * Description : Configures USB Clock input (48MHz)* J* D, Y1 g2 o) A" m. J
- 70 * Input : None.! p$ V. S* \/ [0 \3 N# }
- 71 * Return : None.
2 t! ]2 @* g3 y) v- V5 m - 72 *******************************************************************************/. H0 F4 u7 k/ O( b9 O
- 73 void Set_USBClock(void)# l% A- B9 J7 \& l/ i
- 74 {1 X) v* \* @4 n) [
- 75 /* Select USBCLK source */
. T, B" P- r; }2 n# [/ G - 76 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);" ]6 S: e( k {& @0 }
- 77 ! \& P; B" J, e h" o: X' Y: j
- 78 /* Enable the USB clock */( q8 t6 \) c; Y) o
- 79 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);2 E& ~3 x; x/ X
- 80 }
; o7 U4 l# d) ^9 b5 I; U - 81
7 \4 Q4 J/ j' e - 82 /*******************************************************************************
( E/ W' ?$ S7 T* |8 ] - 83 * Function Name : Enter_LowPowerMode
9 X% V& c* `! q5 C0 O0 m2 S - 84 * Description : Power-off system clocks and power while entering suspend mode
4 R2 e0 J( _; B6 s' z5 i" O - 85 * Input : None.: v7 a0 @9 f- s8 }6 b" j5 l
- 86 * Return : None.7 o& U/ L8 _+ ]0 T) _* l7 d
- 87 *******************************************************************************/3 ~: ]; Y3 {) j
- 88 void Enter_LowPowerMode(void)
_# G& H7 q" v0 M - 89 {: F* I# s( }# S6 e$ n" `
- 90 /* Set the device state to suspend */
: K: z0 l/ H6 n5 \, v# k2 } - 91 bDeviceState = SUSPENDED;- c/ i2 u( j8 f0 W! v6 `: ^
- 92 }
3 u2 H% l7 B1 R* h - 93 * t& H0 r$ z( U
- 94 /*******************************************************************************) T* Z x* B3 N0 k/ k; U
- 95 * Function Name : Leave_LowPowerMode
( ~& x9 p1 h5 L1 d7 ?# P - 96 * Description : Restores system clocks and power while exiting suspend mode
+ ^. J+ a+ X% I' s/ N% J/ p" R - 97 * Input : None.3 X: \9 c, {! V7 o
- 98 * Return : None.
( |+ W6 X0 b! {5 i+ `' v% S) H - 99 *******************************************************************************/$ ?6 j* c0 S4 J) z* S) c: K. Q
- 100 void Leave_LowPowerMode(void)
1 C; G# N- z( t4 z5 \3 U( Y - 101 {. K# C5 _% G% V8 J
- 102 DEVICE_INFO *pInfo = &Device_Info;; C8 g. G( G( \) g
- 103
) {' ^: B6 J8 A0 @ - 104 /* Set the device state to the correct state */8 O- ]$ A4 k9 f
- 105 if (pInfo->Current_Configuration != 0)# ^, t5 W$ W7 A+ Q% U
- 106 {
! b6 c+ v& s) H* R3 G - 107 /* Device configured */
0 H( e1 O3 l/ {" |6 i! g& J - 108 bDeviceState = CONFIGURED;! K" b. o. N9 \$ c0 x
- 109 }
% V9 n$ l3 K- g2 i5 F7 Y3 O* C- m - 110 else: a5 Y" T8 G% k. l$ G, @4 `
- 111 {# B4 R# R2 D% j- b
- 112 bDeviceState = ATTACHED;
2 r' Z1 b% R6 N8 e/ ~ - 113 }
/ B1 p" L# S5 X" s- b/ |9 Z - 114 /*Enable SystemCoreClock*/
# z# y; j, p z7 w: G$ l# I8 y - 115 // SystemInit();
/ C- }; u; S* P& V. i. C - 116 }5 s) q9 T2 Q. }; k
- 117 `' V+ e+ D1 D) i( v; m* \
- 118 /*******************************************************************************
9 G6 I' t5 B4 @; R+ { - 119 * Function Name : USB_Interrupts_Config1 \) N1 |3 _/ I5 ~7 i
- 120 * Description : Configures the USB interrupts
) b- |# O( r* w7 }; O: r - 121 * Input : None.: K6 ~" b8 D P. ^3 g+ U! @
- 122 * Return : None.
3 l' X4 o( e g: m5 j. P1 e# Y - 123 *******************************************************************************/
! c5 q+ D# {' i/ H. \ - 124 void USB_Interrupts_Config(void)
& s1 W: I4 y# X6 t! z3 I - 125 {! ?4 U4 z. S, E; ] \: v/ _
- 126 NVIC_InitTypeDef NVIC_InitStructure; 7 R( n, J1 T+ v) ^
- 127
y" ]; z' p3 ^2 A7 c - 128 NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;, ^+ F. M% q! u7 \9 q$ u* @
- 129 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
6 T C5 M* d* g8 Z8 x6 {2 U - 130 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
$ l, a( F% m- | - 131 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
# A$ `, L( D5 I2 ` g* R% S - 132 NVIC_Init(&NVIC_InitStructure);: U5 F2 c0 W0 r
- 133 $ h6 P5 h9 l4 g0 n8 r6 z+ X
- 134 /* Enable the USB Wake-up interrupt */1 x" U" M" Q$ X* C& i6 p
- 135 NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
" D Y) C" R* z: J - 136 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
' ` E8 t5 W0 m$ n - 137 NVIC_Init(&NVIC_InitStructure);; @# N' ]1 ?: N. m
- 138 }
# [% i9 i; D8 c v8 V - 139
: I+ y6 J: J" y' T; E* g& A - 140 /******************************************************************************* T* J5 j) ]; X$ j9 p. C, x
- 141 * Function Name : USB_Cable_Config
\) m' D5 ]+ \3 F$ k) L - 142 * Description : Software Connection/Disconnection of USB Cable9 \1 c1 } m* m8 Y. T6 n
- 143 * Input : None.9 n/ U0 e1 z& J0 s- I7 J
- 144 * Return : Status+ ?. F2 r3 ?: p" m0 p
- 145 *******************************************************************************/
3 d3 W) |& {8 P3 c l1 s - 146 void USB_Cable_Config (FunctionalState NewState)
' \/ T5 a0 f* Q - 147 {
9 ^+ C/ g9 z* g q: f/ u - 148 if (NewState == DISABLE)
$ A. v5 L" m5 P - 149 {0 s% Z7 M" `$ v% d
- 150 GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
5 w3 ?6 D6 R* ` - 151 }5 e$ w' X5 m$ a( O5 d
- 152 else; X; u0 Y5 S( h7 O& H
- 153 {8 [7 R9 c! F, i
- 154 GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
, r8 m& R) ~' r( Z+ ^ - 155 }2 P3 u) \0 C( _* V7 c
- 156 }" n* ~8 i. X' i5 ]- l+ i
- 157 : I+ ]8 m! C8 g7 Z1 Z
- 158 /*******************************************************************************
5 G+ |5 d) V9 r K4 w- x2 a - 159 * Function Name : void USB_Config(void)/ p6 L* }, e- X* C
- 160 * Description : USB系统初始化
4 d1 }% I1 K: ]3 B - 161 * Input : * i8 R X2 A: E; L4 H" [. Y4 k
- 162 * Output :
K* r, U1 F4 t# c9 f; } - 163 * Other :
; I* e0 @" L) D" R+ p' M - 164 * Date : 2014.11.285 O# e' v* V2 {& A
- 165 *******************************************************************************/
/ k1 E- i+ X, ? - 166 void USB_Config(void)
0 z& U; ?, I3 K" ?' c0 k+ ` - 167 {
4 z3 i5 [/ g, Q - 168 Set_System();3 q/ @! ` M4 W5 n
- 169 " U! x% o( \! V$ ~4 ~
- 170 Set_USBClock();
4 |: q# R/ q9 }4 ~ - 171
; V6 E8 V" g) B+ S - 172 USB_Interrupts_Config();% M1 j$ \& Z; t6 y/ e! T5 x# v: \
- 173
3 m3 v% \) E2 W0 r- U - 174 USB_Init();3 `5 O0 x( C4 C) f$ v
- 175 }
( S: ]5 G( @. x' \. l6 K0 w; X - 176 ' a1 n' x4 s3 w8 A8 w2 @
- 177 /*******************************************************************************- V$ [: j. ^3 j, x, h
- 178 * Function Name : uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)% I; T) l, C1 A( i H( d7 m: ~2 x
- 179 * Description : 从USB接收缓存中读数据, W; W+ i3 U* u1 L3 A9 D
- 180 * Input : & S! A1 {% }+ l5 J
- 181 * Output : : o; L8 ?& @( I! f
- 182 * Other : : V* k5 I$ T& F7 ^3 C4 ]5 k
- 183 * Date : 2014.11.28
( I' a2 c- M- m2 \4 l' `3 r - 184 *******************************************************************************/* c$ q! l0 Q* t$ |0 i- a C6 p
- 185 uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)
) k) w" j' y: X8 o - 186 {* P: r+ Z/ g2 P" x5 {$ q- J
- 187 return QUEUE_PacketOut(&m_QueueUsbComRx, buffter, buffterSize);
I( O* U C2 @" j/ G - 188 }
' U0 {9 [! m0 F - 189 /*******************************************************************************. v6 n# e" h( a& K: K! W
- 190 * Function Name : uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
- ^, c. |2 k7 g - 191 * Description : 写数据到USB接收缓存中
, U$ W* a% ?5 ]' Y& Q; N+ Q7 k - 192 * Input : ( r& n% j- ]+ N. H( J
- 193 * Output : $ F, O1 `8 v9 b3 ?2 `4 u6 e
- 194 * Other : % W9 U5 q0 Z \. |1 L5 U2 K9 K9 A5 H
- 195 * Date : 2014.11.28
' D0 G0 c; S+ r5 g" B - 196 *******************************************************************************/
" b2 U. {9 |0 N) l - 197 uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
4 ?% [% @$ E) t. x+ E! U8 s5 g) s - 198 {* a4 {% o5 M+ z5 ~6 y+ L5 E' p/ e
- 199 return QUEUE_PacketIn(&m_QueueUsbComRx, buffter, writeLen);
8 V: `- E2 o ~2 a( @! S5 P5 {4 Q - 200 }
+ W4 Y) [% H4 a V) V! K: ~: \3 }$ F - 201 /*******************************************************************************1 T! e: N% }" d) a
- 202 * Function Name : uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)% Q: ?# M! u2 l/ N1 J# `$ j* B
- 203 * Description : 从USB发送缓存中读数据
1 W: A9 Y( _$ S6 ~% R2 |) D - 204 * Input :
) K" _7 a+ c% ^9 G( s - 205 * Output :
8 ]! p* Y: N' H4 E: w - 206 * Other :
/ d' q! Y& N& ^2 h1 T - 207 * Date : 2014.11.28
( i0 S8 f" c7 z' f+ H+ h - 208 *******************************************************************************/
6 A, X% i0 T2 j3 j - 209 uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)7 X! d, v, z" m( }9 g6 ~
- 210 {* u/ a% i9 r u1 j/ i: ]+ S
- 211 return QUEUE_PacketOut(&m_QueueUsbComTx, buffter, buffterSize);;
& L- J2 x3 u9 E! ]: f - 212 }# Y" O+ E9 S5 H2 {
- 213 /*******************************************************************************
+ k4 r) w6 D* l) c2 S# t/ z - 214 * Function Name : uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen)2 @: h9 f( y+ U [* i( Z# u- R
- 215 * Description : 写数据到USB发送缓存中
' Y+ j- p) L/ z' e' i# t. j - 216 * Input :
J+ h% \" O1 c, a% n8 R0 r! K - 217 * Output : 2 ?+ B) n/ R) V$ ^2 p3 `
- 218 * Other : - w4 V! r3 b' l S4 O6 J
- 219 * Date : 2014.11.28
; l4 X6 e! |0 C# v, [& o; L - 220 *******************************************************************************/. H9 B i6 ^- K) a. u
- 221 uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen) U4 o% ], m/ ^% O9 J" [
- 222 {3 w% j8 ^# C" M ^
- 223 return QUEUE_PacketIn(&m_QueueUsbComTx, buffter, writeLen);' t& P: k u$ R: N
- 224 }- X: I5 ^+ M) d, Q
- 225 1 l0 x" e' e$ `, \9 z* f
- 226 ( c) y( ?( Q: {" j% a1 n4 @7 D. a
- 227 " u& r+ {, p" J! y; P3 Y- n% e0 |
- 228 /*******************************************************************************; H$ A+ V1 X8 K* R6 A6 j
- 229 * Function Name : Get_SerialNum.
6 ]- X0 l! z- d* A V# O - 230 * Description : Create the serial number string descriptor.
1 h9 r9 M/ p5 u. z" f+ Y - 231 * Input : None.
3 y- h6 J4 L" I* f6 K8 I - 232 * Output : None.9 S8 K% k7 M# [. n: A# M
- 233 * Return : None.% n! E: _- \) j6 ^7 n
- 234 *******************************************************************************/
! b* ^; b8 S+ f2 U: J0 C& r" X7 U - 235 void Get_SerialNum(void)* R: G- U9 \4 d2 t v* g* Z/ s7 h2 x
- 236 {
9 k/ Z3 h! w( d4 a - 237 uint32_t Device_Serial0, Device_Serial1, Device_Serial2;) H0 P3 z g. z4 c4 x7 b8 i
- 238 ' @7 M" W& k. u0 ?6 @
- 239 Device_Serial0 = *(uint32_t*)ID1;
' j# m3 f& y A* p- y - 240 Device_Serial1 = *(uint32_t*)ID2;) @) P) o& x9 O! o1 a/ ?
- 241 Device_Serial2 = *(uint32_t*)ID3;
! q, V5 d; Z0 ]4 C - 242 7 L% }% o' I2 @- T5 V
- 243 Device_Serial0 += Device_Serial2;
& @3 F# V. F: ^; ?$ p6 b& x - 244 ( t" j2 Y" h6 v# ?3 F
- 245 if (Device_Serial0 != 0)3 z' f1 T' m2 k+ S* {$ _! y( c8 h
- 246 {& @+ |4 J: O4 M4 S8 m8 Z2 z s
- 247 IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8);
" D r* _8 A/ O9 c0 `5 {+ W) i - 248 IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4);% P" _$ k$ p/ \3 y9 t( K
- 249 }: R( D [. V, {. b% a2 t+ R7 i& w2 d
- 250 }
# [. b; I* C9 `: X: m6 K! q - 251
4 U6 a/ Y, _* L/ i) a( p/ i7 I - 252 /*******************************************************************************1 H T2 S2 e( F+ l* C; K
- 253 * Function Name : HexToChar.) C/ \2 T! i9 w ?& l$ \( v
- 254 * Description : Convert Hex 32Bits value into char." g& b' k) [! ^
- 255 * Input : None.9 ] [* }" z+ m
- 256 * Output : None.$ w: I" u& N c$ ]; x* A/ J
- 257 * Return : None.* ?4 P! V9 `/ z" z5 D, H
- 258 *******************************************************************************/# {0 R; H; i' N8 j% E: |6 g6 s# D
- 259 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)! S' g9 K; S- \. h! c8 f
- 260 {
# z% }1 B+ u1 W4 y' E( L$ ] - 261 uint8_t idx = 0;! x- S6 N8 o% {5 Z9 _
- 262
* y. L+ ?$ z X$ @ - 263 for( idx = 0 ; idx < len ; idx ++)
! y% T$ Z% C- s% B; a - 264 {; c$ H% ?' Q2 d+ u
- 265 if( ((value >> 28)) < 0xA )
+ P4 _1 x* i+ S+ G/ J; M) D2 h% b - 266 {" ?9 |$ [: Q6 X) `5 C5 G
- 267 pbuf[ 2* idx] = (value >> 28) + '0';4 K" @" f- R, ]0 [* I& e# p# s3 w5 _
- 268 }+ X! e5 d8 h( s% s9 r% E7 R
- 269 else% o- q5 R' w. ?$ n% n
- 270 {
7 c! f6 w6 O3 c; J - 271 pbuf[2* idx] = (value >> 28) + 'A' - 10; ! y% j2 J7 l: y8 R, e! W
- 272 }
% H2 m. d. i& z+ C - 273 0 ?4 r2 E% t1 R H
- 274 value = value << 4;
2 ~# [' q9 w; {1 U: A% t/ p$ V* e - 275
! Q9 h, {% N3 P, j3 ^ - 276 pbuf[ 2* idx + 1] = 0;
* G7 q$ O9 X! C3 X - 277 }
2 p' _$ ]0 B! D: ]) G) C - 278 }) l; |% S# I5 q: n- M0 I6 p& {
- 279
3 D4 r+ F' E) p+ j3 K - 280 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码 # F- c) ?* k, l/ X' P6 p% U
% X; b. I$ p8 w这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。 图7
. A. M0 h+ ^% s; P* D3 r; W1 z7 }9 P% Q& f7 G
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下: 代码3 - 1 /******************************************************************************* I% D; ]! E5 w4 y% B8 y8 w# W" I5 z, [
- 2 * Function Name : USB_Cable_Config1 C/ u- J3 h9 ~
- 3 * Description : Software Connection/Disconnection of USB Cable: n/ q2 z3 t# e1 c- M
- 4 * Input : None.
3 D) X1 v8 J5 N9 D/ E* Q& E) u; E - 5 * Return : Status2 @1 \& p$ Z% {+ ]2 V( g
- 6 *******************************************************************************/
1 ^# M0 K5 t/ {! N" J0 g - 7 void USB_Cable_Config (FunctionalState NewState)" @% ]: P- \" x/ [. C4 }
- 8 {& [( P( c; ?5 d3 [" _1 [
- 9 if (NewState == DISABLE)
, D9 T [( h: o$ U - 10 {
6 H" Z% B1 L8 ? x/ Y - 11 GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);# g6 P: y0 o. D& Z( B5 l0 }
- 12 }# H, y' r/ J' [
- 13 else& ], W- {) L# S3 S2 |
- 14 {
: V+ B4 ^/ Y' Q9 d' o: V! _0 ?* m - 15 GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
3 I% x2 c& H7 S8 p. V& W; U" | - 16 }" g5 R1 Q" L- g C; p& O
- 17 }
复制代码
; s: a I( M, Z* w3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换: 代码4 - 1 /* Includes ------------------------------------------------------------------*/
, P5 o5 B8 @- e - 2 #include "usb_lib.h"* u$ k, \7 O5 y. n
- 3 #include "usb_desc.h": {" r. W9 |, _, K" B1 n( i K
- 4 #include "usb_mem.h"
! Q4 v7 r: [0 _$ e r6 T( `/ E - 5 #include "hw_config.h"
) x2 Z* }: h, h7 ^4 p - 6 #include "usb_istr.h"" F# p' G: u( g4 A$ h, d( _" [
- 7 #include "usb_pwr.h") x& S7 q% m( [. C0 F3 h$ i
- 8 ) F) f' O) Y3 U' a% f" B5 d
- 9 /* Private typedef -----------------------------------------------------------*/
4 ^- Z- ~4 S1 `* H! h# W - 10 /* Private define ------------------------------------------------------------*/
' W5 t, K& M' D# C" a7 T, y - 11 ( R% y& M/ I. Y
- 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
; S; f( P- B0 c - 13 #define VCOMPORT_IN_FRAME_INTERVAL 5( o6 n6 V4 ?6 q0 U w- S
- 14
& F s( E: \. c$ D' w5 x3 [: r- G - 15 /* Private macro -------------------------------------------------------------*/
! b" M8 {8 E, }- R# j - 16 /* Private variables ---------------------------------------------------------*/
/ W3 [" W" ~3 ]% s8 m: E - 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
6 U6 s$ `* ~: K% _ - 18 static volatile uint8_t txFlg = 0;) Y" |. Y! `4 ~% B# c W) T- o
- 19 static volatile uint32_t FrameCount = 0;- b, Z2 u4 {6 v6 s9 l3 @$ l7 K
- 20
8 H' R( Z3 `+ \8 ]7 l, c7 H - 21
; ?( X7 Y0 k2 A2 U( Q# [ - 22 /* Private function prototypes -----------------------------------------------*/
5 [6 W) j; J' R0 ~ - 23 /* Private functions ---------------------------------------------------------*/1 B* A6 \ [. }
- 24 * ^* D) f5 u/ H0 M
- 25 /*******************************************************************************7 Y* S) k; `" q% n6 n: \ X
- 26 * Function Name : EP1_IN_Callback
% ?$ L: ?3 x+ F# [* x - 27 * Description :* h8 }# C: B" i( V
- 28 * Input : None. ?$ e: a6 l0 b
- 29 * Output : None.
+ `6 n; T% N& l$ M - 30 * Return : None.
6 `# ^# F' N, O) ?1 a/ ? - 31 *******************************************************************************/
0 w3 Z$ T, ]5 \ - 32 void EP1_IN_Callback (void)
5 n" G- N- g3 N2 R - 33 {
( T/ d, {& e( b `- X - 34 uint16_t len = 0;; b) C- g$ F, s M2 }; `, u
- 35 - v" Q4 B) t( [* t; k8 [2 c" Y
- 36 if (1 == txFlg)& L8 J& N$ U( @; l% K: R
- 37 {4 W6 U* _' m# ^8 V
- 38 len = USB_TxRead(txBuffter, sizeof(txBuffter));1 t: E; c1 d. W6 m
- 39 ) ]/ n# l) |4 H; \- X4 d `
- 40 if (len > 0)( f( R3 J$ ^* M# N; n5 ^
- 41 {& F- s( E8 T- x( W3 [
- 42 UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);5 L7 Q' `+ u% K' e0 _
- 43 SetEPTxCount(ENDP1, len);
% r |- E" I% q/ h4 h+ p) s2 h - 44 SetEPTxValid(ENDP1); : U3 X5 p& ~5 c
- 45 FrameCount = 0;
/ H, k5 g/ W. }$ | - 46 }0 N% k y7 B; x$ u9 u, v; D
- 47 else* o- q/ M! q ?5 S @
- 48 {
( |: ~1 Z4 x* s+ S* b2 |) ~3 ? - 49 txFlg = 0;
! Z6 R0 [' T ^0 W- A$ k - 50 }
, o) G% w0 O% Q- Q) H k, _ - 51 }( [; G( c$ L, Z5 N
- 52 }
8 e! e5 _3 ~ J- f0 x - 53
% ^0 p7 t$ p, q7 o' Q9 o5 U: A - 54 /*******************************************************************************
. P3 q" [- ^6 p% A) x - 55 * Function Name : EP3_OUT_Callback: M% J: P2 @' J1 v/ s! B
- 56 * Description :1 Q: B. K' X% X& }: ]# t
- 57 * Input : None.
4 F( o+ d1 Z! x7 L$ Y* |9 L - 58 * Output : None.8 ]6 w! k) F8 {2 S* _5 ?
- 59 * Return : None.5 }" B7 U, ^, ~7 D+ H- g1 T
- 60 *******************************************************************************/
3 {4 P+ Y6 k+ o3 p( Q3 o& S - 61 void EP3_OUT_Callback(void)0 U" g3 ^* }7 a1 X" Q% Q6 L$ }# O
- 62 {
* _- I1 t$ X) R& e5 {6 q - 63 static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
I, ] I z7 F% u+ p - 64
4 I" z- R1 T6 V' R' b" A! z. m - 65 uint16_t USB_Rx_Cnt;7 S; ?2 {/ a! v" {' {% U* U+ g
- 66 " p) k h- c0 ?
- 67 /* Get the received data buffer and update the counter */- a$ ?8 j; |" H4 h- ?* v
- 68 USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);9 J& X% t7 c8 o8 j7 Y1 `% y
- 69 & Y* Y8 U! X- H: P! H1 n
- 70 /* USB data will be immediately processed, this allow next USB traffic being 4 S8 J5 s) u8 L
- 71 NAKed till the end of the USART Xfer */
5 S; ~5 Q% ~9 v% H6 Z( R* M4 _( N - 72 USB_RxWrite(buffter, USB_Rx_Cnt);
6 Y* D) F9 a: |6 Y - 73
# T/ ?4 w2 g, Q# P) r - 74 /* Enable the receive of data on EP3 */
1 k; L) v2 t4 d8 A. d$ b - 75 SetEPRxValid(ENDP3);
* H! |- C8 M7 ?# b - 76
5 X, ^1 R& w! ?% H/ o - 77 }3 ]" c; R6 i! B0 g- J7 v" `
- 78 5 s" i- I7 |; X# E" d) _4 ~
- 79 0 N: v& [6 _- L6 t( @7 {$ X
- 80 /*******************************************************************************
$ n( U: |. z" Q. y+ y: E - 81 * Function Name : SOF_Callback / INTR_SOFINTR_Callback
9 v- p( ]( p9 z; I% E2 l% M - 82 * Description :
( R% f6 z+ g8 ^2 E - 83 * Input : None.
$ m9 N, J+ E g+ W; h& ] - 84 * Output : None.6 ?5 x* I, e% |0 u/ _. I
- 85 * Return : None.2 q* ^& I4 y0 L7 h
- 86 *******************************************************************************/9 q' b; a( x% I3 W
- 87 void SOF_Callback(void)
* n3 i) N, [2 Y! t - 88 {) i A; X' f/ S( Y4 z/ v3 ]' f
- 89 uint16_t len = 0;
/ ^9 A* _6 j" I5 J3 T' v- O! o - 90
0 z' b" `: w5 t" i% d - 91 if(bDeviceState == CONFIGURED)+ s: ^& l. {* F
- 92 {
" o" K. o$ l) f+ F0 l' r9 N - 93 if (0 == txFlg)0 O$ I6 l- C i6 O8 l
- 94 {; n8 b$ o" `" ~0 e3 n8 J' U
- 95 if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
! U$ d2 S- G; `0 [ - 96 {
" t" [* }2 \/ A/ H1 ^# w - 97 /* Reset the frame counter */
1 i- B0 e1 c1 d. q i- C - 98 FrameCount = 0; y) S* ], D% h. I. [; j
- 99 6 d8 C( C f8 w( u! p; f: `
- 100 /* Check the data to be sent through IN pipe */
# ~8 M" v. _- s$ Y6 @' R - 101 len = USB_TxRead(txBuffter, sizeof(txBuffter));
: Q* f: ` i! b) Y- ~$ ^ - 102 ' {( H6 f& M' I: D
- 103 if (len > 0)
; K0 ?. E! @( ]1 i - 104 {
1 j0 j. U# z2 ^- D. g: e+ O% @ - 105 UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);6 A! B( z" w& ]% r. R, I& q
- 106 SetEPTxCount(ENDP1, len);
. d3 F1 `0 C) {% g+ g8 C - 107 SetEPTxValid(ENDP1);
/ r b/ ^' b5 m/ d& a- N - 108
7 s2 ^3 D: a6 }: V" ^/ g! O" T - 109 txFlg = 1;+ {/ T4 N) D: `% {$ Q
- 110 }* H0 L$ [. U: q, `
- 111 }
5 P o3 d5 d+ z. l2 u! I - 112 }# i y4 N9 u& c5 a
- 113 }
" |5 \3 j3 J3 N - 114 }% r* u- v, S j- S" F* r; X
- 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
. E7 j1 m- v2 e" l# C/ A$ t ^* k8 Z" d8 J9 ~
这里讲下大概意思,函数EP3_OUT_Callback是在USB口收到数据后,将数据存入FIFO中。 函数SOF_Callback定时查询用户是否有要发送的数据,如果有则进行发送,在发送完成后会触发发送中断EP1_IN_Callback函数,如果发送完毕就不调用SetEPTxValid(ENDP1)函数,发送完成后就不会再触发EP1_IN_Callback函数。 4,修改usb_pwr.c在前文中说到:不让系统进入休眠状态,这里屏蔽185行 __WFI(); 5,修改usb_prop.c屏蔽COM初始化代码。137行USART_Config_Default(); 237行USART_Config(); 6,修改usb_desc.c 这里修改需要参考一些USB专业的书籍,推荐全圈圈的书,讲的通俗易懂。关于本程序的驱动,笔者在win7下测试可以自动安装,如果无法自动安装可使用文章开始的链接中的驱动程序。本文件如果修改需谨慎,其中pid,vid是制造商ID和产品编号,如果修改了那驱动也要对应修改,官方驱动就无法自动进行安装了。 到这里移植就差不多完成了,下面进行测试。由于USB虚拟串口不受波特率限制,所以笔者进行过50k/s的压力测试,运行半小时未丢1个字节。 移植好的工程STM32_UsbVirtualCom.rar也一起存放在上文章开始的链接中。
/ K) B2 V5 _ g, n1 L0 d |