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