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

STM32心得:串口通信相关知识及配置方法

[复制链接]
STMCU小助手 发布时间:2022-11-20 18:08
主要内容:2 [# \, q: T! k4 W: T2 g
1) 串行通信接口背景知识;
2 a4 [4 K9 S. g  ^6 \9 {: D; Y" W2) STM32F1串口框图讲解;
' c) t* z6 `+ I( R5 O. ^3) STM32串口部分常用寄存器和库函数;: v' i: r: @! M; r, q) l
4) 串口配置一般方法;
1 `$ e2 G) r- S* A$ `5) ALIENTEK提供的公用代码usart.c和usart.h解读。3 Y  k* C  y8 e+ d8 V" r3 f

, v, W( ~& ~6 [4 s" `; X2 K* f- W' v1. 处理器与外部设备通信的两种方式
' q# U6 b# \+ A" A1.1 并行通信,传输原理:数据各个位同时传输。优点:速度快。缺点:占用引脚资源多。2 n, P. J' G( n3 U( l9 ~: ~; s' @
1.2 串行通信,传输原理:数据按位顺序传输。优点:占用引脚资源少。缺点:速度相对较慢。
! O5 \8 a6 A4 ~- N# |: k2. 串行通信(按照数据传送方向可分为)6 l* N, v7 u' T3 O) o  ~! v% A( m* b: ~
2.1 单工:数据传输只支持数据在一个方向上传输(图a);
3 j) C+ i: {9 h2.2 半双工:允许数据在两个方向上传输,但在某一时刻,只允许数据在一个方向上传输,实际上是一种切换方向的单工通信(图b);
4 d5 ~+ v" y% g" y/ H, ?& [2.3 全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力(图c)。
" _% H) |4 `9 u
" c, I7 t7 P/ z: o- o 20200406091726697.jpg
7 J9 o, O- D  N. @* X, M3 k6 L' W$ E$ D
3. 串行通信的通信方式! a9 `, H" ~1 j9 q. |' Q  n
3.1 同步通信:带时钟同步信号传输,包括SPI,IIC通信接口;* Q% B( N9 c2 U: q) O7 m+ Q( M
3.2 异步通信:不带时钟同步信号,包括UART(通用异步收发器,双方需事先约定好波特率),单总线。
; I' p, w1 w4 `
+ x+ K# g  E6 A4. 常见的串行通讯接口
# T$ Q+ t- |9 T6 ?7 L8 H7 m8 ^( w( p+ h
2020040609190067.png
; l: q. Z1 J: `: c3 l5 @5. STM32的串口通信接口- }( K4 T2 d3 E6 H+ f
5.1 UART:通用异步收发器;
: W. e; @4 B; `9 q$ X$ m6 k5.2 USART:通用同步异步收发器。
( q( N6 y  O: E- `5 @2 H备注:大容量STM32F10x系列芯片,包含3个USART和2个UART。+ U0 }2 R& A1 P+ q; a8 f
7 v2 s( Y0 N: d' }
6. UART异步通信方式引脚连接方法: \3 c/ E1 z8 e9 F; Q  G4 S( b
6.1 RXD:数据输入引脚。数据接受;; C& A6 A& Z* i0 g* I( M9 i1 o
6.2 TXD:数据发送引脚。数据发送。$ D) R3 k0 @! s( z+ S/ T
" B/ w: H+ y- K3 E! R; N" i
20200406092107514.jpg . f" E6 ~0 {1 t+ O8 H( P0 E

6 x1 {" {& j" E! g6.3 开发版上的串口引脚如下表所示:( M9 r3 G4 u5 _" e: A. p( S/ U
$ S! t; Q' R2 E9 u: n
20200406092152980.png
% o' V8 q+ P1 }4 t6 W- r
2 T- Z' G+ Y0 k+ F' R7. UART异步通信方式特点
, K+ `2 Z) E  O8 V8 U% s$ D7.1 全双工异步通信;
) a) a: N2 u. C% k7 ]7.2 分数波特率发生器系统,提供精确的波特率。发送和接受共用的可编程波特率,最高可达4.5Mbits/s;
" z  |0 u. Y5 _+ [8 H4 |7.3 可编程的数据字长度(8位或者9位);
/ ^; a) H5 k6 _, Q' F$ E2 ~7.4 可配置的停止位(支持1或者2位停止位);
. o( i6 ?& p: f' `. n7.5 可配置的使用DMA多缓冲器通信;
# C: v& H1 G8 L0 [4 o. F1 `" r7.6 单独的发送器和接收器使能位;
/ o) ?5 ~5 e5 J7.7 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志;
$ y" S" C' t4 W$ w7.8 多个带标志的中断源。触发中断;
. m7 k2 j  E" j) H. {7.9 其他:校验控制,四个错误检测标志。
. ~( y" y  @8 r5 H' C3 a" O
0 E7 i! E9 G  {- Y; S8. 串口通信过程
- ^0 y. X: Y! U. _4 h4 k) f" e( c
/ m/ W! Y4 F: i3 i! @ 20200406092341382.png
$ N/ I$ B& y: v7 D
$ ~4 R  ~. Y5 G5 x9. STM32串口异步通信需要定义的参数
; n2 V7 R- i+ z- e
9.1 起始位;
, z  j. V& ]8 ]. e& ~' `9 W4 g! e9.2 数据位(8位或者9位);
! v9 P. z- T3 @& [) T! V9.3 奇偶校验位(第9位);
3 A" Z; F0 i$ Y. k% i9.4 停止位(1,15,2位);' H. U/ l6 `, k
9.5 波特率设置。
; a+ I# [2 R0 s
' s& {8 m* N5 b1 k) ]6 s  a8 w 20200406092501380.png # A" x- a- Q% p1 j- z

- Y" l+ J, O. ]7 s$ l8 A10. STM32串口框图
3 X3 D" n8 Q8 D  O; [9 A# j- @10.1 对于大容量的STM32F10x芯片,有5个串口,串口1时钟来源PCLK2,串口2~4时钟来源PCLK1。0 O& s5 |! C. \' G5 i! i1 @
8 P  ~1 k  j3 y/ |% [8 S
20200406092600669.png
& K$ N" I* L3 F0 h# t; `3 \, q
11. 常用的串口相关寄存器* }. |# ~  x" i7 c& @+ N8 _* D- Z6 s
11.1 USART_SR状态寄存器(串口通信的状态位);0 i$ q9 i& ?3 s. h$ O6 b
11.2 USART_DR数据寄存器(读写都通过该寄存器);/ D7 Q4 O3 X2 Q) n" |8 Q1 @) L
11.3 USART_BRR波特率寄存器。
$ F& n. c# R/ K  h/ ~  `  {
9 Z5 }/ Z6 L, |12. 串口操作相关库函数7 R9 t) |' {5 r
8 A# e1 {  `' K1 m& K' k
  1. void USART_Init();                      //串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能//4 T) L6 h( F. O+ T) E4 V9 y4 w
  2. void USART_Cmd();                       //使能串口//: z: z! y: O3 T9 \4 s1 |; C
  3. void USART_ITConfig();                  //使能相关中断//  t# }% @9 X; k1 }; q' [
  4. void USART_SendData();                  //发送数据到串口,针对DR寄存器//
    # i" p7 Z0 Z1 C/ |8 _* V
  5. uint16_t USART_ReceiveData();           //接受数据,从DR读取接受到的数据,针对DR寄存器//; m" ~% R: R: N* s" \/ {/ O! Y
  6. FlagStatus USART_GetFlagStatus();       //获取状态标志位,针对SR寄存器//
    % C$ x8 R5 L# I0 [" f
  7. void USART_ClearFlag();                 //清除状态标志位,针对SR寄存器//
      b" r* o% r" T2 @# L
  8. ITStatus USART_GetITStatus();           //获取中断状态标志位,针对SR寄存器//
    ( i5 B: |3 s  C! K
  9. void USART_ClearITPendingBit();         //清除中断状态标志位,针对SR寄存器//
复制代码
0 s) c6 u6 q  m1 Z3 O; ~
13. 串口常用寄存器解读, k% e, s. u4 ]; J: w
13.1 状态寄存器(USART_SR)
$ m8 B% m# K" q
! D5 i0 t' u4 \& ^
  1. FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
