在研究STM32串口接收发送中断的时候找到不少不错的资料,现在备份在这里。以供自己查阅,以及方便其他人。 TC ====TXE 顺便预告下最近会写个有关串口处理数据的帖子,从查询和中断方面以及数据处理的方式,从队列以及FIFO方面写起。
3 f; C( m! `7 ^3 ]SECTION 1 - /*2 Y( o; ~; g. m0 T
- 调试STM32串口过程中发现一个奇怪的问题,初始化串口1口,使能串口发送完成中断后,立刻就进入了发送完成中断。" t' X' f1 u( I" L% G8 I: u; h
- 仔细的查阅了STM32手册中的串口部分的介绍:
4 D s6 ]9 Y: Z& }$ q3 x -
! t* \* j+ p7 L+ d, P2 G- \" q - 以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。( T& F6 S t0 k! u6 I
- 8 d0 P6 q/ l2 ]8 c; ^! y: N7 ]2 L @
- 配置步骤:
6 V6 {" t% W8 e& _# L& s+ A - 1. 通过在USART_CR1寄存器上置位UE位来激活USART, M7 y- X: b7 |9 {. L5 F5 W
- 2. 编程USART_CR1的M位来定义字长。
+ M9 }; E8 ^% ` - 3. 在USART_CR2中编程停止位的位数。5 s* t5 Z4 R* A
- 4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中
: @0 E; e8 }" \7 l# N2 }! ~ - 的描述配置DMA寄存器。
$ R' G4 f/ J5 V; N - 5. 利用USART_BRR寄存器选择要求的波特率。8 h1 M4 J% l* Y. q* G
- 6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。" S( G* \! U" s/ d" Z
- 7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况$ R, q* D. ?; L
- 下,对每个待发送的数据重复步骤7。- a- h5 E. K$ n$ Y
- 8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的
3 F, b+ x% e/ @! i) S; A - 传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏
7 G3 z' x$ `9 Y- L% _8 c. { - 最后一次传输。2 c: I) C5 V$ g5 E# r8 C" y3 a( P' K1 M
- */
$ d5 B1 O3 [, |1 H: a: s4 P - //解决的办法:, s5 w/ ?+ S# E+ l& L1 |+ d6 c
- //方法一
* q e" U+ r9 P0 G1 Y2 v; n - //在执行) C2 E* o# O( s( \8 R! m: r
- USART_ITConfig(USART1, USART_IT_TC, ENABLE); ; e7 w6 Z: \7 V
- //之前,先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行3 n2 z7 M5 R5 r D
- USART_ClearFlag(USART1, USART_FLAG_TC);' E+ g/ {! E( ?5 i" `
-
+ {: d9 I8 f- y) N8 N8 j5 t - //方法二:% G3 F Y6 t$ n
- //在执行
6 i9 _" x! ~. a, f3 h5 i% d, ] - USART_ITConfig(USART1, USART_IT_TC, ENABLE);% L5 { [! b6 g: X5 T5 C" J
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
2 Y3 T1 i; c0 P. B' N$ H% N2 u8 \ - {8 B! w9 }: H' ?) I) j2 ^; _1 b
- ; //等待空闲帧发送完成后 再清零发送标志
( y! X8 h! l3 _! T; o* r' b - }/ B# r1 M3 ~* L1 s$ c
- USART_ClearFlag(USART1,USART_FLAG_TC);
复制代码
' E7 P) L+ l* `7 Z) f ]. x+ b- f. }3 c3 |! m0 s
SECTION 2 * T& g) ~, Y: _; Y+ ?2 g
先说TC。即Transmission Complete。发送一个字节后才进入中断,这里称为“发送后中断”。和原来8051的TI方式一样,都是发送后才进中断,需要在发送函数中先发送一个字节触发中断。发送函数如下 : i& u4 ~% A) F5 v; M
H$ M% p8 Q& a# O; m
- /*******8 L1 B% ]" ^$ a) a* o9 Q
- 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.
. K I( { E, u7 @. G - 输入:字符串的首地址
& m8 M, H; z; p- ]9 {( t - 输出:无
3 @2 G6 M. _( K' I0 j4 ^1 S - *******/" X" e# i Y' A0 @* Z- H) G
- void USART_SendDataString( u8 *pData )( q7 P& o0 P* h# k
- {
) Y0 y6 Y) [7 z8 u2 V/ w' N - pDataByte = pData;# a% l4 k4 w# ^' `+ i; N
- $ @! l; }! _0 Q1 a6 G4 J3 F1 A
- USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.
( j/ F1 N- F8 L; a* U* [8 @ - & e& z2 `# n& q. Y$ S, v
- USART_SendData(USART1, *(pDataByte++) ); //必须要++,不然会把第一个字符t发送两次
% h. L6 f- e1 B - }
复制代码
$ d+ [$ T6 b" i# Q" N6 p中断处理函数如下
& v+ p' E, [7 M5 \9 V2 n4 ^- /********
$ W( [, h9 J/ x0 o) k" j" X& W6 T - * Function Name : USART1_IRQHandler
4 K: i" ^& ~. x: s - * Description : This function handles USART1 global interrupt request.
+ i, E6 f& K6 P9 a9 e( l - * Input : None
- ~1 K4 F4 F/ c+ d - * Output : None: h# d2 u6 ?( S' x
- * Return : None9 D) b" Q* `/ r5 |
- *********/
& A6 \, t. n6 W7 H9 |; @& C - void USART1_IRQHandler(void)
& m5 p( p* S* m% w: @ - {
6 y4 y) L' q, U/ d - if( USART_GetITStatus(USART1, USART_IT_TC) == SET )$ H' e2 C; F; z" c: [/ ~7 _
- {4 m) x& R3 ~' O$ M4 H' D' L( I
- if( *pDataByte == '\0' )//TC需要 读SR+写DR 方可清0,当发送到最后,到'\0'的时候用个if判断关掉9 ]; M3 c b+ P" y$ S
- USART_ClearFlag(USART1, USART_FLAG_TC);//不然TC一直是set, TCIE也是打开的,导致会不停进入中断. clear掉即可,不用关掉TCIE
/ f% }- ~" @* G1 u1 H2 M2 m. x \ - else
4 s @3 ~+ \, r" n$ J' s - USART_SendData(USART1, *pDataByte++ );" [, O1 H9 q( {, M( L
- }
1 u8 s# u q! S4 f+ Q
( t" M. Q( l8 z' \& A! G- }
复制代码 8 L' ]6 N, l! R' J: w' f
其中u8 *pDataByte;是一个外部指针变量 ; K9 M+ b* K1 U4 Z3 U+ ]; C
7 u3 I. N% [1 ~$ x" x在中断处理程序中,发送完该字符串后,不用关闭TC的中断使能TCIE,只需要清掉标志位TC;这样就能避免TC == SET 导致反复进入中断了。
& k2 s( O4 N# r) r. s8 t& _串口初始化函数如下 ' N D1 e2 j2 n" A( f6 ?
/ w; E& F; ?$ F4 V6 o$ c' A# F" ~
- /*********8 @7 p7 @- a# v
- 名称: USART_Config
- D+ C, I% b) k$ q! ^: Q4 @ - 功能: 设置串口参数
$ b" I$ v7 A+ G) O3 r - 输入: 无
* t* N/ V* s) g9 ?0 N; j - 输出: 无9 J- X5 ^- r3 e6 [" Z: p# h; @
- 返回: 无
, [+ J( a2 r- C - **********// U0 ] F* j4 g1 r0 T4 T, c7 y
- void USART_Config()
. [/ b# a' ~# L ]/ ^ - {+ ?3 D% r4 B% Q; W; d
- USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体
& {9 m* ]- d9 L! n' w- f$ R+ d" `& } -
' t( S+ f( [) N# K" F% [: ^: y - USART_InitStructure.USART_BaudRate = 9600; //波特率96005 e+ T; m) D" V9 q6 J6 P
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位5 `8 I; i. G) z% F$ Q
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
' p) R% p9 o! i; L1 @ - USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
7 _$ s9 r7 k+ x - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
$ Q( m( `* c1 Z4 ? - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式0 Y3 m# ~, R9 J% J4 O$ H- C# t5 R
- USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭8 u+ H. P7 s- `+ F: V0 w+ u
- USART_InitStructure.USART_CPOL = USART_CPOL_Low;- O: J9 z8 ^/ C! ~
- USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;
9 t( {3 d D# A* o, n { - USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
& t6 ^8 Q( o8 p0 E - USART_Init(USART1, &USART_InitStructure);//设置到USART1
0 }: N0 l3 V1 \' i. e" K -
4 A% L2 N+ g! g/ c7 t. w/ R- v - USART_ITConfig(USART1, USART_IT_TC, ENABLE);//Tramsimssion Complete后,才产生中断. 开TC中断必须放在这里,否则还是会丢失第一字节
7 c$ m& F! U. P4 `, y1 K
3 L6 N) Q+ s& G/ E9 _- USART_Cmd(USART1, ENABLE); //使能USART1: B A! B1 |, i' W
- }
复制代码 + [/ W' v7 @( F/ [/ |. S
这里请问一个问题:开TC中断USART_ITConfig()如果放在我的USART_SendDataString()中再开,会丢失字符串的第一字节。必须放在串口初始化函数中才不会丢。不知道为什么??
$ N. I ]3 c# X& C. j5 C# P这里笔者可以给出解释,你看下SECTION1 就可以知道为什么呢,你这样做的原理和SECTION1讲解的差不多,就相当于延时,而你后面没有丢失数据的主要原因就是你代码中有这么一句 USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.
3 R) Y; m! G) z6 \6 \6 B& Y" F) }7 ?: N6 }. f/ F
再说判断TXE。即Tx DR Empty,发送寄存器空。当使能TXEIE后,只要Tx DR空了,就会产生中断。所以,发送完字符串后必须关掉,否则会导致重复进入中断。这也是和TC不同之处。
# ]7 @4 D% [3 b1 N i- x
$ f* L. ?- {4 v' I8 l$ c发送函数如下:. r* D+ r b3 ? h' h+ `( y+ Z
- /*******
- P B# a/ i7 x6 ^% o7 r - 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.# t% t/ O0 F) H s2 u
- 输入:字符串的首地址7 ?) W: _1 j# _6 E8 d
- 输出:无8 z, M1 o q5 i& \) V" t
- *******/
6 a" Z( A+ J4 K" L4 i - void USART_SendDataString( u8 *pData )2 u6 c2 G- A% d. @. u
- {% l0 h$ }$ }8 @! ~
- pDataByte = pData;" o5 c; r& N- l: X6 O$ b1 s$ v
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。
4 T; e: w( q- S5 ^+ f - ' e7 p8 L/ S+ h p4 N [+ P
- }
% O; i2 E. s% k: \4 v
复制代码
4 R; c# S3 X' o- S. k" B) {中断处理函数如下:, R6 r/ E+ n% M9 l3 d: m
5 n' e0 m; s+ ]. j& J4 Q- /********$ {& R: j8 ?# h% r9 p9 m
- * Function Name : USART1_IRQHandler, r: c" t$ A; }6 ~( D; d9 i
- * Description : This function handles USART1 global interrupt request.
) n2 P# ?% |+ b* m. [4 X8 | - * Input : None
: r: \6 t+ Y) M( a& I2 v - * Output : None" k1 V+ i* Q" F" z; g3 B
- * Return : None
6 W! B( g3 b S: L - ********/$ e M6 X: W& I, `& U
- void USART1_IRQHandler(void). `) \: q1 n( Y, \
- {3 F% q% C0 i7 V, N6 q4 ]
- if( USART_GetITStatus(USART1, USART_IT_TXE) == SET )
) l4 h- j1 r' k# R. o - {# l8 r) y9 n. M( A# y& T. N9 H* g
- if( *pDataByte == '\0' )//待发送的字节发到末尾NULL了. S( A3 |) r8 o1 s0 ~( h1 P
- USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//因为是 发送寄存器空 的中断,所以发完字符串后必须关掉,否则只要空了,就会进中断
0 d% V4 q! W3 V9 ~9 Z# @ - else
) f5 f1 _9 e) {: B, X - USART_SendData(USART1, *pDataByte++ );
5 a/ y3 u" ]# s. e - }
* S, G& h4 I5 S. Q
. g1 P# D/ C# h" }- }
复制代码 % k& b0 d8 ~9 F2 i
在串口初始化函数中就不用打开TXE的中断了(是在发送函数中打开的)如下:6 }" R- E f' T2 R' G; j: f
- /************% h# Q( s7 c; O% R
- 名称: USART_Config# B" Z ^, ]5 I
- 功能: 设置串口参数
/ g! K' T- L: \. l - 输入: 无
b6 f5 T C$ L* v) V- q9 q - 输出: 无% C) T6 e# |5 @0 I. ]3 U: I9 y0 S# h
- 返回: 无
" U) }, s e' K7 ~ - ************/2 X* S) ^8 W1 d# m9 S* N4 b
- void USART_Config(). n g/ g+ _+ [) C" A: l7 y; M
- {: U9 g7 Q% X9 p$ i" P) o6 `3 F
- USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体( r" G: ~6 b" w" e
-
J. `' @9 c7 b7 A( I; h - USART_InitStructure.USART_BaudRate = 9600; //波特率9600
% U+ }, p' k, e- f- l! C/ [ - USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位0 l9 ^1 C* t! ]+ Z I( s+ ^" F' F
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位6 E4 I9 c5 ~8 _
- USART_InitStructure.USART_Parity = USART_Parity_No;//无校验. }0 [4 V$ T% Q2 r1 }# H9 M3 g
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
1 x' F+ o" ^ K+ E9 ?9 J% m) Y - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式- Q( J5 I) d9 d( l. a" g0 Q' H7 Y6 t r
- USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭
( ], w6 ? M% D6 H) q1 E# | - USART_InitStructure.USART_CPOL = USART_CPOL_Low;
) O- C9 d* }: g$ D- \" @+ S9 V - USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;: C: u, y, Q- x+ X4 g8 Y9 h
- USART_InitStructure.USART_LastBit = USART_LastBit_Disable;# T& J6 w" a0 U- Z- \" }' f. z
) ?! U, l" L+ N2 V3 B8 Z- USART_Init(USART1, &USART_InitStructure);//设置到USART1
6 g; \9 \6 h9 Q -
' a3 e7 K5 q- O# D - USART_Cmd(USART1, ENABLE); //使能USART19 W6 C" I; ^! d
- <div align="left">}</div>
复制代码 Y0 V. ]& B1 e" g/ p% l
SECTION 3 * B3 B" s. r1 I5 C
! i# J- c1 d. q7 b- b+ ?在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register)。, @: ]5 H. V8 B5 L5 v
" r# _# _. W+ E8 w3 n; E+ j2 {! `- z对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束;对照下图,当TDR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。: ~2 h6 g4 S: w
% z$ c, I6 V" [# ]另一方面,在刚刚初始化好USART还没有发送任何数据时,也会有TXE标志,因为这时发送数据寄存器是空的。+ X9 b! ?" O) B- q( I/ m) P6 W
; e1 x$ P! r5 K0 r( f" x6 _TXEIE和TCIE的意义很简单,TXEIE允许在TXE标志为'1'时产生中断,而TCIE允许在TC标志为'1'时产生中断。
: ^ d+ `$ d4 Z% r! a5 Q+ _- }' k8 [0 G8 N
至于什么时候使用哪个标志,需要根据你的需要自己决定。但我认为TXE允许程序有更充裕的时间填写TDR寄存器,保证发送的数据流不间断。TC可以让程序知道发送结束的确切时间,有利于程序控制外部数据流的时序。
6 e9 ^8 G0 L6 W7 T; K3 FSECTION 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;
: H2 A( I( E9 t8 b - extern uint8_t *TXS;
" A1 O, n4 H9 x; B1 K J - extern __IO uint8_t TxLen; </div><div align="left">void USART1_IRQHandler(void)' T( Y/ V( b( A! r! Q$ ?" y
- {
& Q0 m3 Q$ \3 {3 O1 c9 n) m, ^ u - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)# k6 e* m/ g$ d4 o. g
- {
1 W, B3 E0 v4 g1 X% ] - if(TXS[TxCounter1]) //如果是可显示字符- q& k) `% ~, J
- { USART_SendData(USART1,TXS[TxCounter1++]);}
' y' X5 r$ x1 I x- T6 t" f( i4 R - else //发送完成后关闭TXE中断,
- r8 r1 D! B" L - { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);} * `: ~6 {* N# d. H3 W
- } 8 z" ]- C$ e3 ^0 \$ _. x$ C7 W
- }</div><div align="left"> 对于第二种情况,和上面的大同小异,其中TXLen表示要发送的二进制数据长度:</div><div align="left">void USART1_IRQHandler(void)5 C3 }9 o) \, T7 i, G
- {
! w* S8 D7 G. k+ |& k O6 w; O - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //对USART_DR的写操作,将该位清零。
" D& D9 \5 F# |% w, q5 K1 x- q - { ' j1 _ n, y. v3 Q. R
- if(TxCounter1<TxLen)" c* E2 o- G9 i7 ]5 _& B
- { USART_SendData(USART1,TXS[TxCounter1++]);}" X6 j0 X+ X( c9 b
- else //发送完成后关闭TXE中断$ ]( m, ~! n% ~1 F
- { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);} + J, r# G1 W6 s* V" ~8 {4 C
- } + D4 g7 | }+ Y' K
- }</div>
复制代码 ! h4 m7 x+ ~( |5 k% K9 }
事实上第一种情况是第二种的特殊形式,就是说可以用第二种情况去发送可显示的字符——当然没人有闲心去数一句话里有多少个字母空格和标点符号! 在使用时,只要将TXS指向要发送的字符串或者数组,设置TxLen为要发送的数据长度,然后执行USART_ITConfig(USART1, USART_IT_TXE,ENABLE)就立即开始发送过程。用户可以检查TxCounter1来确定发送了多少字节。比如以第二种情况为例: - <div align="left">uint32_t *TXS;
6 s6 E+ F: i, I1 ~1 ?9 F - uint8_t TxBuffer1[]="0123456789ABCDEF";3 W* b$ I4 e" Q R' _, k2 ^- w
- uint8_t DST2[]="ASDFGHJKL";
6 @6 `# h: ]- Y4 R' _8 e2 {2 b% K: Q - __IO uint8_t TxLen = 0x00;</div><div align="left"> TxLen=8; //发送8个字符,最终发送的是01234567; o/ l% s) @2 M7 F1 h" }3 l
- TXS=(uint32_t *)TxBuffer1; //将TXS指向字符串TxBuffer1
$ X# f2 Y0 R* ^; `& q - TxCounter1=0; //复位索引值
( J5 i0 ?2 s" Q! `. t' v - USART_ITConfig(USART1, USART_IT_TXE,ENABLE); //启用TXE中断,即开始发送过程; V% r/ i$ N: Y- Y: ^2 X: R* D! J: |
- while(TxCounter1!=TxLen); //等待发送完成" Y' y$ ^$ t6 @: J" H1 g
/ q/ ]) @& `" T( ~* o6 O# \6 t- TXS=(uint32_t *)TxBuffer2; //同上,最终发送的是ASDFGHJK
9 j6 B, S$ @" l - TxCounter1=0;+ [/ D# `) t3 {* i8 t l
- USART_ITConfig(USART1, USART_IT_TXE,ENABLE);
& b' ]2 `; }. l2 E7 D7 M/ u& V8 c0 v - while(TxCounter1!=TxLen);</div>
复制代码 7 l3 z) @- d: }
以上就是我认为的最佳方案,但串口中断方式数据有多长就中断多少次,我认为还是占用不少CPU时间,相比之下DMA方式就好多了,因为DMA发送字符串时最多中断两次(半传输完成,全传输完成),并且将串口变成类似16C550的器件。
: S; I8 A* A4 U# V# q, V5 v% f7 Y( r; Y! P0 H9 Z4 S3 c) B% h
|