在研究STM32串口接收发送中断的时候找到不少不错的资料,现在备份在这里。以供自己查阅,以及方便其他人。 TC ====TXE 顺便预告下最近会写个有关串口处理数据的帖子,从查询和中断方面以及数据处理的方式,从队列以及FIFO方面写起。 6 ?" ~" E8 ^& o: F" H& H
SECTION 1 - /*3 ?4 e$ u$ P5 O; @* d* \
- 调试STM32串口过程中发现一个奇怪的问题,初始化串口1口,使能串口发送完成中断后,立刻就进入了发送完成中断。! g4 G7 m/ C: h( `
- 仔细的查阅了STM32手册中的串口部分的介绍: y! W# ]: m' j" z8 C3 o0 r" E- X
-
9 V# w# w6 i) u+ l - 以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。2 m2 S0 w2 S# Y+ k/ l& C D
-
( ~; `6 a, N; B - 配置步骤:- w7 Y/ v4 U$ Y; h5 M8 r- t6 W
- 1. 通过在USART_CR1寄存器上置位UE位来激活USART P6 R$ N: L& b: Z7 r4 d) \$ {0 P
- 2. 编程USART_CR1的M位来定义字长。8 }5 X" d0 m8 H" q
- 3. 在USART_CR2中编程停止位的位数。, h5 i6 O, k7 h: N3 J% t
- 4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中
; J4 D* s- J8 K: \- s6 ] - 的描述配置DMA寄存器。
$ ]; O3 r- F+ k- m! @ - 5. 利用USART_BRR寄存器选择要求的波特率。
, O0 D! ]9 J' `; Z, O4 ^/ P) p, q - 6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。$ C; A' A( v8 f. z/ h8 g
- 7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况
* U0 Y4 L% i9 ]7 Y9 U* E- ` - 下,对每个待发送的数据重复步骤7。# t, L9 j s }/ U% z1 _4 D3 M
- 8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的
$ g9 A! e& }- s8 o - 传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏
0 Y9 f9 o5 Q) z( g; z! Y! U - 最后一次传输。1 e/ G9 ?& G# O& s/ e4 W
- */
% M: K3 T! Z6 ~; y; b* d, C2 a - //解决的办法:
" d# [( S j+ d+ B: }( A - //方法一3 R# k* N. e# |) a5 H
- //在执行
+ W" g! a) v! e& O" r8 T - USART_ITConfig(USART1, USART_IT_TC, ENABLE);
3 s" |7 X5 M1 K2 D r: v9 X - //之前,先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行
# x: E% u! ^' { t& T - USART_ClearFlag(USART1, USART_FLAG_TC);. Y2 T A; f5 }+ ]$ [/ a \, T
- 3 T; d5 m1 A5 T: r
- //方法二:1 {, l3 k6 g; n( p: ~# ^9 g
- //在执行
0 `; G, j4 N$ {* ^8 c- u5 `6 ^' ? - USART_ITConfig(USART1, USART_IT_TC, ENABLE); t5 C6 l$ }/ V6 M9 n0 h9 W1 k1 z
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
/ H& Y" ]% e9 _' y$ q4 H - {% k9 R) H& E+ @% t
- ; //等待空闲帧发送完成后 再清零发送标志 L( a% j# m5 {+ K( l9 P9 f
- }4 v& b, b2 {/ q) z0 _# A( H
- USART_ClearFlag(USART1,USART_FLAG_TC);
复制代码
! c+ l2 B5 r* d* {0 n& }+ e9 `3 V! Q, d8 m( t4 E$ z9 d# T
SECTION 2 1 m/ y x; L( }' Z) c' @
先说TC。即Transmission Complete。发送一个字节后才进入中断,这里称为“发送后中断”。和原来8051的TI方式一样,都是发送后才进中断,需要在发送函数中先发送一个字节触发中断。发送函数如下
0 l- z% D" I; w$ \$ t M& A2 s$ y$ o$ X+ O6 d7 `9 j0 h
- /******** H1 U& d# t. d$ j
- 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.! ~# A: A7 H3 c# u9 B# E$ A
- 输入:字符串的首地址- m, i! D8 F6 }. ^- B
- 输出:无
i. M4 \; X! x2 n8 z - *******/
2 | s: [, L0 n+ Z3 J2 \$ [ - void USART_SendDataString( u8 *pData )
5 Y$ v" O3 ~# V$ x - {( [1 m4 ^: E0 h3 _
- pDataByte = pData;1 ^7 i" ~; M. i; W
-
/ i7 \7 ~/ b6 }$ c/ E( { - USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.2 f+ W! ] D" {9 j
- ' E2 Q0 V" d B1 M0 r" T
- USART_SendData(USART1, *(pDataByte++) ); //必须要++,不然会把第一个字符t发送两次/ m% V" `& ^4 F% b8 [7 I
- }
复制代码 5 h! D! u7 q7 d* |' z
中断处理函数如下 3 E- x, b' J9 Y! \
- /********
0 Y; d" i$ a& r1 v: x2 F( Z7 l - * Function Name : USART1_IRQHandler
+ N8 T7 T" B0 } h5 ^1 i# W0 p7 s - * Description : This function handles USART1 global interrupt request.4 |( t0 X: e$ F$ k/ B: e
- * Input : None
M/ f* E) ?0 { @: |& L( r - * Output : None4 M9 t) l4 B$ S
- * Return : None; [/ _$ {# C/ R8 h' T; ^$ f$ L% Y6 W7 e
- *********/
; r5 U9 v# t# ^' v - void USART1_IRQHandler(void): T+ }# v! z0 n4 l! D
- {4 ]* @. C; v' O
- if( USART_GetITStatus(USART1, USART_IT_TC) == SET )1 V" C2 {. @4 F
- {2 Z4 c' F4 N# f' K- q& [
- if( *pDataByte == '\0' )//TC需要 读SR+写DR 方可清0,当发送到最后,到'\0'的时候用个if判断关掉
; J6 a, }! H2 r$ R. Z& f% A2 f4 o4 z - USART_ClearFlag(USART1, USART_FLAG_TC);//不然TC一直是set, TCIE也是打开的,导致会不停进入中断. clear掉即可,不用关掉TCIE
$ l3 k4 ]' d, P u - else1 }6 t- Y9 U* ?. i9 u( M3 d( @
- USART_SendData(USART1, *pDataByte++ );/ C7 v2 ?, l7 T. s+ t& t) A; n
- }3 K7 q8 ~) m/ ]: V' @7 @8 U
. N. U$ P, m$ k1 M- }
复制代码 , v& `: f$ Y* X: H: m; L
其中u8 *pDataByte;是一个外部指针变量 2 G9 ^/ ~! k F/ Z
! `' f9 N, h2 j, B4 n在中断处理程序中,发送完该字符串后,不用关闭TC的中断使能TCIE,只需要清掉标志位TC;这样就能避免TC == SET 导致反复进入中断了。
5 x, r3 ~$ ^/ B/ F串口初始化函数如下 + z9 c% u. N& s: ?
* O/ o3 B# _1 d
- /*********
6 w$ B$ ?- ]# K8 L: d - 名称: USART_Config: h' A; F) p& }8 I/ k4 M& o( _
- 功能: 设置串口参数& Y2 n' R! z% `" `' y
- 输入: 无3 A/ a/ q9 p# g9 ?2 e& P7 u
- 输出: 无; H( v' G0 }& i$ Q) @/ @! E
- 返回: 无2 w1 ]3 s& x) y9 H b; @% g
- **********/
9 W) m+ f3 I2 g v. {& l; H" u& C1 o U - void USART_Config()1 f* `2 b/ B6 I% x! z* [/ a+ d" @: q
- {
( j4 N9 B% O: w% `& S- q/ w - USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体, s" _8 s) D/ E# U
- 3 t: S; f* \: x) ^4 {3 N
- USART_InitStructure.USART_BaudRate = 9600; //波特率9600
5 F! G3 P) }$ k5 p0 F - USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
. D% [! A3 M/ n2 J6 @3 ] - USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位& X$ I' l6 q4 d$ J" I9 I
- USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
3 S$ A: n b0 Z6 ]1 O - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
5 r, M; ?! j0 T8 n6 Q# c( S - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式
2 @7 p* Y9 q( o* f - USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭- A! C8 b( w* B" b- d! m
- USART_InitStructure.USART_CPOL = USART_CPOL_Low;8 B; |. O8 @1 ]; G9 o+ g1 W5 R
- USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;" ~8 U3 p9 ]# n/ C
- USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
! t& s4 X+ }9 N# _7 F. z - USART_Init(USART1, &USART_InitStructure);//设置到USART12 P5 X* ?$ T0 M. Y4 |& Z
-
5 J9 w6 J$ L: W7 P/ q' d4 I5 D) T - USART_ITConfig(USART1, USART_IT_TC, ENABLE);//Tramsimssion Complete后,才产生中断. 开TC中断必须放在这里,否则还是会丢失第一字节0 d, U& b) H( e" p$ g; ?* V; A5 E
- ' E/ o& v2 U5 c2 F
- USART_Cmd(USART1, ENABLE); //使能USART1( a* P) f( U7 X E* h0 Y/ H4 Y3 X
- }
复制代码
8 d. k% m/ c9 {( b" x这里请问一个问题:开TC中断USART_ITConfig()如果放在我的USART_SendDataString()中再开,会丢失字符串的第一字节。必须放在串口初始化函数中才不会丢。不知道为什么?? : D" [" x+ s% ?8 h! _
这里笔者可以给出解释,你看下SECTION1 就可以知道为什么呢,你这样做的原理和SECTION1讲解的差不多,就相当于延时,而你后面没有丢失数据的主要原因就是你代码中有这么一句 USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.
7 e/ r2 l; \$ V( p& [+ j, k1 H- S/ M' a/ F7 n/ Z: D5 F
再说判断TXE。即Tx DR Empty,发送寄存器空。当使能TXEIE后,只要Tx DR空了,就会产生中断。所以,发送完字符串后必须关掉,否则会导致重复进入中断。这也是和TC不同之处。
6 v9 k: E/ [5 Q3 x
! j, K' ]/ U; f$ x/ ]2 a6 \9 S发送函数如下:
8 V. J$ c8 ]/ f: S: Q- /*******
4 V2 w3 |& k( p0 o) a6 W - 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.! S7 e. C; c. j' p* ^3 L G
- 输入:字符串的首地址
6 Y/ K1 z8 K( l, V _3 @0 N2 h - 输出:无
. C( o4 ?9 j) P - *******/
6 D; ~8 m% d& ` L9 R7 c" z! n7 |* p' x - void USART_SendDataString( u8 *pData )% F6 i( {) B. C i, p5 F
- {
' U$ C- H1 ]. ?1 @ - pDataByte = pData;/ `: n0 p6 ^0 [. X7 ^
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。 ; w* l" D" k$ s7 f% Z7 a# G
- 1 c' `2 p3 x/ c+ e7 j# h
- }
7 M I6 W2 K; w( l4 v6 A
复制代码 ; D8 j; D2 i0 L' \
中断处理函数如下:9 r" t/ B- H8 X v2 y [
- B+ S4 z3 r w% N- g) ]- /********& L7 @ y- z" l. X
- * Function Name : USART1_IRQHandler; K) @4 v; f' Z* I9 t
- * Description : This function handles USART1 global interrupt request.
/ `# I; ]! `% S( [# p4 u: T - * Input : None) a! j2 l& |" `+ H
- * Output : None$ x: {! s5 O- f9 H5 M
- * Return : None# Q$ H( D% U% @ J+ I& [# a
- ********/
# z; T4 P- `. ~* E q - void USART1_IRQHandler(void)# O K. U7 r# C9 I5 R& [
- {8 u$ C' S! Y% C* F, u8 c' e
- if( USART_GetITStatus(USART1, USART_IT_TXE) == SET )
8 @5 j! _# D8 D7 G+ `7 u, P) v& q - {) b- Q4 @# {) e
- if( *pDataByte == '\0' )//待发送的字节发到末尾NULL了5 }; Y# K+ J7 C0 n4 x5 \
- USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//因为是 发送寄存器空 的中断,所以发完字符串后必须关掉,否则只要空了,就会进中断
& r* B, e/ I( Q5 {/ N: y - else
: O* T5 _8 q: H L# I - USART_SendData(USART1, *pDataByte++ );
3 B( Q; Y; r; c2 x) T - }* w- f* R0 ^6 ?/ m, r
- 0 O( K, z# x5 @% A& h1 G
- }
复制代码
6 V3 j o' |8 i3 W在串口初始化函数中就不用打开TXE的中断了(是在发送函数中打开的)如下:1 P" f: c G" t
- /************
8 j- }" t- |7 k( e# Q3 Q9 A- [7 R - 名称: USART_Config
* p' B+ a; [ `0 G. _9 ]" L; M - 功能: 设置串口参数
" f7 O$ l( D5 P& a d6 f5 y( d6 _ - 输入: 无
" t3 Z' O3 i3 l; S9 I7 t1 ?5 S& c Y - 输出: 无* ^& w6 X0 R* V& P
- 返回: 无
+ j2 T3 M0 K$ j2 _ - ************/
" P2 M6 P) z5 P$ v - void USART_Config()
% N" F6 o: J3 H+ T - {
( a' ?1 M- {! F5 I - USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体
$ e6 O8 W# I q; e+ S7 b- L7 e6 L - ; S. i/ C& [; X7 E4 P) b7 @
- USART_InitStructure.USART_BaudRate = 9600; //波特率96004 y6 y/ H+ E' s; e# ^
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位( ~3 x% V3 e' d, A$ G3 `+ z
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位6 t m2 W! o/ B& W- A1 I( r/ o
- USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
1 v" }: ?3 b5 L" B) q - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
0 V9 W# A6 Q, C( z: q' T" } - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式
6 i; z- b4 G' H2 p - USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭' {- e) ^/ ?) r) `
- USART_InitStructure.USART_CPOL = USART_CPOL_Low;
1 [4 j5 s/ z! c, r - USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;
; P' X: ]: x( m; r- p - USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
4 ~/ w1 O$ ~: p8 P7 t - . L j8 i% i; _
- USART_Init(USART1, &USART_InitStructure);//设置到USART1
: l. v6 B# |2 y' \6 @ - 6 g O$ J3 |& n" t2 L; \9 ?( P1 w
- USART_Cmd(USART1, ENABLE); //使能USART1
1 [7 V/ E: ]" r+ \% c! P - <div align="left">}</div>
复制代码
# U( J3 C$ r8 s$ w% R" S+ ESECTION 3
* D2 Q$ o& z7 l& {( ~
% Q5 g' L- [( T; T8 A" _在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register)。
' I; S# a- @+ j Q! R: D) F" \0 E+ D1 ?, E3 p: @
对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束;对照下图,当TDR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。# X# P0 v: }* p+ W/ D
+ ]) ~" ?8 U/ e$ l另一方面,在刚刚初始化好USART还没有发送任何数据时,也会有TXE标志,因为这时发送数据寄存器是空的。
5 h# V% x& c& o3 L$ J
& p9 p8 q7 h% u2 K( R) PTXEIE和TCIE的意义很简单,TXEIE允许在TXE标志为'1'时产生中断,而TCIE允许在TC标志为'1'时产生中断。
; z! b l; l* F. s# p4 o4 P
# U* v1 \7 n; N3 Z2 _, |2 E& K5 t: D至于什么时候使用哪个标志,需要根据你的需要自己决定。但我认为TXE允许程序有更充裕的时间填写TDR寄存器,保证发送的数据流不间断。TC可以让程序知道发送结束的确切时间,有利于程序控制外部数据流的时序。
+ @1 y- U$ I7 P ?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; {4 b: x9 [) F/ _
- extern uint8_t *TXS;
5 u6 g2 @+ j+ R# W' | - extern __IO uint8_t TxLen; </div><div align="left">void USART1_IRQHandler(void)
* b: \ j( D/ P% R2 S* [/ F - {
* Y$ B& t8 t! B3 X3 Z5 z/ } - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)6 R5 c7 s. T$ r8 c* L. P
- { ; i) [; F& V, p" [3 Q6 D/ I8 k
- if(TXS[TxCounter1]) //如果是可显示字符
+ D2 P1 ?0 X9 s( @, g6 _, Y - { USART_SendData(USART1,TXS[TxCounter1++]);}
7 i, r6 r- K8 d* p - else //发送完成后关闭TXE中断,; r2 W9 i; \, e* e' Q/ _% c
- { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);} 6 o. } Q2 @7 H6 H @# `- G
- } 0 R3 u: I, c$ [5 g- c2 y
- }</div><div align="left"> 对于第二种情况,和上面的大同小异,其中TXLen表示要发送的二进制数据长度:</div><div align="left">void USART1_IRQHandler(void)9 \6 ~! v1 K0 i4 p
- {
\7 S" y; p3 x0 t; e: g - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //对USART_DR的写操作,将该位清零。8 ]# ?5 h$ `. \2 s# U+ M, R
- {
A. f0 L# B, F6 D - if(TxCounter1<TxLen)
9 z1 P$ E9 p$ N. q" u+ i! t - { USART_SendData(USART1,TXS[TxCounter1++]);}/ U* L* ^9 b1 y$ y, L
- else //发送完成后关闭TXE中断- J7 f" S1 X& D, l; w( G
- { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);} 7 Q/ p& J6 N6 A# V0 y8 u8 ^' i
- }
- {+ c8 ~$ q/ ^% ~ - }</div>
复制代码 ( ]4 Q2 k2 w& E% _4 E
事实上第一种情况是第二种的特殊形式,就是说可以用第二种情况去发送可显示的字符——当然没人有闲心去数一句话里有多少个字母空格和标点符号! 在使用时,只要将TXS指向要发送的字符串或者数组,设置TxLen为要发送的数据长度,然后执行USART_ITConfig(USART1, USART_IT_TXE,ENABLE)就立即开始发送过程。用户可以检查TxCounter1来确定发送了多少字节。比如以第二种情况为例: - <div align="left">uint32_t *TXS;
( x; ^/ f5 A. g+ l - uint8_t TxBuffer1[]="0123456789ABCDEF";
4 ~! A, D2 ^: C- @' F3 x- c - uint8_t DST2[]="ASDFGHJKL";
# A# k" d# Z% a - __IO uint8_t TxLen = 0x00;</div><div align="left"> TxLen=8; //发送8个字符,最终发送的是01234567- F+ l5 i. f! ^
- TXS=(uint32_t *)TxBuffer1; //将TXS指向字符串TxBuffer1
( }9 q p# O2 z: y( V( h - TxCounter1=0; //复位索引值5 w; s* m5 v/ x4 m
- USART_ITConfig(USART1, USART_IT_TXE,ENABLE); //启用TXE中断,即开始发送过程
( d7 O( Z; n0 s% J5 X( u* i6 S - while(TxCounter1!=TxLen); //等待发送完成0 N* }& M, c. Q/ W6 t6 b# W
- 7 C6 e$ \3 j$ l0 h3 r$ Q
- TXS=(uint32_t *)TxBuffer2; //同上,最终发送的是ASDFGHJK! }1 e( i6 V& X. D4 ? e
- TxCounter1=0;1 C7 w( p8 P* [6 `4 I5 a6 Q5 B
- USART_ITConfig(USART1, USART_IT_TXE,ENABLE);
% a Y9 S0 \+ O$ a" u T( l7 t - while(TxCounter1!=TxLen);</div>
复制代码 : u% ?2 E8 k: o7 J0 ?
以上就是我认为的最佳方案,但串口中断方式数据有多长就中断多少次,我认为还是占用不少CPU时间,相比之下DMA方式就好多了,因为DMA发送字符串时最多中断两次(半传输完成,全传输完成),并且将串口变成类似16C550的器件。
/ x& w- e# B( G: G( ?$ F o/ a, b# ~3 s7 H
|