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

STM32 串口详解

[复制链接]
STMCU小助手 发布时间:2021-2-2 09:45
STM32 串口详解
1.     USART的特点
USART是通用异步收发传输器(UniversalAsynchronousReceiver/Transmitter),通常称作UART,是一种异步收发传输器,是设备间进行异步通信的关键模块。UART负责处理数据总线和串行口之间的串/并、并/串转换,并规定了帧格式;通信双方只要采用相同的帧格式和波特率,就能在未共享时钟信号的情况下,仅用两根信号线(Rx和Tx)就可以完成通信过程,因此也称为异步串行通信。

# A" b  B( f4 p# T) K
(1)    全双工异步通信。
(2)    小数波特率发生器系统,提供精确的波特率。
(3)    可配置的16倍过采样或8倍过采样,因而为速度容差与时钟容差的灵活配置提供了可能。
(4)    可编程的数据字长度(8位或者9位);
(5)    可配置的停止位(支持1或者2位停止位);
(6)    可配置的使用DMA多缓冲器通信。
(7)    单独的发送器和接收器使能位。
(8)    检测标志:①接受缓冲器  ②发送缓冲器空 ③传输结束标志
(9)    多个带标志的中断源。触发中断。
(10)  其他:校验控制,四个错误检测标志。

6 Y8 _! C& ~/ x6 |4 Y; G
通信结构
1.1.png
( B( p  ^( j4 A" v+ o
2.     USART简介
2.1、数据传输模型
1.2.png
- L' g) @- V, X2 {$ m
2.2、帧结构
串口异步通信需要定义的参数
① 起始位
② 数据位(8位或者9位)
③ 奇偶校验位(第9位)
④ 停止位(1,15,2位)
⑤ 波特率设置
带奇偶校验的数据为就是9位
1.3.png
( J7 S3 h3 Y% T6 {- D
(1)   数据包
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。
9 Q8 x1 Y) k9 d
(2)   波特率
由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。

& y. I- A- n$ k' I& X% W
(3)   起始和停止信号
数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。
+ [  i/ h2 p1 F' h2 F& }0 q) \
(4)   有效数据
有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
  W8 K! }4 A( {/ ^# X! M7 g
(5)   数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。
  y: E2 J, `# g; ~4 W
2.3、波特率
1.4.png
$ Z3 Z/ S4 [  n* _& t0 e+ o+ W
OVER8,用于配置过采样,通常情况下,OVER8设置为0。
1.5.png
4 n, h/ z# b" ^- z+ ]
如果时钟时84M
USARTDIV = 84000000/(115200*16) = 45.572
那么得到:
DIV_Fraction = 16*0.572 = 0x09;
DIV_Mantissa = 45 = 0x2D;
8 D8 Q; C6 \2 U  {, F
3.     STM32的USART
根据STM32F207数据手册,STM32F207一共6个串口
1.6.png
( `5 t# n% _1 L) w" j. x5 f2 Y
下文我们以USART1为例讲解
从STM32F207数据手册的Table10.Alternate functionmapping图中看到USART1的对应管脚,下文我们选择PA9和PA10作为USART1的管脚。
1.7.png

! P1 ?3 w/ l$ d& p# Z2 ]$ k, U1 m
4.     代码配置
配置中断优先级。
  1. /* Enable the USARTx Interrupt */  l9 A- z; Z5 D) _5 o
  2.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;: `9 i# q( d% R" B& q+ y# h
  3.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;5 A. q5 F4 n8 c0 y
  4.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    % k+ A4 h0 O8 k
  5.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    1 r4 B- G  T1 L8 m, C  U
  6.   NVIC_Init(&NVIC_InitStructure);
复制代码

* x: m$ o* \4 e6 ~5 \7 N* o/ E
打开串口与相应的GPIO引脚,配置好相应串口信息与GPIO引脚的工作模式。
  1. /* Enable GPIO clock */5 r6 p: s/ ~2 w
  2.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);* h. r! P' t1 }% v, ~# G% B$ W* v) O
  3.   /* Enable UART1 clock */
    6 i# ~  C7 k2 A/ B
  4.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);; d1 ~4 a# D' s1 e; D. P5 Z
  5.   /* Connect PXx to USARTx_Tx*/* g2 {$ C7 l" P
  6.   GPIO_PinAFConfig(GPIOA, 9, GPIO_AF_USART1);
    1 z2 ^& A9 T" N
  7.   
    . y( q) F" Z7 s& z( D4 F# m- @: c
  8.   /* Connect PXx to USARTx_Rx*/! a( o& M5 Z0 b: w+ P  U5 R. V! p
  9.   GPIO_PinAFConfig(GPIOA, 10, GPIO_AF_USART1);6 ?) l) c# ^: y' e+ b+ P! t
  10.   ' H, O/ [7 g7 }% \% m
  11.   /* Configure USART Tx as alternate function  */
    7 ~$ v2 T" j6 Y9 }2 s
  12.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    6 n9 R% \  T: C& `; o7 i/ D
  13.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    * Q& V( H! G0 N* b/ m& L( b/ j% o
  14.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    + I+ s# X& R# }# o
  15.   2 f) v7 p5 u/ J7 _
  16.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    ' t4 f1 x3 ^) G  s, r% K: K
  17.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    . \) q8 g2 x+ f0 ~, c4 [# ]
  18.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    1 X; `+ z% w/ u; ]5 {" T1 A0 J
  19.   
    0 [' A: t; l2 d. C) ]
  20.   /* Configure USART Rx as alternate function  */
      p3 {  `4 J) [5 c% Q
  21.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    0 Z, _; `6 w# |! s
  22.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;6 t& p6 ^% G( x! `) c" {
  23.   GPIO_Init(GPIOA, &GPIO_InitStructure);
复制代码
& K' U& M1 }1 O+ g
配置USART1。
  1. USART_InitStructure.USART_BaudRate = 115200;//配置波特率
    ' M: P% b* T% t8 Z/ @& x
  2.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;//配置数据字长; K7 N5 u' {, b
  3.   USART_InitStructure.USART_StopBits = USART_StopBits_1;//配置停止位
    1 c8 m3 y" X; u
  4.   USART_InitStructure.USART_Parity = USART_Parity_No;//配置校验位
    : Z3 ^6 z# \+ p8 F% U" _7 y3 \
  5.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//配置硬件流控制
    " U3 \, P6 O+ A* H
  6.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//配置工作模式,收发一起) l. e) L6 X$ U7 u: F3 z
  7.   
    / H2 I' ]( Y3 |7 C. z* _
  8.   /* USART configuration */' ?% I  j6 ]$ x9 @0 D
  9.   USART_Init(USART1, &USART_InitStructure);// 完成串口的初始化配置
复制代码

* T/ v3 Y' m0 x3 W6 g  N) l  u
使能中断配置。
  1. USART_ITConfig(USART1, USART_IT_TC, ENABLE);/ v& K; D) i" G0 N* ~9 i- f% s
  2.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)
复制代码
  D* E5 o/ p# o) i# M- `8 N
我们配置了发送传输完成中断和接收数据寄存器非空中断。我们可以配置很多类型中断,在ST提供的标准库函数中看到。
  1. /**  [, H  z3 s% R7 x0 v0 ?3 [2 O
  2.   * @brief  Enables or disables the specified USART interrupts.! Z' ~. ?) E7 E2 L7 k& c
  3.   * @param  USARTx: where x can be 1, 2, 3, 4, 5 or 6 to select the USART or ' j+ p4 n7 R8 ~) C# H9 l
  4.   *         UART peripheral.3 `& ~# _# Q0 l& E3 m( ^
  5.   * @param  USART_IT: specifies the USART interrupt sources to be enabled or disabled.
    3 s* c, e2 X- {) c% W: p
  6.   *          This parameter can be one of the following values:, N  r6 V) _5 C5 e  m6 w/ n
  7.   *            @arg USART_IT_CTS:  CTS change interrupt
      b2 s' k  M2 }2 X/ n2 K/ ?
  8.   *            @arg USART_IT_LBD:  LIN Break detection interrupt+ T/ n3 q2 P- [6 t* t
  9.   *            @arg USART_IT_TXE:  Transmit Data Register empty interrupt- R1 D  G. F! J, q; o" m
  10.   *            @arg USART_IT_TC:   Transmission complete interrupt
    : |- p  q% {2 f5 S
  11.   *            @arg USART_IT_RXNE: Receive Data register not empty interrupt* Z  M! [" _* U/ ]: x
  12.   *            @arg USART_IT_IDLE: Idle line detection interrupt5 d4 }! C' T& a% p3 {
  13.   *            @arg USART_IT_PE:   Parity Error interrupt# N: ~4 g: x: F' K9 P& S, f
  14.   *            @arg USART_IT_ERR:  Error interrupt(Frame error, noise error, overrun error)6 o+ g& h4 F8 G# t& _7 i$ E6 c
  15.   * @param  NewState: new state of the specified USARTx interrupts.
    7 c3 A2 E. Q: A+ R; J
  16.   *          This parameter can be: ENABLE or DISABLE.( n1 L) X/ b  k% c
  17.   * @retval None7 k7 ^, ^$ N& M, N$ q! P
  18.   */
复制代码

+ v0 ~& M8 Y1 B/ Y: W2 ?! P
最后使能串口。
  1. /* Enable USART */0 N3 j, G. g: i5 _' ^
  2.   USART_Cmd(USART1, ENABLE);
复制代码
- y, J9 h( P, D8 I/ T
main主函数,功能是LCD显示串口接收的10个字符(如果不是ascii码则不显示),串口倒序返回接收到的10个字节。
  1. int main(void)% s) G+ F8 t2 c7 B
  2. {* G# ]3 q' c- ~  s8 {% I
  3.   while (1)# f) K4 |6 ]+ f6 e
  4.   {
    . q2 }. Q0 O" S- y
  5.     if(LCD_refresh_flg){
    # B$ a  ^9 E8 I9 [) u
  6.       LCD_refresh_flg = 0;
    4 k+ l% k6 R' I) K: U  C7 ^& x5 M. b
  7.       LCD_ShowString(0,16,receive_data);
    " X. p' C/ ~* D$ n2 h$ u1 s
  8.       receive_num--;# C& K2 \* ]: e2 c6 g
  9.       USART_SendData(USART1, receive_data[receive_num--]);
    * V: [3 Z+ P4 s: j
  10.       send_flg = 1;
    , u- ^5 X  ~1 D* H  K. }  m" S
  11.     }( t9 N7 M' d$ B( a
  12.   }
    : Q% |% C2 w+ \' ^6 P/ C, M: [) D
  13. }
复制代码
+ d# b! R9 _9 j, I/ X3 k
因为使能了中断,我们还需要编写中断函数。
  1. void USART1_IRQHandler(void)
    5 G% o! y; {: Z7 }+ w. T
  2. {
    ) O/ E3 |0 g3 k2 I) y. o& J
  3.   if(USART_GetFlagStatus(USART1, USART_FLAG_TC))" g  X' r/ u* B* D
  4.   {
    & I( z- c9 }7 P$ ]. e
  5.     if(send_flg == 1){+ y; l* B8 o/ H4 B3 g% d2 `/ W
  6.       if(receive_num==0){
    * e9 K9 ~; k" M% D3 B) x6 o6 M, [- V- R
  7.         USART_SendData(USART1, receive_data[receive_num]);) a5 }- W; l5 y4 a
  8.         send_flg = 0;% X& {# E( |- x# J2 J: N8 J: W# _
  9.         receive_flg = 1;
    ! @+ J( H- O' K2 w' p
  10.       }else{5 C* S- V8 ^: X
  11.         USART_SendData(USART1, receive_data[receive_num--]);8 b; e0 z% X3 Y
  12.       }
    3 @; o+ S' L- D0 P% i
  13.     }
    # I" U3 F7 v' `2 Y! q  H% F
  14.     USART_ClearFlag(USART1, USART_FLAG_TC);
    2 ?9 Z$ Q4 e1 y5 P: w' Z
  15.   }, Z* L* N( l' m1 g
  16.   if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
    % t, T1 W: C" _& j% N/ a% q- I6 z7 H. F
  17.   {
    ) x5 o. t& I2 a: e2 |- F$ z. y
  18.     if((receive_flg)&&(send_flg == 0)){
    $ S' f: l* R) ~5 {
  19.       receive_data[receive_num++] = USART_ReceiveData(USART1);
    % U9 d4 y& Z+ K7 Z* s' `
  20.       if(receive_num==10){" j) o' P; @9 }7 H7 f0 m4 s
  21.         receive_flg = 0;
    0 I) f  W! H% T. I! P! O: l1 v
  22.         LCD_refresh_flg = 1;
    % G2 A, ^" A5 L+ \- `0 n& y
  23.       }
    , s; x1 H+ C+ f; e% L
  24.     }
    ' ~& P/ K8 f: b1 {9 ^1 r/ ~
  25.     USART_ClearFlag(USART1, USART_FLAG_RXNE);
    8 X8 j9 m4 U% Q- Z. w
  26.   }
    " ]  w! V% C) Y
  27. }
复制代码
7 r- @. V/ T( H+ V! H. N4 r
下载验证
LCD显示屏可以显示接收的10个字符,且PC以100ms为间隔发送数据,发送977包收到977包回复,测试demo就够健壮,没有出现丢包。
1.8.png

; ]+ C* D9 x0 R2 n
PCB和工程代码开源地址:https://github.com/strongercjd/STM32F207VCT6
; J0 F% D9 l2 V; m5 N3 a
文章出处: 知晓编程
6 y5 y- Z2 K: u4 ^, t; H$ N, T
收藏 评论0 发布时间:2021-2-2 09:45

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版