|
在研究STM32串口接收发送中断的时候找到不少不错的资料,现在备份在这里。以供自己查阅,以及方便其他人。 TC ====TXE 顺便预告下最近会写个有关串口处理数据的帖子,从查询和中断方面以及数据处理的方式,从队列以及FIFO方面写起。 , I' m5 r! C9 l# F( u* m; `8 m& q. n
SECTION 1 - /*
5 q$ Y) H; d6 ~8 _ - 调试STM32串口过程中发现一个奇怪的问题,初始化串口1口,使能串口发送完成中断后,立刻就进入了发送完成中断。1 F. @, ~4 |0 V4 k0 u1 R5 E
- 仔细的查阅了STM32手册中的串口部分的介绍:
" t5 Z ?) i& b2 Z& T* Z) A - ) Z1 Q0 v3 s1 Y7 D
- 以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。$ ?& r. i8 [9 ~1 a0 @! J
-
: p& m0 ]( k. a! q2 O6 r - 配置步骤:
+ z) P4 u: o& Z4 H - 1. 通过在USART_CR1寄存器上置位UE位来激活USART: `, \4 }: V& z; {2 p' O0 C
- 2. 编程USART_CR1的M位来定义字长。
( e" Q/ a% d9 ~2 J8 W: e - 3. 在USART_CR2中编程停止位的位数。8 i5 k' p5 }) F, q
- 4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中5 l. ?8 w7 L8 A K% ]3 c+ v" u
- 的描述配置DMA寄存器。
& ?" Z& l8 S) `3 R - 5. 利用USART_BRR寄存器选择要求的波特率。
8 A5 m5 g, L" X4 \# f: v1 l( ^+ | - 6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。
# `# ]8 m U, a/ |( Z0 m - 7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况
0 q5 w- N8 o6 j( l - 下,对每个待发送的数据重复步骤7。
" K* u1 W" ^( x$ l( l! @ - 8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的
3 T* N5 W0 U" d3 S( w# J* a; N# w - 传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏+ A/ ^. u+ k% w+ n" H+ ^
- 最后一次传输。. ?4 X+ f8 c6 i1 Z3 Q |" C
- */0 ^' X3 Q. o- x: i0 K
- //解决的办法:
5 w% K- ?: @( h4 F: p4 f o - //方法一% \6 q( k% H8 X# J! a. E* Y" G- p
- //在执行
" ?3 V% r9 }8 @7 L- } - USART_ITConfig(USART1, USART_IT_TC, ENABLE); + i5 `8 D9 I2 v1 w
- //之前,先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行
# c; U3 }$ A# ` z: s0 ^- k8 [ - USART_ClearFlag(USART1, USART_FLAG_TC);' i! S$ N) y: t& q: n: N
- % t% i5 h* A3 g& T4 ^. O. s
- //方法二:
* F7 Z" g6 A! M7 o - //在执行6 r) P7 k$ W* H
- USART_ITConfig(USART1, USART_IT_TC, ENABLE);$ H3 r' g5 P z! t2 n
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); z/ A- |2 p8 Y6 E- C4 t8 @* r8 H
- {
9 c6 [: ]# I+ X. x! L - ; //等待空闲帧发送完成后 再清零发送标志% z' U) t6 }9 a c9 v" L
- }
7 d0 Z$ [5 I. b" w- Q - USART_ClearFlag(USART1,USART_FLAG_TC);
复制代码 ) F$ o1 e. \/ l: v
3 H% a i0 q/ @* o
SECTION 2
; N5 a( `- j3 n* L8 B+ F0 K7 P9 o* [先说TC。即Transmission Complete。发送一个字节后才进入中断,这里称为“发送后中断”。和原来8051的TI方式一样,都是发送后才进中断,需要在发送函数中先发送一个字节触发中断。发送函数如下 6 u" J/ k# [8 S
; k8 O5 V3 ]& p, D. |- /*******. S0 z) V- V5 C* ~- Y
- 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.
, k. S: [# N& z - 输入:字符串的首地址
u& P' n" x( j7 A) d7 C5 y, M - 输出:无
2 c2 w6 [$ y+ f5 F- V" G6 Z - *******/
; y! C2 V% b0 P( C6 z4 } - void USART_SendDataString( u8 *pData )0 P j6 n! {2 m# N
- {
8 ?, C* z, T; y8 q5 O& `6 U- E5 p - pDataByte = pData;" P! d- m B& @) J9 Y
-
. o" S# k" U3 ~+ ` - USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.
: a& K# q( x+ B& Q; v1 u/ ~ - - \ L' \, I8 a3 y5 b/ g
- USART_SendData(USART1, *(pDataByte++) ); //必须要++,不然会把第一个字符t发送两次
2 F3 r7 a, o6 |$ ` - }
复制代码
+ ^5 O- P- o7 i中断处理函数如下
! A. G9 B* K1 Z. C3 t- /********
5 C& Y3 x, t' O+ U - * Function Name : USART1_IRQHandler& T% w1 L+ I6 Y( r, d- x5 {) i
- * Description : This function handles USART1 global interrupt request.0 V9 D9 G+ F- q" |. y
- * Input : None
; ~$ f' v8 y6 X6 ]$ Y" u - * Output : None4 ]$ }2 v8 `9 a; Z" X w( v: g
- * Return : None
' ?- C: r, k' o( {; r - *********/
* H) Q0 x- a+ ^ - void USART1_IRQHandler(void)
$ | `, n: y0 f2 C1 X: w. o" w - {
& M6 m* ?- o' e# G* B. J% \$ T4 f - if( USART_GetITStatus(USART1, USART_IT_TC) == SET )
$ Y6 a5 ?% f1 v6 ] - {
5 F& |& ?. [1 B5 D - if( *pDataByte == '\0' )//TC需要 读SR+写DR 方可清0,当发送到最后,到'\0'的时候用个if判断关掉; P+ i# O2 Z, c% ~4 \
- USART_ClearFlag(USART1, USART_FLAG_TC);//不然TC一直是set, TCIE也是打开的,导致会不停进入中断. clear掉即可,不用关掉TCIE. ~5 G4 x) F. E! {
- else
0 |8 A) U+ w$ P* a - USART_SendData(USART1, *pDataByte++ );
, {5 M! l$ @5 L8 D8 y# Z2 H - }
9 ~6 L( I1 L7 R% j - # i/ K6 \' ^/ P- T# ] n
- }
复制代码
2 t% u- e7 |! b7 p其中u8 *pDataByte;是一个外部指针变量 , j/ E, J7 }5 B6 a5 u& s1 ~) u
0 O7 z" I4 s" i6 _8 Y
在中断处理程序中,发送完该字符串后,不用关闭TC的中断使能TCIE,只需要清掉标志位TC;这样就能避免TC == SET 导致反复进入中断了。
$ x; h) {: s* r; m1 s0 Z5 w- U; B串口初始化函数如下 ; `. |2 u4 ^6 s+ C7 I
* v, w* e5 Q) Y0 O& u- /*********
3 i$ i+ c; f9 f - 名称: USART_Config" k5 ?3 q5 d$ _( F% G' j Y
- 功能: 设置串口参数
; l/ f# g6 _- |" c" P. e5 U6 B& F/ q - 输入: 无( _+ s/ ^% G" y; G3 o
- 输出: 无
" b& P- _$ V: T. Y4 R* z7 H - 返回: 无
: k T5 @( W- J$ Q4 h+ y - **********/! V4 U1 b$ F/ b0 ?! W! a
- void USART_Config()
0 t% v: F5 M! J( I2 W1 d0 b - {$ Y, g ?: b( F; G+ ^
- USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体
7 h$ {! I' y' i - 0 h5 F, b X# v0 v! E# m- }; u# ` V
- USART_InitStructure.USART_BaudRate = 9600; //波特率9600; A* d+ _) p& ?* B
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位7 k) U' N0 C* m# a# t% I
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
: U9 t) m) x) d - USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
: m! R1 |1 w/ V - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
/ w/ {- p0 K+ E+ w - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式! p% p; x( c" g+ P& K$ N
- USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭
$ [6 l: w6 V/ c+ E- W+ g - USART_InitStructure.USART_CPOL = USART_CPOL_Low;" ]2 b3 E; E% V, C. V
- USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;
9 l1 Q& u$ A% j' [$ u) Q7 h2 ~% N - USART_InitStructure.USART_LastBit = USART_LastBit_Disable;9 n; p1 N. [( y' ]2 S9 ?% s+ X
- USART_Init(USART1, &USART_InitStructure);//设置到USART1
2 C3 X7 b- m9 J- Y# i A1 d4 E -
A5 j# D9 r# \) S - USART_ITConfig(USART1, USART_IT_TC, ENABLE);//Tramsimssion Complete后,才产生中断. 开TC中断必须放在这里,否则还是会丢失第一字节( t' k2 m( j$ h3 A: B; p
- : I5 [7 E, q) ^* U! G" N% c9 m
- USART_Cmd(USART1, ENABLE); //使能USART1, r) U3 U: _1 }' ^/ G/ u" o
- }
复制代码 5 Z; r- i+ s) V
这里请问一个问题:开TC中断USART_ITConfig()如果放在我的USART_SendDataString()中再开,会丢失字符串的第一字节。必须放在串口初始化函数中才不会丢。不知道为什么?? % E, d& `5 S+ M4 G7 W0 B; T! A' Z
这里笔者可以给出解释,你看下SECTION1 就可以知道为什么呢,你这样做的原理和SECTION1讲解的差不多,就相当于延时,而你后面没有丢失数据的主要原因就是你代码中有这么一句 USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供. & ]0 T \% n3 G& y
0 v6 t# l! k( ~/ Y; m
再说判断TXE。即Tx DR Empty,发送寄存器空。当使能TXEIE后,只要Tx DR空了,就会产生中断。所以,发送完字符串后必须关掉,否则会导致重复进入中断。这也是和TC不同之处。
: b0 w& S/ Z: {- M( P# ^- B, |2 k5 E$ s& B
发送函数如下:
: p8 ~' k, z2 Y4 F) O- /*******
1 x8 P* U: G4 }5 p3 n; s/ j4 R5 m - 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.
/ @* v: W4 D' C% q [6 S8 Z3 { - 输入:字符串的首地址
! g( p% ^* k3 m, } [1 x! ? - 输出:无4 q4 c; Q9 N+ ?' U0 C8 C9 l1 j
- *******/
+ s% k! o7 x! s' N$ F - void USART_SendDataString( u8 *pData )
. @7 M! A- l2 t- O - {+ T8 t' k7 s) F4 Y9 l
- pDataByte = pData;
2 P" b) j" L# V5 Z* ? - USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。 0 g% l, v# r0 A- U; `/ @; [/ w
- . d1 w- h5 L; C8 D8 ` z0 M
- }) R- M4 p [1 Y9 P
复制代码 * N5 O! w) V: p6 D$ R* {& U
中断处理函数如下:
, \! D" P) E3 V* F" o1 o% n& d9 U2 P% u$ n3 U9 e& ~- I
- /********4 N/ }' i2 w3 d" p( K- o
- * Function Name : USART1_IRQHandler
4 S2 { g f" B ~0 j - * Description : This function handles USART1 global interrupt request.+ y: u1 t) s0 J3 \
- * Input : None
: L% k- U' y2 [5 `1 h - * Output : None
- x% w' N/ i* h9 o1 o9 o7 | - * Return : None
5 |- m3 C8 P2 _) ~$ e - ********/
0 d1 h1 ^1 X! A! @: A - void USART1_IRQHandler(void)" V: ?) P1 Q5 B+ m3 W
- {) v# m$ t5 k$ `2 w6 d8 k
- if( USART_GetITStatus(USART1, USART_IT_TXE) == SET )
# V: W" O: e9 x' f1 v - {" V9 c9 E( n" ^# [# l+ |, G
- if( *pDataByte == '\0' )//待发送的字节发到末尾NULL了
X- ?$ b. A: ? - USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//因为是 发送寄存器空 的中断,所以发完字符串后必须关掉,否则只要空了,就会进中断5 W# T s& n6 {% o; f$ H
- else' C( C" n( y2 B% R. w" P6 {
- USART_SendData(USART1, *pDataByte++ );$ E4 O* o$ g6 ]0 x
- }+ @# G q. B! i5 G
( O5 l+ V1 ~$ j- f4 `/ T5 Q" M- }
复制代码
4 n, Z, p) Y$ `在串口初始化函数中就不用打开TXE的中断了(是在发送函数中打开的)如下:
% z2 n$ M. Z4 M3 e6 c0 A. m- /************0 }4 w6 m* O8 T
- 名称: USART_Config
% D( ^! A' n4 ~$ D. b+ b+ x. [ - 功能: 设置串口参数, d3 N6 e' R2 A; }8 J: x( s. u
- 输入: 无
+ n1 A3 a; b+ p9 b - 输出: 无' y/ N) S& @7 z, g/ t' j# }) c3 ]. p
- 返回: 无4 w+ A; Q. I# D L9 g0 V
- ************/. @# L, K4 H' Y0 _" {3 @
- void USART_Config()) H, l% N' _, |- i% n; Y" J4 T
- {: u/ s! e4 p2 E+ Z* O. O5 {9 J5 W
- USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体# o3 _6 Z2 D1 A% _8 ~, H
- * l* ]6 C3 F5 s
- USART_InitStructure.USART_BaudRate = 9600; //波特率96000 M2 T( {, G9 L7 z
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
f: q A. ?1 @5 D - USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
- H( s' ^2 U, i# T" I. T4 z - USART_InitStructure.USART_Parity = USART_Parity_No;//无校验! H1 \9 e1 l' O
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制 g/ v) b6 i, P5 Q) \" }7 S: C/ c
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式
1 D; @* j2 s/ ^0 {! Y9 O6 O - USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭
& J ]3 v+ m, r0 c - USART_InitStructure.USART_CPOL = USART_CPOL_Low;1 o9 X/ @. I& n" S8 x
- USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;
" z6 y. k9 t, {) q( K) a. | - USART_InitStructure.USART_LastBit = USART_LastBit_Disable;2 {. e2 u& i P" f; J$ p3 f
5 ]- X/ [# U0 c+ M. n9 T* V- USART_Init(USART1, &USART_InitStructure);//设置到USART13 y1 f( n9 U# O. z/ w# t
-
' j/ y* G8 ]; ^. Q - USART_Cmd(USART1, ENABLE); //使能USART1
) X8 w/ t. l0 s- J9 _ - <div align="left">}</div>
复制代码
7 O8 R, M. w3 ]( \+ F8 D4 lSECTION 3
3 E9 }" }9 t# R+ {3 o5 U
2 p4 g" S9 s% N2 M/ E在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register)。
7 N3 w# C* V9 o
- _) m: z" l" Z1 {3 X对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束;对照下图,当TDR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。" d) C8 z7 S% y4 h1 [
- a/ }" h% P$ M( h8 g$ Y: X* q另一方面,在刚刚初始化好USART还没有发送任何数据时,也会有TXE标志,因为这时发送数据寄存器是空的。
$ u0 y/ a7 V2 ~/ D( R3 [0 F' j1 o, b3 T
TXEIE和TCIE的意义很简单,TXEIE允许在TXE标志为'1'时产生中断,而TCIE允许在TC标志为'1'时产生中断。
# S( K) t. }' W7 B o! p3 W: B- z
, i; _0 ` p$ Z% C8 F& \. Z至于什么时候使用哪个标志,需要根据你的需要自己决定。但我认为TXE允许程序有更充裕的时间填写TDR寄存器,保证发送的数据流不间断。TC可以让程序知道发送结束的确切时间,有利于程序控制外部数据流的时序。 & L& T- \3 |- w- \/ O
SECTION 4 总的来说,STM32单片机的串口还是很好理解的,编程也不算复杂。当然我更愿意希望其中断系统和51单片机一样的简单。 对于接收终端,就是RXNE了,这只在接收完成后才产生,在执行USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)代码时不会进入ISR。但麻烦的就是发送有关的中断了:TXE或者TC,根据资料和测试的结果,TXE在复位后就是置1的,即在执行USART_ITConfig(USART1, USART_IT_TXE, ENABLE)后会立即产生中断请求。因此这造成一个麻烦的问题:如果没有真正的发送数据,TXE中断都会发生,而且没有休止,这将占用很大部分的CPU时间,甚至影响其他程序的运行! 因此建议的是在初始化时不好启用TXE中断,只在要发送数据(尤其是字符串、数组这样的系列数据)时才启用TXE。在发送完成后立即将其关闭,以免引起不必要的麻烦。 对于发送,需要注意TXE和TC的差别——这里简单描述一下,假设串口数据寄存器是DR、串口移位寄存器是SR以及TXD引脚TXDpin,其关系是DR->SR->TXDpin。当DR中的数据转移到SR中时TXE置1,如果有数据写入DR时就能将TXE置0;如果SR中的数据全部通过TXDpin移出并且没有数据进入DR,则TC置1。并且需要注意TXE只能通过写DR来置0,不能直接将其清零,而TC可以直接将其写1清零。 对于发送单个字符可以考虑不用中断,直接以查询方式完成。 对于发送字符串/数组类的数据,唯一要考虑的是只在最后一个字符发送后关闭发送中断,这里可以分为两种情况:对于发送可显示的字符串,其用0x00作为结尾的,因此在ISR中就用0x00作为关闭发送中断(TXE或者TC)的条件;第二种情况就是发送二进制数据,那就是0x00~0xFF中间的任意数据,就不能用0x00来判断结束了,这时必须知道数据的具体长度。 这里简单分析上面代码的执行过程:TXE中断产生于前一个字符从DR送入SR,执行效果是后一个字符送入DR。对于第一种情况,如果是可显示字符,就执行USART_SendData来写DR(也就清零了TXE),当最后一个可显示的字符从DR送入SR之后,产生的TXE中断发现要送入DR的是字符是0x00——这当然不行——此时就关闭TXE中断,字符串发送过程就算结束了。当然这时不能忽略一个隐含的结果:那就是最后一个可显示字符从DR转入SR后TXE是置1的,但关闭了TXE中断,因此只要下次再开启TXE中断就会立即进入ISR。对于第二种情况,其结果和第一种的相同。 对于第一种情况,其程序可以这么写:其中TXS是保存了要发送数据的字符串,TxCounter1是索引值: - <div align="left">extern __IO uint8_t TxCounter1;) O7 T% ^: J! Y* j; Q$ U
- extern uint8_t *TXS;; c# D' P) Y4 g1 [5 U
- extern __IO uint8_t TxLen; </div><div align="left">void USART1_IRQHandler(void)
/ q9 f2 b& h6 g( l. `' g/ q, q - {
6 v- \0 v" v- t - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)8 G& x2 _( v1 }5 [" z& K
- { # [, Q6 Z1 g9 u. H1 |7 v
- if(TXS[TxCounter1]) //如果是可显示字符
6 t+ y' u' p% T: }0 N* k$ z - { USART_SendData(USART1,TXS[TxCounter1++]);}+ c( n. j0 X! u4 O# ]1 v
- else //发送完成后关闭TXE中断,. r; Z$ m7 M, g {4 }
- { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
0 @, z% X& |2 G. f - }
! }( z* X- U* C5 z) e0 C! P3 r - }</div><div align="left"> 对于第二种情况,和上面的大同小异,其中TXLen表示要发送的二进制数据长度:</div><div align="left">void USART1_IRQHandler(void)
+ V' Q2 L1 h, r9 h. D8 m# {% H, @ - {
) N. a2 _' d8 O! P+ E; b8 q+ _! P - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //对USART_DR的写操作,将该位清零。# Y) q- y# E, c n
- { h% |# @% w' V1 _4 m, {* I0 C
- if(TxCounter1<TxLen)# \* {+ x. Y; Q0 G0 J! G4 n
- { USART_SendData(USART1,TXS[TxCounter1++]);}
. h9 i0 r+ | |% M1 w - else //发送完成后关闭TXE中断
! a4 v. Q. f& K - { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);} * j, r) r+ F" ]; k$ c
- }
* J* y4 s D! A/ V - }</div>
复制代码 ( x. Z2 R3 u T D0 I$ B
事实上第一种情况是第二种的特殊形式,就是说可以用第二种情况去发送可显示的字符——当然没人有闲心去数一句话里有多少个字母空格和标点符号! 在使用时,只要将TXS指向要发送的字符串或者数组,设置TxLen为要发送的数据长度,然后执行USART_ITConfig(USART1, USART_IT_TXE,ENABLE)就立即开始发送过程。用户可以检查TxCounter1来确定发送了多少字节。比如以第二种情况为例: - <div align="left">uint32_t *TXS;4 k$ a* O) ~. o
- uint8_t TxBuffer1[]="0123456789ABCDEF";
- B- \( o! o; }% H/ F+ k( ] - uint8_t DST2[]="ASDFGHJKL";. i0 v a4 M$ W
- __IO uint8_t TxLen = 0x00;</div><div align="left"> TxLen=8; //发送8个字符,最终发送的是012345675 Y) |; g: Z6 }' W: Q' R
- TXS=(uint32_t *)TxBuffer1; //将TXS指向字符串TxBuffer1
8 B: k9 I8 _9 C0 y. @ - TxCounter1=0; //复位索引值; t5 \) W7 c' ~
- USART_ITConfig(USART1, USART_IT_TXE,ENABLE); //启用TXE中断,即开始发送过程
1 s. E# W3 P6 D Z - while(TxCounter1!=TxLen); //等待发送完成, Z6 {1 E) P3 i' a
- & ?6 K" ?# ?& s3 B1 U. ` M2 q7 P
- TXS=(uint32_t *)TxBuffer2; //同上,最终发送的是ASDFGHJK
8 ~: h1 v- ~. L8 O$ k7 W% H - TxCounter1=0;
6 S I% m' X% N* @ - USART_ITConfig(USART1, USART_IT_TXE,ENABLE);
$ D7 N& ?% Y: O$ A - while(TxCounter1!=TxLen);</div>
复制代码 7 Z) `) B$ `9 c8 |
以上就是我认为的最佳方案,但串口中断方式数据有多长就中断多少次,我认为还是占用不少CPU时间,相比之下DMA方式就好多了,因为DMA发送字符串时最多中断两次(半传输完成,全传输完成),并且将串口变成类似16C550的器件。 / S2 c6 K: y. G; j! R1 \; O r, u+ V
# |; ~% i# X# t+ h# D+ S
|