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