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