复制代码

7 ?2 ^0 x1 ^# w9 @$ w% u 20200407143351654.png 4 m8 p" s; x1 d" F

1 c2 f/ k, H0 ]) ]4 k' _( G13.2 数据寄存器(USART_DR)- t+ }7 |& e6 S+ R9 B5 I2 ^
# s, X+ @2 u0 [" N% j: Q  O
  1. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
    ! j) V( {+ c) c
  2. uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
复制代码

- \8 e; p; X# q; I 20200407143449289.png " F" Q8 L0 r. L- x
* o4 S4 r: I8 n6 \
13.3 波特比率寄存器(USART_BRR)  i5 F6 F# L" t0 `4 R
! w  P2 l, }+ I6 S4 O- M6 @: Q  k
  1. void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
复制代码
3 I, e$ s, h; Q' Q+ R9 a
14. 波特率计算方法

/ Q' q& e% j2 ?$ @; N
: Y, {% D) i& k' @) W& k% g+ q 202004071436317.jpg 8 u# s+ f" `! v) M1 }* M5 t, X/ e
% Q: V8 s, {- I; U" B
15. 串口配置一般步骤
9 M$ R! C+ ^. i. o
15.1 串口时钟使能,GPIO时钟使能;  v" B. y6 F: u+ f7 x

* u1 D+ s4 b, j# A5 A# }& v
  1. RCC_APB2PeriphClockCmd();     //USART1位于RCC_APB2PeriphClockCmd中//
复制代码
$ D1 N1 ~$ Z6 C' h5 H5 X+ Q9 B/ u/ m# b
15.2 串口复位;- B8 n. B  d2 m* p' M" ]
( Z3 h' ?* Y& D- D# Y
  1. USART_DeInit();               //这一步不是必须的//
复制代码

, O# ]. q! ]! _- m2 T1 Z15.3 GPIO端口模式设置;$ S* X3 [+ D/ d: F/ e; K
( H5 v8 a! ?- O
  1. GPIO_Init();                  //TX模式设置为GPIO_Mode_AF_PP,RX模式设置为GPIO_Mode_IN_FLOATING //
复制代码
' B4 g( o6 h, S3 u4 f
15.4 串口参数初始化;5 D3 @( c0 R9 `. o" v5 a

# N' c3 _, g+ h  O) z  r
  1. USART_Init();
复制代码
. a9 K  |. W: t2 }* ?
15.5 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤);
, G5 K! H( l( ^* H" e7 w) I- G
5 u- T6 w: j5 l# D. y1 L
  1. NVIC_Init();# J8 b( L/ M& ]! O
  2. USART_ITConfig();
复制代码

1 F; A. Y, Z# H! e5 m/ o8 l15.6 使能串口;4 N* v6 X5 J( t& |" |" H# X0 v4 G. D  Q
7 O% u! Z( I$ J& o3 w( o9 c
  1. USART_Cmd();
复制代码

+ i4 M, F6 r7 h! E( z3 r15.7 编写中断处理函数;; K% A2 A! Q4 p; u3 ^
' x3 A$ a3 y/ Q6 I0 e& _. ?
  1. USARTx_IRQHandler();
复制代码

: t, Y+ T1 a: m1 x! C15.8 串口数据收发;2 y* f# j+ u5 z( I
! ]: {& Q, g  R2 V( e) @& X
  1. void USART_SendData();                      //发送数据到串口,DR//7 G! G. `8 F7 {! S+ w6 P# e- ?" c
  2. uint16_t USART_ReceiveData();               //接受数据,从DR读取接受到的数据//
复制代码
% F2 q9 o. c9 t, E
15.9 串口传输状态获取;: a+ j8 \) p. l3 @% c7 k
) V' M. K3 j; y2 ?0 P0 h
  1. FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
复制代码
' H) V; |. k! D
20200407144125217.png
5 u6 Q! D- ?) o. P3 T
- {* k) p: m, t4 R; u
  1. void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
复制代码
! ?4 w0 |$ x% \
20200407144213278.png
1 m6 h3 {2 v1 _9 `& Y1 T# ~! [, G& M& F
16. 串口配置案例7 T$ C, Y! u5 d( v
3 j% n1 U! n5 O2 c, K2 k
  1. //案例说明:设置PA9和PA10位USART1的TX和RX,开启USART_IT_RXNE接收中断,中断服务函数目的为,当USART_IT_RXNE发生,USART1接收数据并发送回去,需配合串口调试助手进行实验//( k- {: p! b8 V" E5 E# [  k& N
  2. #include "stm32f10x.h"
    $ W: _" i. k  z
  3. //编写我的初始化函数//
    ' s! F( Q- o, D( z5 z/ L3 E
  4. void My_USART1_Init(void)6 E" i1 `2 `; E8 U
  5. {
      i1 h7 O* b$ G+ |' k' \
  6. GPIO_InitTypeDef GPIO_InitStruct;
    . f. s: l6 ^/ B' L. j
  7. USART_InitTypeDef  USART_InitStruct;
    - @+ T$ j' y/ P' z: @
  8. NVIC_InitTypeDef NVIC_InitStruct;4 b& |$ ^) ?2 U
  9. //第一步,使能相关时钟//
    " n! D7 I& ]  q* \
  10. //使能GPIOA时钟,RCC_APB2PeriphClockCmd()位于stm32f10x.rcc.c文件中//
    , r$ T$ K8 b& P# V6 u- ^5 q4 L; _
  11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 6 e; R7 _( }8 D5 T
  12. //使能USART1时钟// * v& z- r8 B' s! Y
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);                      3 {2 d8 d; v. {. O9 f
  14. //第二步,串口复位//
    0 d% T6 A. n% T9 C1 G
  15. //将外设 USARTx 寄存器重设为缺省值,复位USART1,USART_DeInit()位于stm32f10x.usart.c文件中//
    $ q2 ?. r! L5 a1 g: ~8 g3 a
  16. USART_DeInit(USART1);                                                            * d7 W: N+ y4 O  O2 x, V( q6 ?  d  }
  17. //第三步,GPIO端口模式设置,PA9对应RXD,PA10对应TXD//( `% v% H6 b9 C/ g3 Q
  18. //先对PA9进行设置,模式为复用推挽输出,引脚9,速度随意//6 h4 Q$ J6 @! ]% ^" B+ `4 W3 H
  19. GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;         //复用推挽输出//8 n# i5 \) C- z( A
  20. GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;               //引脚9//
    % z6 _4 e1 J) h6 A# i
  21. GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;       //随意设置//# v, n0 T* y# @2 \2 Q  T, q9 w8 k
  22. //根据上述GPIO_InitStruct中指定的参数初始化外设GPIOA寄存器,,GPIO_Init()位于stm32f10x.gpio.c文件中//
    ) e) c7 V0 i/ ?' o' L0 `
  23. GPIO_Init(GPIOA,&GPIO_InitStruct);                                          : t2 K$ O4 c8 L
  24. //再对PA10进行设置,模式为浮空输入或带上拉输入,引脚10,速度随意//) Y+ `. g4 k1 [1 \! w3 B
  25. GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //浮空输入//
    : D% Q& u  g' J; o! y
  26. GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;              //引脚9//
    / }* i' N* ~# a  H& Z( Q
  27. GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;       //随意设置//3 S3 c( ], `# f8 b$ C/ p) q/ Z
  28. //根据GPIO_InitStruct中指定的参数初始化外设GPIOA寄存器,GPIO_Init()位于stm32f10x.gpio.c文件中//
    + n! e+ X# ^; Z' Z
  29. GPIO_Init(GPIOA,&GPIO_InitStruct);                                           ! J. N0 c1 L& C$ q6 T
  30. //第四步,串口参数初始化,在电脑上进行串口通信时,串口调试软件也需按下述参数设置//
    0 g4 _6 `5 `4 q3 T1 I1 L! ?2 |
  31. USART_InitStruct.USART_BaudRate=115200;                                    //波特率为115200//5 t" u. k9 |3 w4 i+ B
  32. USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不使用硬件流控制//
    ) |7 e. z2 G7 M) I
  33. USART_InitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;                 //收发都使能,可用或运算//
    1 N# t& ?/ z( {) _8 ~  `1 n
  34. USART_InitStruct.USART_Parity=USART_Parity_No;                             //不用奇偶校验位//                           
      L* b2 o2 ]% A2 D1 D
  35. USART_InitStruct.USART_StopBits=USART_StopBits_1;                          //设置1个停止位//
    * ?2 }( h  Q4 D" w! _* j
  36. USART_InitStruct.USART_WordLength=USART_WordLength_8b;                     //设字长为8,因为不用奇偶校验//
    ) L: w* [, O5 O% h; Z# L
  37. //根据上述USART_InitStruct中指定的参数初始化外设USART1寄存器,USART_Init()位于stm32f10x.usart.c文件中//
    * e, q* Q1 M4 a( t3 m
  38. USART_Init(USART1,&USART_InitStruct);
    " |: C$ o- j: K3 }; ^
  39. //第五步,开启指定中断,并初始化NVIC//   * V# E  @# q0 {  ~2 o  X
  40. //NVIC初始化// : g! `, H: M' h: P7 u2 v: t
  41. NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;            //选择位于stm32f10x.h文件中STM32F10X_HD中的USART1_IRQn//
    3 h! C$ l* E; j' ]
  42. NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;              //使能上述中断通道//
    1 C/ ~' b: e5 f/ _# x
  43. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;    //因为没有别的中断,根据中断分组2,参数可设0~3之间//
    / j+ Z, q) a4 h! ^: C2 k
  44. NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;           //因为没有别的中断,根据中断分组2,参数可设0~3之间//
    : H$ r) o0 L4 e
  45. //根据上述NVIC_InitStruct中指定的参数初始化外设NVIC寄存器,NVIC_Init()位于misc.c文件中//
    4 j( S/ N$ `2 N8 }9 O
  46. NVIC_Init(&NVIC_InitStruct);            3 |5 X9 S% m* F6 z& `1 F8 y/ ^
  47. //使能USART1的USART_IT_RXNE中断,RXNE是状态寄存器USART_SR的第5位,意思是接收中断//
    & G2 K/ A2 }3 s
  48. USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
    ' D4 _% Q# C$ P: z2 o0 {+ _
  49. //第六步,使能串口//  * l. n  V9 b2 P) X$ i5 M3 s
  50. //使能USART1外设,USART_Cmd()位于stm32f10x.usart.c文件中//
    ; e% h& w9 Z6 ?  {
  51. USART_Cmd(USART1,ENABLE);   
    ; g3 k6 h% _* v7 A  S* T
  52. }
    6 z6 U, M- i8 q" a
  53. //第七步,编写中断服务函数//$ i; O& Q4 d# b6 F
  54. //函数名称USART1_IRQHandler是由位于启动文件startup_stm32f10x_hs.s文件里定义的//
    + {% p# k5 ]9 y7 q$ }
  55. void USART1_IRQHandler(void)                                                   8 A$ s2 s; p1 V2 Y4 [5 n
  56. {# p: G  R; q: t! h, \
  57. u8 data;
    + K; J: O$ C& j( r/ ?* |/ ~! B1 [( X
  58. //第八步,串口状态获取//
    " |( }6 a; k) \4 ]5 b+ g8 S& e, f" k
  59. //检查USART1的接受中断USART_IT_RXNE发生与否,USART_GetITStatus()函数位于stm32f10x_usart.c文件中//
    - d8 q4 _. a8 N, J
  60. if(USART_GetITStatus(USART1,USART_IT_RXNE))                                 
    1 I- [( [( E1 {! s2 D1 H
  61. {
    ) V( x9 ~8 x% g
  62. //第九步,串口数据收发,较为常用//
    ' B6 L. m% J8 o& }. \1 l4 o
  63. //返回USART1最近接收到的数据,USART_ReceiveData()函数位于stm32f10x_usart.c文件中//
    9 ^) o8 R8 _. K/ |$ o2 m& @
  64. data=USART_ReceiveData(USART1);
    2 Q8 r6 _  L6 E5 x1 V
  65. //通过外设USART1发送单个数据,USART_SendData()函数位于stm32f10x_usart.c文件中//  
    + W, }5 }8 f) F9 U5 F( I5 Y! C
  66. USART_SendData(USART1,data);                                               , b+ U1 A% b) [; g( Z/ T5 H
  67. }5 ~/ N9 u9 o2 a
  68. }
    6 D( X0 L/ V; g* G) o% n  t
  69. //编写主函数//% b2 L* U- V% a5 G1 T5 Z# A
  70. int main(void)
    3 R2 a) ^0 s& P
  71. { / g' c0 Z5 t+ g" H2 N. x
  72.   //设置优先级分组:先占优先级和从优先级//
    ' ^# p2 ~( Z) i; A( f. ]+ v
  73.   //设置分组2,即2位抢占优先级,2位响应优先级,NVIC_PriorityGroupConfig()位于misc.c文件中//
    4 B! O* \( B- F5 H! W1 q5 g
  74.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                               A$ l+ h; I: p7 a! R' t! a% ^
  75.   My_USART1_Init();, G# ^' u3 [: o; j3 k" C( G+ ^
  76.   while(1)- e( Z; f4 r6 V' E8 A( g9 _
  77.   {2 `  B7 t8 T  V1 W- z
  78.   }6 a5 m# H7 V/ f9 q8 v
  79. }
复制代码

" @: l$ @9 G- e+ W% I1 m% {17. usart.h代码讲解
1 L  b8 W/ |/ b% E0 L+ b
) n9 N# i# p: n
  1. #ifndef __USART_H
    % `0 A' C4 X8 B3 T$ U
  2. #define __USART_H
    . @+ g9 n) h. |7 Z
  3. #include "stdio.h"    : y9 w+ I2 S1 q, Q7 k
  4. #include "sys.h"2 Q, k3 C# C2 @* q* t( [# s( p
  5. #define USART_REC_LEN    200            //定义最大接收字节数 200//
    # D; o  s. C4 }# y" w
  6. #define EN_USART1_RX     1              //使能(1)/禁止(0)串口1接收//
      w- R4 n# A' u' O: P0 x0 G3 r
  7. extern u8 USART_RX_BUF[USART_REC_LEN];  //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符//
    ' k+ U8 D8 w" S$ {7 m' y
  8. extern u16  USART_RX_STA;               //接收状态标记//       * P+ R# I4 }7 |. n2 r# y& y
  9. //如果想串口中断接收,请不要注释以下宏定义//
    % t1 Z1 J+ |" I. D; a; M8 i
  10. void uart_init(u32 bound);              //设置波特率//, l/ K3 [  J* ~. G
  11. #endif
复制代码

* [5 O3 Q) a; h18. usart.c里中断服务函数USART1_IRQHandler函数代码讲解4 I1 v, t4 S- \) z

& q1 h2 \% y9 w5 V
  1. void USART1_IRQHandler(void)      //串口1中断服务程序//
    ) }9 m: x; V- }# q
  2. {" |+ v7 f3 ^: L: V3 ^. \6 {- T
  3.    u8 Res;                          //定义一个变量Res,用来接收数据//
    # ]& m! h' d; {' w: Q2 u
  4.    #if SYSTEM_SUPPORT_OS                //如果SYSTEM_SUPPORT_OS为真,则需要支持OS//- A: [# T7 S( h1 w+ \" Z3 u$ }  |
  5.        OSIntEnter();   
      W- U- P8 g# V
  6.    #endif
    / B1 M* l9 M, i; K0 w1 d! Z1 E: Z
  7.    //*判断接收中断USART_IT_RXNE是否发生,发生则为1,不发生为*0//
    2 n3 F9 a3 J! v" B: N7 ?# h; {
  8.    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   //RESET=0//
    4 I/ i# Z& L& E/ t) w+ G
  9.       {. ?6 N7 C$ k! i, O+ w3 J: F
  10.       //*若接收中断USART_IT_RXNE发生,Res读取接收到的数据*//# C& J' }4 c/ M7 T
  11.         Res =USART_ReceiveData(USART1);         
    6 @0 ^% K9 B1 U1 m
  12.       //判断变量U16 USART_RX_STA的位15是否为0,当USART_RX_STA的位15为0时,则与运算后值为0,if返回1(真),反之if返回0(假)*//
    # Y; E* z- e0 O9 X, Y5 Z; L* B
  13.         if((USART_RX_STA&0x8000)==0)                  
    / c. V. L* S+ \9 D
  14.            {
      ?9 m6 a+ K9 q
  15.            //*若USART_RX_STA的位15为0时,判断USART_RX_STA的位14是否为0*//9 q5 N8 S( a) Y; ~5 n& Z
  16.               if(USART_RX_STA&0x4000)                  / `% j) p; C1 {4 ?! O" u8 s
  17.                  {( R# G- A; F9 _9 a' @2 J
  18.                  //*若USART_RX_STA的位14为1时,则判断Res接收的数据是否为0x0A,0x0A为换行标志*//; E6 R6 O. h9 ~+ w9 C  R
  19.                     if(Res!=0x0A)   
    - }; X% H6 u- z  v" ~
  20.                        //*若Res接收的数据不是换行标志,则接收错误,重新开始*//             $ H# y& N! ^$ R$ a* E
  21.                        USART_RX_STA=0;   + _6 ?5 t/ B$ {* p. u  B6 l
  22.                     //*若Res接收的数据是换行标志,则USART_RX_STA的位15至1* //       4 H2 l3 W* g8 {) a9 |5 F  h2 r
  23.                     else USART_RX_STA|=0x8000;      
    5 m, b8 p2 {$ K3 j0 r0 Q
  24.                   }; `  L( D: b4 ~% i
  25.                //*若USART_RX_STA的位14为0时,执行else *//! z, U0 R/ t7 M& h
  26.                else                                  S6 ~( F3 O* M" t
  27.                   {     
    ! z( Q1 X; K6 ^. w1 {6 Q3 e1 |
  28.                     //*判断Res是否等于(接收到)0x0D,0x0D为回车标志*//
    . M, _0 [5 r7 [/ |* w3 u0 G$ K) \
  29.                     if(Res==0x0d) - @. {- [( c9 \+ B/ J: W0 o, t
  30.                        //*若Res接收到回车标志,if为1(真),则USART_RX_STA位14至1 //                      . \2 u7 J8 D7 L; E
  31.                        USART_RX_STA|=0x4000;
    ) j2 l6 w( e4 @+ e1 P+ Y0 c7 C2 F
  32.                     //*若Res未接收到回车标志,if为0(假),执行else//* C' F9 \& b9 E' v/ N. G1 j: x
  33.                     else                               7 T4 C1 D* j6 N: A3 r1 l& N( W; P
  34.                          {
      ^& r* Z# @7 [% m
  35.                           USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;
    6 A7 N; ?1 K* g% W; q$ D% b/ K: ]
  36.                           USART_RX_STA++;2 D7 t5 }- F) y, _
  37.                               //*若USART_RX_STA值大于所设最大接收字节数,则接收数据错误,重新开始接收*//   
    ( H5 G$ p8 F( r3 r' y
  38.                               if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;                              ( e# S8 M) B$ ~) y% I+ V0 M5 I
  39.                           }
    9 t' T  M- ~* S0 z0 [
  40.                    }
    ; T% F8 u) x; J
  41.            }                  # j" z+ r1 L6 ~, W8 f
  42.      }
复制代码
  m( Z2 w. X$ h# X+ m6 W
上述代码中,变量U16 USART_RX_STA用法如下图所示:
) T( m8 J; y( H8 e2 M. T# b. N; O6 M" I7 ?. j) U/ G9 B
2020040722410483.png # L$ y+ w4 ?& N5 x

) u3 G( w  \; |: _19. main.c文件里主函数代码讲解
$ ?% @: N* ]! a$ U( Q
1 S  T% W; P- n: p; S
  1. int main(void)
    6 y: c0 M: Y, ]! `
  2. {            & K. ]  I2 d& Y& S6 ?& s# y) j
  3.   u16 t;  " r' b( x6 P4 P2 I
  4.   u16 len;    5 w! I- ~, O2 f1 x) A+ `8 \0 ~
  5.   u16 times=0;
    , V" Q+ w+ x7 @# N3 S
  6.   delay_init();                    //*延时函数初始化*//
    3 f. L2 u/ U# }6 `3 b3 i
  7.   //设置NVIC中断分组2:2位抢占优先级,2位响应优先级//2 w9 o& @3 b# Z* u+ y
  8.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);+ Y7 q! I2 h$ y. Y" Z
  9.   uart_init(115200);            //串口初始化为115200//
    ; ]/ {. {- h  R7 Y% q
  10.   LED_Init();                       //LED端口初始化//
    1 v: o! I$ ^! _& p! k1 Z) [
  11.   KEY_Init();               //初始化与按键连接的硬件接口//7 y6 k8 `0 c- H  n
  12.   while(1)3 l: h+ S5 s( r. h+ Z9 f  S
  13.        {3 b2 a& Q4 z; K1 ?" O! c( F
  14.          //*判断USART_RX_STA的位15是否为1*//
    2 y$ {" [& A: n' i1 X( z8 F
  15.          if(USART_RX_STA&0x8000)
    / \% X* p3 M. q0 s3 d' K& w( t! I3 ~
  16.            {     5 M3 ?# y3 q3 a- L6 n
  17.             //*若USART_RX_STA的位15为1*//                          6 g: N( K* B' W, K0 z* X7 ~
  18.             len=USART_RX_STA&0x3fff;        //得到此次接收到的数据长度//
    6 e- A$ O) S; L! h+ w
  19.             printf("\r\n您发送的消息为:\r\n\r\n");
    ; F  _( v" c+ r+ b
  20.             for(t=0;t<len;t++)  D: j7 q$ A* I2 ^' X
  21.                {0 \0 r  L$ q! J, ]2 Z! @- V  v
  22.                   USART_SendData(USART1, USART_RX_BUF[t]);   //向串口1发送第t个数据//) \' S3 _2 L" J
  23.                   //*等待发送结束,USART_FLAG_TC意思是Transmission Complete flag*//
    0 x" b# ^% \: b4 M
  24.                   while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);* ^: m7 l) \( I1 m8 U; h
  25.                 }- u+ l( T' ?+ x
  26.              printf("\r\n\r\n");                                      //插入换行//, p9 a" c4 X) H
  27.                      USART_RX_STA=0;
    0 r9 h8 z9 O- D0 f9 L
  28.            }else
    . x' F- W( T; {/ z" w3 J. `
  29.                 {1 y7 n$ P' o+ C
  30.                 times++;; o9 A" ]- D9 N
  31.                 if(times%5000==0)                                     //*times为5000的整数倍时*//5 {8 F1 Q3 h3 ]1 V
  32.                   {% i# g6 l8 B1 O
  33.                     printf("\r\n战舰STM32开发板 串口实验\r\n");
    , r' k" Q; m5 _6 b& y! h  y
  34.                     printf("正点原子@ALIENTEK\r\n\r\n");
    8 t/ T- i, i* i
  35.                    }; G9 C) j9 |! E- ]3 h
  36.                  if(times%200==0)printf("请输入数据,以回车键结束\n");   //*times为200的整数倍时*//
    4 j) ~, `; n& a* d. P
  37.                      //*times为30的整数倍时,闪烁LED,提示系统正在运行*//
    " G. ^5 |- G% W' W* |8 v7 i9 C1 j
  38.                      if(times%30==0)LED0=!LED0;          ) [8 p0 J3 V% s( m2 F
  39.                      delay_ms(10);   
    7 n- \# ]. j( X  y9 ]8 S5 x4 |
  40.                  }
    & P& ]. U' h1 b: w8 g/ X+ }
  41.            }     
    / Y1 e2 G$ o9 Q* R4 S
  42.   }
复制代码

3 F" V/ ^; M% e1 f20. usart.c里中断服务函数printf()函数代码讲解
1 s+ J% j  w% G/ }( N1 E
" i9 V1 _) m3 _+ _4 N
  1. #if 1
    & M2 n8 B: \3 c0 b( j
  2. #pragma import(__use_no_semihosting)             ; E# I1 ~. ]0 c3 Y# T, G0 d
  3. //标准库需要的支持函数//                 * O' w3 y5 j6 `; p
  4. struct __FILE
    % }. M( ?) ~% w$ T8 Z
  5. { 4 Z8 K8 o2 L' v: d3 I3 n( H
  6.        int handle; / g* P0 N5 F1 I0 k: K1 F" {
  7. };
    % r# t& L  {* k. K" _- u
  8. FILE __stdout;       4 ]; z4 b" w) C' X2 _
  9. //定义_sys_exit()以避免使用半主机模式//   4 L2 r% u+ t0 P; y& v7 j0 u
  10. _sys_exit(int x)# P; K' ~8 D" C0 W
  11. {
    - Z, a3 O5 j2 r7 @
  12.     x = x;
    - y3 M0 r% {8 F6 s9 C$ m
  13. } 4 p! X6 S% E# e5 M3 c/ s5 s' _
  14. //重定义fputc函数//
    5 C- \0 s; N) {7 t. Q8 _
  15. int fputc(int ch, FILE *f)
    + o$ T' x# U7 U
  16. {      
    9 b9 M3 i$ |3 T+ ]) W
  17.     while((USART1->SR&0X40)==0);//循环发送,直到发送完毕//  " z+ q6 n  X7 X0 h) ?
  18.     USART1->DR = (u8) ch;      
    : z0 c+ T& |/ o+ z/ T9 ?, h0 N
  19.     return ch;
    1 F$ H2 d3 _8 r* h' M, _
  20. }
    3 [' {0 I7 F5 S% S& Q) U
  21. #endif; a4 M( N9 {1 Q& ~
  22. //若要对其他串口进行操作,只需将上述代码中的USART1改成USARTx即可。这段代码方便开发过程中查看代码执行情况以及一些变量值,该代码不需要修改,引入到 usart.h 即可//
    ' ~% l* _# Z% C  ~" G
复制代码
+ Q1 R3 S4 y+ G8 p
————————————————
  }. y6 S/ L& A$ z" V1 x+ E1 X版权声明:天亮继续睡! M: G2 ~" f* p8 o

9 A9 [: T" i5 T
. ]; d- n0 a6 |7 {. J; {
202004071435316.png
赞 收藏 评论0 发布时间:2022-11-20 18:08

举报

0个回答

所属标签

相似技术帖

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