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