你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32串口中断的一些资料

[复制链接]
STMCU小助手 发布时间:2022-1-23 22:20
在研究STM32串口接收发送中断的时候找到不少不错的资料,现在备份在这里。以供自己查阅,以及方便其他人。
TC ====TXE
顺便预告下最近会写个有关串口处理数据的帖子,从查询和中断方面以及数据处理的方式,从队列以及FIFO方面写起。
6 z$ u1 y2 R: n
SECTION 1
  1. /*) e. D' R! `5 n! d& ]8 Z
  2. 调试STM32串口过程中发现一个奇怪的问题,初始化串口1口,使能串口发送完成中断后,立刻就进入了发送完成中断。8 ^7 C% E; K) l. k% ~) H& e- x
  3. 仔细的查阅了STM32手册中的串口部分的介绍:
    / _- e: |$ p% _/ W" i
  4.          
    / H' `3 V2 j  I4 [7 G
  5. 以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。; M' d/ i" A* e' R
  6.           1 {9 N6 s) r1 {* x
  7. 配置步骤:
    5 s9 h; H: i! D. K2 g
  8. 1.  通过在USART_CR1寄存器上置位UE位来激活USART9 }: ]" {# `) N$ k$ k
  9. 2.  编程USART_CR1的M位来定义字长。1 f6 t, W- y2 W8 I
  10. 3.  在USART_CR2中编程停止位的位数。6 v! ?4 I$ R4 H: l" l$ [
  11. 4.  如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中
    7 a$ C! T/ S4 U  s0 u9 B* h) q
  12. 的描述配置DMA寄存器。  |6 i) d2 r, h1 x( K
  13. 5.  利用USART_BRR寄存器选择要求的波特率。1 w+ |% m4 {2 z  n! R
  14. 6.  设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。: m: ]0 R6 j6 g5 m. h
  15. 7.  把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况
    ( X. S/ [( P7 G7 y' f* Q+ w
  16. 下,对每个待发送的数据重复步骤7。
    # S0 I* F% Q. y- J2 g3 \
  17. 8.  在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的
    ! Z) a3 R- N6 E% N2 }6 n
  18. 传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏
    5 J6 k; R8 h7 i- N
  19. 最后一次传输。
    + r3 |4 k% P% ~7 v9 w8 C; U3 i
  20. */
    7 d; J# A  q, z  D5 p: b4 z# u% \
  21. //解决的办法:
    - |# h8 a7 Z; e8 n
  22. //方法一
    / ^1 c! H6 Z$ B: u. r
  23. //在执行
      I5 R$ ~* a1 q, f5 x
  24. USART_ITConfig(USART1, USART_IT_TC, ENABLE); ! G) ~# e6 n* j
  25. //之前,先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行
    7 I# ?0 g6 K8 x/ }  }/ r  {: k3 Y
  26. USART_ClearFlag(USART1, USART_FLAG_TC);
    6 U0 D1 {4 |" t5 ^% @& h
  27.          
    5 ]; V! A; C2 \
  28. //方法二:% u; @/ E- h. X
  29. //在执行4 e: [  D- r3 }6 c; o
  30. USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    9 H' Y$ {" ^$ D
  31. while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
    - o( ?# y, j7 A* K2 c
  32. {! d; a( u; S% j- ~; r' ]
  33.         ; //等待空闲帧发送完成后  再清零发送标志! K8 r1 Z5 ], }9 s$ u
  34. }9 Y. j5 U; ?1 M1 F3 {5 A  D5 v$ I
  35. USART_ClearFlag(USART1,USART_FLAG_TC);
复制代码

8 N9 ?9 z# ]3 C* k1 N# q
, h$ I( @0 c/ F) r
SECTION 2
6 t" P7 z# z; s* X. A$ d! o7 Z" i
先说TC。即Transmission Complete。发送一个字节后才进入中断,这里称为“发送后中断”。和原来8051的TI方式一样,都是发送后才进中断,需要在发送函数中先发送一个字节触发中断。发送函数如下
# ?, _5 @1 H/ V9 v7 p# O
' g7 m* _/ A$ Y. J; b  W% H0 \
  1. /*******
    5 J% W- E; R& [0 p9 s2 M' A
  2. 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.
    0 |4 N% c& C2 {
  3. 输入:字符串的首地址" \$ d9 g; R. a3 I$ @; I+ n
  4. 输出:无
    % t$ x) n6 }9 `9 m8 k. n
  5. *******/+ W% C6 m( @0 [3 w. b- r
  6. void USART_SendDataString( u8 *pData )* T# ^; B1 b1 [+ e, l/ J
  7. {1 U- b! J/ [& H
  8.     pDataByte = pData;0 C: e( ?1 {' _4 o$ u+ q# u
  9.   
    : [! ~( ~1 y, ~: x6 F
  10.     USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.
    * }0 X0 l5 W) r5 [& Q# ~- l- v
  11.     * d. }1 Z1 B+ ?4 B5 Y
  12.     USART_SendData(USART1, *(pDataByte++) ); //必须要++,不然会把第一个字符t发送两次
    & S, U. s% s$ Y$ P
  13. }
复制代码
- i0 g2 C" I/ F) L( D3 G$ N8 `* J
中断处理函数如下
* R; |0 ?% f0 q  o7 ^
  1. /********8 d  v" B, {* ^2 ^
  2. * Function Name  : USART1_IRQHandler) E8 M; P$ z$ x, I# P
  3. * Description    : This function handles USART1 global interrupt request.( c7 K4 k7 ~. w3 g$ U2 \/ o9 K# b
  4. * Input          : None
      J# D$ h% q/ R+ B
  5. * Output         : None! k/ _0 ~* f' {- b& y/ i/ K
  6. * Return         : None
    5 ]" [, G. s7 \& v1 d; m- p
  7. *********/
    ; l6 z; ~; }; r) ^& k
  8. void USART1_IRQHandler(void)
    7 u( {$ ?7 Y4 }$ P! O
  9. {
    - i- k  j3 Y/ T/ u% r" h9 `3 Q
  10.     if( USART_GetITStatus(USART1, USART_IT_TC) == SET  )
    ' F4 N  J/ a5 {1 o
  11.     {
    5 S! V( I; |! C4 \% X' q( h
  12.         if( *pDataByte == '\0' )//TC需要 读SR+写DR 方可清0,当发送到最后,到'\0'的时候用个if判断关掉
    2 K0 N. |: E- v0 `% M0 V- f
  13.             USART_ClearFlag(USART1, USART_FLAG_TC);//不然TC一直是set, TCIE也是打开的,导致会不停进入中断. clear掉即可,不用关掉TCIE
    ! J) Y$ Q1 @4 e
  14.         else
    , Z! l3 b! K; U$ h  J) y3 p
  15.             USART_SendData(USART1, *pDataByte++ );
    - w, ?% U2 A1 J" w" e) w0 @+ m
  16.     }
    ; y- x0 B9 Q( a6 q0 y0 r  _

  17. 4 v6 a7 x8 R: {# y" k* j3 I
  18. }
复制代码

7 }6 b9 p8 N3 Y3 D; a其中u8 *pDataByte;是一个外部指针变量0 w- [! |0 ]; A+ L

5 j- a9 J3 F9 P; f: Q5 @在中断处理程序中,发送完该字符串后,不用关闭TC的中断使能TCIE,只需要清掉标志位TC;这样就能避免TC == SET 导致反复进入中断了。

3 _5 W" D1 u% U1 N; V# p( b
串口初始化函数如下
7 \. @; T- F5 c) u# W; s# ?6 W- m  C1 D# n1 Z: u  _3 Q
  1. /*********$ M% l2 Z/ u2 @2 w0 {
  2. 名称:  USART_Config2 n; n. T, v8 H. p, h% _# V
  3. 功能:  设置串口参数! G; x1 }# ^: D2 x! ^7 ]
  4. 输入:  无
    ; t* u, F' X; \  N6 m& y( r* U
  5. 输出:  无
    5 W3 B4 }$ f" M, P2 H0 }, w. ^) e
  6. 返回:  无, ]  {: Y2 ~. |( e
  7. **********/& C6 P% @* o) H8 [& c: M
  8. void USART_Config()
    1 a- R; i3 g; U7 I+ g! }- v8 ?
  9. {% p( m, ^8 c- `) d* v7 \
  10.   USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体
    8 u' i7 ]$ r. V  F( E' K. o* Y
  11.   
      b; F* W7 R: L
  12.   USART_InitStructure.USART_BaudRate = 9600; //波特率96001 ^5 T. j& f& t# h6 C5 F
  13.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位" {" b( H$ N6 f/ z* w
  14.   USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
      m: u3 I4 f* ^/ \' ]2 U. F& ^
  15.   USART_InitStructure.USART_Parity = USART_Parity_No;//无校验6 O& B2 j# X+ l+ K: z7 u; A9 [
  16.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制- Z. @. g7 D9 y( v1 v
  17.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式
    ' B$ C. }! y) E' f: `
  18.   USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭- Z2 Z5 u7 Z9 ~0 ~4 }. A( K/ n
  19.   USART_InitStructure.USART_CPOL = USART_CPOL_Low;
    # l" i* U3 Y1 a6 T
  20.   USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;
    % _/ v9 R, @2 {' O% f: U2 w  i
  21.   USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
    , ]8 U) E! v4 ~# a  [3 D  y% ~
  22.   USART_Init(USART1, &USART_InitStructure);//设置到USART1. z* w6 D) }+ {! Y0 {
  23.   
    4 L" M" Z# j; q
  24.   USART_ITConfig(USART1, USART_IT_TC, ENABLE);//Tramsimssion Complete后,才产生中断. 开TC中断必须放在这里,否则还是会丢失第一字节3 H2 I$ x; T- ^

  25. - M9 a! S5 N- O! D1 ^
  26.   USART_Cmd(USART1, ENABLE); //使能USART17 _+ O! N- A' ?$ R" M
  27. }
复制代码

2 P. {8 i" e- {! Z5 I" _这里请问一个问题:开TC中断USART_ITConfig()如果放在我的USART_SendDataString()中再开,会丢失字符串的第一字节。必须放在串口初始化函数中才不会丢。不知道为什么??
4 z! K! T" k! x" j' K0 g
这里笔者可以给出解释,你看下SECTION1 就可以知道为什么呢,你这样做的原理和SECTION1讲解的差不多,就相当于延时,而你后面没有丢失数据的主要原因就是你代码中有这么一句 USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位,否则可能会丢失第1个字节的数据.网友提供.
+ @! L# q9 k5 V$ }

( N6 e0 R5 H/ s/ p* R6 f再说判断TXE。即Tx DR Empty,发送寄存器空。当使能TXEIE后,只要Tx DR空了,就会产生中断。所以,发送完字符串后必须关掉,否则会导致重复进入中断。这也是和TC不同之处。7 e, ]( }8 [2 D

8 f% O! ~* V; ?发送函数如下:
+ z. S3 M% @" Z; N# S
  1. /*******- I3 ~& a- Q& z
  2. 功能:中断方式发送字符串.采用判断TC的方式.即 判断 发送后中断 位.
    8 V9 ^3 i( Q5 ^9 ^$ c2 O4 z
  3. 输入:字符串的首地址6 u% S5 a( D9 S
  4. 输出:无* n6 R/ q% N3 H
  5. *******/, u0 b9 K, q  p" F2 v
  6. void USART_SendDataString( u8 *pData )
    1 J/ B$ a6 u1 g) r
  7. {
    - u0 c$ D4 J: L) D& @; L
  8.     pDataByte = pData;
    * H: Y9 I4 q2 J3 u4 Z
  9.     USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。 & Q) E* a; V* z, X7 u
  10.     . c# X7 p3 f1 S! E  h8 M3 s
  11. }$ v- Y% v1 n2 F2 }8 n* j
复制代码

3 ~5 ^/ |4 G! n% z; ?中断处理函数如下:; c* p) Y. ~$ A+ P* x
9 J$ u5 X0 q' C- Q( K" @
  1. /********1 v# S7 R6 g% i
  2. * Function Name  : USART1_IRQHandler( [$ l; o$ d: X2 M: k
  3. * Description    : This function handles USART1 global interrupt request.
    $ x5 m& d8 m; c5 a" G- D6 k: @/ `
  4. * Input          : None
    1 d  u7 ?" x3 `) I$ n  t
  5. * Output         : None* n! W  N3 X+ u: P$ D
  6. * Return         : None
    5 d# W% j- d  F
  7. ********/7 X& M5 V7 a( p) G: y
  8. void USART1_IRQHandler(void)
    ' _8 p+ a1 j) ~; n' Y3 v( A* x: P
  9. {
    / y8 L1 h* P8 Q) ^" T5 C% |
  10.     if( USART_GetITStatus(USART1, USART_IT_TXE) == SET  )0 {9 _6 e0 ~' b8 R
  11.     {
    * `' V1 O, k" e* E8 z- h" o* B" k& v: |
  12.         if( *pDataByte == '\0' )//待发送的字节发到末尾NULL了
    7 l9 a- S! r* u8 B
  13.             USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//因为是 发送寄存器空 的中断,所以发完字符串后必须关掉,否则只要空了,就会进中断- V2 T7 t- u% j
  14.         else6 ^' }! X6 B# ]' y$ G  ?
  15.             USART_SendData(USART1, *pDataByte++ );
    9 L- L- P/ l  B2 \9 k7 U& R
  16.     }
    1 D8 s( r; z: W$ M* R- z

  17. 1 h5 {9 g+ B( k  y; s
  18. }
复制代码

" k. R( E$ @8 ^3 J, m在串口初始化函数中就不用打开TXE的中断了(是在发送函数中打开的)如下:2 N# I9 C; r/ j2 p( X' n9 @2 _
  1. /************
    , l3 G% q/ h2 k$ [& O0 r. C' |
  2. 名称:  USART_Config5 h- H# T% N# o* z- d: [1 a
  3. 功能:  设置串口参数
    3 M7 O7 F/ G) x' P
  4. 输入:  无' ~* n! f% v8 Y, V2 h: z
  5. 输出:  无5 {. p4 a# R( k) p4 O) q4 i
  6. 返回:  无
    % L4 V) e( Q1 s+ R( m! c$ j
  7. ************/
    * V0 g" B; ?& k( [3 P
  8. void USART_Config()
      |* u8 T5 N4 x" G8 s
  9. {' g* u* Q0 w. w2 J; P0 m( E
  10.   USART_InitTypeDef USART_InitStructure;//定义一个包含串口参数的结构体
    3 u( [4 `4 n7 X
  11.   
    ) \* F1 d, F. e3 J* b
  12.   USART_InitStructure.USART_BaudRate = 9600; //波特率9600: t1 l" r- D* ~. g9 z# a
  13.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位6 v  m, b: I" c, e
  14.   USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位% g/ T4 K/ M) J/ I6 j
  15.   USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
    , s6 e8 Q- k/ E; Y' v  h! T7 ]
  16.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制; j- V6 ^; S9 R, r* ?: g3 Q
  17.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//输入加输出模式* P5 k8 Q/ k% M; U2 ~
  18.   USART_InitStructure.USART_Clock = USART_Clock_Disable;//时钟关闭- O6 _. K- H2 J0 ~; Z, v3 c
  19.   USART_InitStructure.USART_CPOL = USART_CPOL_Low;% n9 F0 P( P% W2 H* X2 B
  20.   USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;
    2 f2 M$ ~& H: y) [& d9 z
  21.   USART_InitStructure.USART_LastBit = USART_LastBit_Disable;: M, i4 T) a& ^
  22. : N7 }" b2 o6 m$ f3 B0 W
  23.   USART_Init(USART1, &USART_InitStructure);//设置到USART1
    / n4 t* Q" C' j, y; a/ o9 w, n" f
  24.   % O- G0 ?, ]+ B' C" b8 I) Q
  25.   USART_Cmd(USART1, ENABLE); //使能USART1- s3 u4 i6 T2 S( T5 F3 ?" u5 d
  26. <div align="left">}</div>
复制代码
7 u( @6 i7 [  K% Z3 L1 M* [
SECTION 3
5 o0 N" U# J" c5 b/ z1 B6 t) Z
1 y- n3 Z+ F  s$ I. k
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register)。, ]! n; a6 \5 }2 q1 t$ Z: l
  v2 |8 W) ?# Y' U( h
对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束;对照下图,当TDR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。0 L: l9 t0 x7 }+ W4 |4 a

5 O9 J  \/ _) c& p另一方面,在刚刚初始化好USART还没有发送任何数据时,也会有TXE标志,因为这时发送数据寄存器是空的。
2 o& W/ T( x, q! q2 d
9 J/ J/ ~, i% M7 ETXEIE和TCIE的意义很简单,TXEIE允许在TXE标志为'1'时产生中断,而TCIE允许在TC标志为'1'时产生中断。
, p' W4 f. z. h# v4 f
; N2 K, i7 u( l+ q4 v, t1 I" n至于什么时候使用哪个标志,需要根据你的需要自己决定。但我认为TXE允许程序有更充裕的时间填写TDR寄存器,保证发送的数据流不间断。TC可以让程序知道发送结束的确切时间,有利于程序控制外部数据流的时序。
9 d& X8 B& p  g! k1 a' H
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是索引值:
  1. <div align="left">extern __IO uint8_t TxCounter1;
    . F' n$ ?& [5 M& l' l" {& Z, b  ^8 H$ J
  2. extern uint8_t *TXS;% p  x) R; q8 b7 R& U& y5 i! Y
  3. extern __IO uint8_t TxLen; </div><div align="left">void USART1_IRQHandler(void)+ ^( N% _6 N, R1 O2 q* Y) W; D
  4.     {
    % r+ Y8 t5 N( p9 v" C
  5.         if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
    # r: w5 G, B3 Q. |5 l
  6.             {                                               
    , D4 R/ v1 b& B/ ~9 f9 G& Z
  7.                 if(TXS[TxCounter1]) //如果是可显示字符6 o8 k5 r1 q# d9 ?
  8.                     { USART_SendData(USART1,TXS[TxCounter1++]);}+ A; S  c! P% [0 ?7 _
  9.                 else   //发送完成后关闭TXE中断,
    8 B. o- I% H' [
  10.                     { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}                                                        ' C- O6 g3 [1 g/ Y  \
  11.             }                   ( u. }1 W% i+ E  b7 f- ]+ d
  12.     }</div><div align="left">        对于第二种情况,和上面的大同小异,其中TXLen表示要发送的二进制数据长度:</div><div align="left">void USART1_IRQHandler(void)
    5 g# c3 O/ S) r; `+ R& q, E" J
  13.     {  ^" z6 V# l5 u4 }* r7 u+ D( {
  14.         if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //对USART_DR的写操作,将该位清零。" m. c+ F6 k! Z. r5 O
  15.             {                                              1 i, r; l9 K9 r  y$ x
  16.                 if(TxCounter1<TxLen)2 f* x! R7 l7 i; ^3 ~+ S
  17.                     { USART_SendData(USART1,TXS[TxCounter1++]);}
    ) l: F6 S3 r3 U7 P2 ~, S
  18.                 else   //发送完成后关闭TXE中断5 m$ n8 W/ W) o/ V, H4 |$ l8 W
  19.                     { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}                                                         
    ) D) |: x& P* W( z/ r
  20.             }                    
    + m0 R* @- X4 Z
  21.     }</div>
复制代码

4 O0 R- B; |! O% ~% a# A7 J& a7 w! F
        事实上第一种情况是第二种的特殊形式,就是说可以用第二种情况去发送可显示的字符——当然没人有闲心去数一句话里有多少个字母空格和标点符号!
        在使用时,只要将TXS指向要发送的字符串或者数组,设置TxLen为要发送的数据长度,然后执行USART_ITConfig(USART1, USART_IT_TXE,ENABLE)就立即开始发送过程。用户可以检查TxCounter1来确定发送了多少字节。比如以第二种情况为例:
  1. <div align="left">uint32_t *TXS;
    9 t: g5 _. o7 _7 X; P! a
  2. uint8_t TxBuffer1[]="0123456789ABCDEF";5 {# J$ B- A2 O! L8 r- ^
  3. uint8_t DST2[]="ASDFGHJKL";
    7 F9 i$ z$ p% V4 a. n5 n$ Q
  4. __IO uint8_t TxLen = 0x00;</div><div align="left">     TxLen=8;                               //发送8个字符,最终发送的是01234567. i8 N0 f' E  D1 V" u( l
  5.     TXS=(uint32_t *)TxBuffer1;   //将TXS指向字符串TxBuffer1
    4 L  g" X0 X% D  b+ w: Z
  6.     TxCounter1=0;                     //复位索引值0 _$ `: |; B) x3 W  N
  7.     USART_ITConfig(USART1, USART_IT_TXE,ENABLE);   //启用TXE中断,即开始发送过程
    1 b; P$ g! U# J4 Z; n
  8.     while(TxCounter1!=TxLen);   //等待发送完成4 P# ?2 F0 t9 J  \$ B
  9. ! I1 g& g" q! a- t6 I
  10.     TXS=(uint32_t *)TxBuffer2;   //同上,最终发送的是ASDFGHJK
    0 \4 _+ O8 a, h: P4 ]
  11.     TxCounter1=0;
    5 {6 ]* L3 A7 u8 F" N
  12.     USART_ITConfig(USART1, USART_IT_TXE,ENABLE);; ]# \2 g3 M! g
  13.     while(TxCounter1!=TxLen);</div>
复制代码

7 U9 d# W% F* ~- R0 ?: p
        以上就是我认为的最佳方案,但串口中断方式数据有多长就中断多少次,我认为还是占用不少CPU时间,相比之下DMA方式就好多了,因为DMA发送字符串时最多中断两次(半传输完成,全传输完成),并且将串口变成类似16C550的器件。
  D( o# w  P/ V1 g6 q* m- @
8 F6 q; O. G' }8 P
赞 收藏 评论0 发布时间:2022-1-23 22:20

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版