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

【经验分享】基于STM32之UART串口通信协议(一)详解

[复制链接]
STMCU小助手 发布时间:2022-1-13 20:53
一、前言1、简介
  写的这篇博客,是为了简单讲解一下UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作,在后面我会以我使用的STM32F429开发板来举例讲解(其他STM32系列芯片大多数都可以按照这些步骤来操作的),如有不足请多多指教。
2、UART简介
  嵌入式开发中,UART串口通信协议是我们常用的通信协议(UART、I2C、SPI等)之一,全称叫做通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)。
3、准备工作1)Keil5
. t7 s% E; }8 B% ~' @; p2)STMCubeMX5.1.0版本
6 S: |% e* l4 g5 O3)STMF429开发板
  
/ n# b0 h3 x2 h  p# o  _

/ c) K1 I) W1 v$ h+ E
注:
  只要是stm32的开发板都可以用到的,在STM32CubeMx里选对型号、配置好就行了。
二、UART详解0 b% C* r6 \+ t0 J) U* [4 M
1、UART简介
  嵌入式开发中,UART串口通信协议是我们常用的通信协议(UART、I2C、SPI等)之一,全称叫做通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输,它能将要传输的资料在串行通信与并行通信之间加以转换,能够灵活地与外部设备进行全双工数据交换。
注:
  在此开发板中,是有USART(Universal Synchronous Asynchronous Receiver and Transmitter通用同步异步收发器)串口的,USART相当于UART的升级版,USART支持同步模式,因此USART 需要同步始终信号USART_CK(如STM32 单片机),通常情况同步信号很少使用,因此一般的单片机UART和USART使用方式是一样的,都使用异步模式。因为USART的使用方法上跟UART基本相同,所以在此就以UART来讲该通信协议了。
2、UART通信协议( L6 \; K4 g$ r/ n( ?, M% @3 e. O8 |
1545553-20190503191826863-1694313472.png

2 @1 }) G3 U( h' W$ o3 |
1)起始位
  当未有数据发送时,数据线处于逻辑“1”状态;先发出一个逻辑“0”信号,表示开始传输字符。
2)数据位
  紧接着起始位之后。资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。
3)奇偶校验位
  资料为加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验资料传送的正确性。
4)停止位
  它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
5)空闲位或起始位
  处于逻辑“1”状态,表示当前线路上没有资料传送,进入空闲状态。
  处于逻辑“0”状态,表示开始传送下一数据段。
6)波特率
  表示每秒钟传送的码元符号的个数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示。
  常用的波特率有:9600、115200……
  时间间隔计算:1秒除以波特率得出的时间,例如,波特率为9600的时间间隔为1s / 9600(波特率) = 104us。
3、UART功能说明
  接口通过三个引脚从外部连接到其它设备。任何 USART 双向通信均需要 至少两个引脚:接收数据输入引脚 (RX) 和发送数据引脚输出 (TX):
4 G0 b0 |& B. L8 {- F  RX:接收数据输入引脚就是串行数据输入引脚。过采样技术可区分有效输入数据和噪声,从而用于恢复数据。, p8 U' H6 @* ]* r8 ~
  TX:发送数据输出引脚。如果关闭发送器,该输出引脚模式由其 I/O 端口配置决定。如果使 能了发送器但没有待发送的数据,则 TX 引脚处于高电平。在单线和智能卡模式下,该 I/O 用于发送和接收数据(USART 电平下,随后在 SW_RX 上接收数据)。
1)正常 USART 模式下,通过这些引脚以帧的形式发送和接收串行数据:
  • 发送或接收前保持空闲线路
  • 起始位
  • 数据(字长 8 位或 9 位),最低有效位在前
  • 用于指示帧传输已完成的 0.5 个、1 个、1.5 个、2 个停止位
  • 该接口使用小数波特率发生器 - 带 12 位尾数和 4 位小数
  • 状态寄存器 (USART_SR)
  • 数据寄存器 (USART_DR)
  • 波特率寄存器 (USART_BRR) - 12 位尾数和 4 位小数。
  • 智能卡模式下的保护时间寄存器 (USART_GTPR)。
    % J2 y9 H/ I/ |% `8 U$ Y
    # r$ |, o6 ~2 i3 t; ?- Q6 v7 s
2)在同步模式下连接时需要以下引脚:
  • SCLK:发送器时钟输出。该引脚用于输出发送器数据时钟,以便按照 SPI 主模式进行同步发送(起始位和结束位上无时钟脉冲,可通过软件向最后一个数据位发送时钟脉冲)。RX 上可同步接收并行数据。这一点可用于控制带移位寄存器的外设(如 LCD 驱动器)。时钟相位和极性可通过软件编程。在智能卡模式下,SCLK 可向智能卡提供时钟。在硬件流控制模式下需要以下引脚:
    6 \( h& q0 E6 g' T+ `; C% j: c  b
    3 [2 a2 V, ?1 c3 O& ?* m: n. N/ u1 t
  • nCTS:“清除以发送”用于在当前传输结束时阻止数据发送(高电平时)。
  • nRTS:“请求以发送”用于指示 USART 已准备好接收数据(低电平时)。
    % y3 p+ I! E* R& i& h

    ! l) U+ @3 y3 |" y! t/ B/ f
USART框图如下:7 E) n5 x- B. h- l
. z, u. ~- i' R* N
1545553-20190503200746476-1202727130.png
5 M- a/ H$ S, H3 u( h* T
4、UART工作原理1)发送接收  发送逻辑对从发送FIFO 读取的数据执行“并→串”转换。控制逻辑输出起始位在先的串行位流,并且根据控制寄存器中已编程的配置,后面紧跟着数据位(注意:最低位 LSB 先输出)、奇偶校验位和停止位。
& e* b3 ^. }4 j% n6 {1 {9 A  在检测到一个有效的起始脉冲后,接收逻辑对接收到的位流执行“串→并”转换。此外还会对溢出错误、奇偶校验错误、帧错误和线中止(line-break)错误进行检测,并将检测到的状态附加到被写入接收FIFO 的数据中。6 r. H% _( Z0 K% G: j8 `  a! I! m
2)波特率产生
  波特率除数(baud-rate divisor)是一个22 位数,它由16 位整数和6 位小数组成。波特率发生器使用这两个值组成的数字来决定位周期。通过带有小数波特率的除法器,在足够高的系统时钟速率下,UART 可以产生所有标准的波特率,而误差很小。
3)数据收发
  发送时,数据被写入发送FIFO。如果UART 被使能,则会按照预先设置好的参数(波特率、数据位、停止位、校验位等)开始发送数据,一直到发送FIFO 中没有数据。一旦向发送FIFO 写数据(如果FIFO 未空),UART 的忙标志位BUSY 就有效,并且在发送数据期间一直保持有效。BUSY 位仅在发送FIFO 为空,且已从移位寄存器发送最后一个字符,包括停止位时才变无效。即 UART 不再使能,它也可以指示忙状态。
  在UART 接收器空闲时,如果数据输入变成“低电平”,即接收到了起始位,则接收计数器开始运行,并且数据在Baud16 的第8 个周期被采样。如果Rx 在Baud16 的第8 周期仍然为低电平,则起始位有效,否则会被认为是错误的起始位并将其忽略。
  如果起始位有效,则根据数据字符被编程的长度,在 Baud16 的每第 16 个周期(即一个位周期之后)对连续的数据位进行采样。如果奇偶校验模式使能,则还会检测奇偶校验位。
+ x5 `  c6 ?- [. X" ^  最后,如果Rx 为高电平,则有效的停止位被确认,否则发生帧错误。当接收到一个完整的字符时,将数据存放在接收FIFO 中。. }0 C$ h# J0 E' @6 \0 U
4)中断控制
  出现以下情况时,可使UART 产生中断:
  • FIFO 溢出错误
    6 U1 ~/ A/ |7 C  @5 s) ^
  • 线中止错误(line-break,即Rx 信号一直为0 的状态,包括校验位和停止位在内)
    6 g, V. }; ^! f$ p4 m9 w
  • 奇偶校验错误* m- S% l1 C9 d3 z6 D+ C
  • 帧错误(停止位不为1)8 c: M5 p* b3 v3 E
  • 接收超时(接收FIFO 已有数据但未满,而后续数据长时间不来)
    * J: j. [$ V' [+ u- [& `7 G
  • 发送2 D0 V5 U% w  L. P0 L0 m/ U
  • 接收
    ! x' r9 h3 u% E: r/ M
  由于所有中断事件在发送到中断控制器之前会一起进行“或运算”操作,所以任意时刻 UART 只能向中断产生一个中断请求。通过查询中断状态函数,软件可以在同一个中断服务函数里处理多个中断事件(多个并列的if 语句)。
5)FIFO 操作
  FIFO 是“First-In First-Out”的缩写,意为“先进先出”,是一种常见的队列操作。 Stellaris 系列ARM 的UART 模块包含有2 个16 字节的FIFO:一个用于发送,另一个用于接收。可以将两个FIFO 分别配置为以不同深度触发中断。可供选择的配置包括:1/8、 1/4、1/2、3/4 和7/8 深度。例如,如果接收FIFO 选择1/4,则在UART 接收到4 个数据时产生接收中断。
  发送FIFO的基本工作过程: 只要有数据填充到发送FIFO 里,就会立即启动发送过程。由于发送本身是个相对缓慢的过程,因此在发送的同时其它需要发送的数据还可以继续填充到发送 FIFO 里。当发送 FIFO 被填满时就不能再继续填充了,否则会造成数据丢失,此时只能等待。这个等待并不会很久,以9600 的波特率为例,等待出现一个空位的时间在1ms 上下。发送 FIFO 会按照填入数据的先后顺序把数据一个个发送出去,直到发送 FIFO 全空时为止。已发送完毕的数据会被自动清除,在发送FIFO 里同时会多出一个空位。
3 }. G5 p) Z# L) I! ?  接收FIFO的基本工作过程: 当硬件逻辑接收到数据时,就会往接收FIFO 里填充接收到的数据。程序应当及时取走这些数据,数据被取走也是在接收FIFO 里被自动删除的过程,因此在接收 FIFO 里同时会多出一个空位。如果在接收 FIFO 里的数据未被及时取走而造成接收FIFO 已满,则以后再接收到数据时因无空位可以填充而造成数据丢失。& K% K* Z! b4 ^
  收发FIFO 主要是为了解决UART 收发中断过于频繁而导致CPU 效率不高的问题而引入的。在进行 UART 通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发 FIFO,则每收发一个数据都要中断处理一次,效率仍然不够高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14 个)后才产生一次中断然后一并处理,这就大大提高了收发效率。% k0 r: y- }1 r% n& ]  w
  完全不必要担心FIFO 机制可能带来的数据丢失或得不到及时处理的问题,因为它已经帮你想到了收发过程中存在的任何问题,只要在初始化配置UART 后,就可以放心收发了, FIFO 和中断例程会自动搞定一切。0 q4 n( e) S/ J
6)回环操作
  UART 可以进入一个内部回环(Loopback)模式,用于诊断或调试。在回环模式下,从Tx 上发送的数据将被Rx 输入端接收。
三、CubeMx配置
说明:
  在使用STM32CubeMx配置的时候,首先要选择正在使用的芯片的型号,再配置芯片的时钟,然后才去配置所需要用到的功能。
1、新建项目, b* T( E0 G7 z: u
1)选择新建
  J9 s1 i. o: X* j9 |8 B  e/ H 1545553-20190430105236070-1164917135.png
2)选择芯片型号' [% r+ l; z' e% {- x. b
1545553-20190430105744777-331178679.png
2、时钟配置
6 n% s- W5 ^( Y  f1)配置界面
  P+ y/ e! w& g* Y* ~6 V, f2 K 1545553-20190430110326398-350737939.png
2)时钟模式配置
) u- P" }2 x0 k8 g 1545553-20190430110649413-884731017.png
3)设置调试接口+ K0 o8 _& x1 M4 t9 z; r
1545553-20190430111908943-481093766.png
4)时钟配置(尽量将下面方框内的值设成最高值即可)
# C7 q/ U) `! Z0 k! F! G! E5 j 1545553-20190430112847550-168090184.png
' G6 V$ m0 M3 O+ ?8 F
3、功能配置
& ^/ h, d2 A3 `9 `, ?2 J 1)启用串口# |; ~  `0 x. r8 W3 {
1545553-20190430113227671-736499631.png
2)配置串口(默认即可,波特率为115200)
: p# l5 ~$ V0 f0 T9 U6 h' t4 e 1545553-20190430113513365-482313513.png
4、生成工程
" l/ D$ Y0 M4 M1)项目信息设置
2 B1 Z+ i/ j' k( M 1545553-20190430114137417-478418310.png
2)选择生成必要的代码
8 X7 Y* E+ V/ w0 x 1545553-20190430114329861-1909888479.png
3)生成代码, i6 {' n7 f( f5 P
1545553-20190430114551087-1240427520.png
4)打开项目(生成代码成功后会弹出窗口,可以直接打开工程)" D6 h. M9 r8 \* F1 M& D
1545553-20190430114641714-1781152243.png
注:
  因为STM32CubeMX自动生成的代码中,没有设置把每次下载烧写都重置一下,所以生成代码后,我们需要自己选上该功能,步骤如下:
1)功能界面
1545553-20190504145128554-1188623726.png
2)选择小锤子
1545553-20190504145528204-1318000177.png
3)选择Debug->Settings
1545553-20190504145612952-1331411380.png
4)选择Flash Download->勾选Reset and Run
1545553-20190504145804671-691413611.png
  完成上面的操作后,在每次烧写都会重置,并运行新下载烧写的程序了。
四、HAL库关键函数说明" E" M0 H  O# s
1、初始化/还原初始化函数
+ K7 b, j) z3 d6 Y9 |4 O* H
  1. 1 /* Initialization/de-initialization functions  **********************************/
    % q  K. d7 Z1 G! u) x+ y, i% a
  2. 2 HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);                                                    //根据UART_InitTypeDef中指定的参数初始化UART模式,并创建关联的句柄。" s: d' ]8 L* O! G+ S
  3. 3 HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart);                                              //根据UART_InitTypeDef中指定的参数初始化半双工模式并创建关联句柄。
    6 ?# w! Q; i- R$ H
  4. 4 HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength);                         //根据UART_InitTypeDef中指定的参数初始化LIN模式,并创建关联的句柄。
    % I7 D1 j  t) i; x/ L) I
  5. 5 HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod);  //根据UART_InitTypeDef中指定的参数初始化多处理器模式,并创建关联的句柄。
    " Q8 l" h5 W" Z2 o" A
  6. 6 HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *huart);                                                  //非初始化UART外围设备。. Q0 F) U! P8 ^: X+ F4 N: I
  7. 7 void HAL_UART_MspInit(UART_HandleTypeDef *huart);                                                              //弱函数UART MSP初始化
    0 f; L$ t0 [4 t0 Y' w9 w
  8. 8 void HAL_UART_MspDeInit(UART_HandleTypeDef *huart);     
复制代码
4 C" Q" ?& V+ {+ g6 E+ m
2、IO口操作函数* \9 W2 l6 C; r( f7 c5 f- t
  1. 1 /* IO operation functions *******************************************************/9 A7 B* p3 h- e" ?0 Z1 f3 [  ~
  2. 2 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);//以阻塞模式发送大量数据。  n: t1 h( f" a# z+ {
  3. 3 HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); //在阻塞模式下接收大量数据。
    5 F% ?9 p3 U7 L. w6 l
  4. 4 HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);               //以非阻塞模式发送大量数据。
    : r+ W3 y8 P& A. c/ g: f
  5. 5 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);                //在非阻塞模式下接收大量数据。# \1 q# g8 @+ R1 M3 p
  6. 6 HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);              //以非阻塞模式发送大量数据。
    + V5 ], R1 z0 }2 v9 f
  7. 7 HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);               //在非阻塞模式下接收大量数据。7 j) i# N" c) e
  8. 8 HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart);                                                 //暂停DMA传输。
    6 o# k- m4 a& P5 f
  9. 9 HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart);                                                //恢复DMA传输。+ {1 U5 a$ x" x9 V" k* K" b
  10. 10 HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart);   
复制代码
; k- S( o6 ?+ {& L' U* k/ g
3、传输中断函数4 v! i" ~. s" S' S% V2 l8 N# W6 F( z
  1. 1 /* Transfer Abort functions */% _  q8 w$ ?: y1 ~2 f
  2. 2 HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart);            //中止正在进行的传输(阻塞模式)。4 a7 c! e% Y, X" _5 `- D
  3. 3 HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart);    //中止正在进行的传输传输(阻塞模式)。0 v4 F+ }0 \8 i& m+ g
  4. 4 HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart);     //中止正在进行的接收传输(阻塞模式)。
    , d" N0 D, `; ?1 z  n. j
  5. 5 HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart);         //中止正在进行的传输(中断模式)。
      K) `1 _. p5 j8 B  X
  6. 6 HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart); //中止正在进行的传输(中断模式)。
    : Z: t1 D$ d) d: I( J) d0 d) x
  7. 7 HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart);  //中止正在进行的接收传输(中断模式)。
复制代码
; O0 v1 d) b9 S8 m  H0 m+ i+ M8 ~: n
4、中断处理及回调函数" d: d/ O5 V& M/ u7 A) Z: S, t
  1. 1 void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);                    //函数处理UART中断请求。9 d" g; ^5 G% T3 a2 G4 |
  2. 2 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);                //Tx传输完成回调函数。
    & l# _6 w) t& j0 }
  3. 3 void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);            //Tx半传输完成回调函数。
    : ]2 y# I% ^; h$ r/ M
  4. 4 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);                //Rx传输完成回调函数。
    7 x1 k3 Z) o9 o4 j5 e1 m& E
  5. 5 void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);            //Rx完成一半传输回调函数。
    ( Q1 o% d: z! [8 l# v
  6. 6 void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);                 //UART错误回调函数。
    4 i- u+ l0 [& e. |" z( o& S
  7. 7 void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart);             //UART中止完成回调函数。
    $ T3 x' ^6 U' m: B8 |
  8. 8 void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart);     //UART中止完成回调函数。
    + U: Z/ h; F3 N! R) T
  9. 9 void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart);      //UART中止接收完整的回调函数。
复制代码

, ?2 a  j( H  Y, N
& ^% l+ |: p/ P& G 五、结尾
4 w+ g+ {6 Z7 W: F& l% T; b; e
1、总结
  这篇博客主要是讲解一下UART串口通信协议的时序、功能以及工作原理,还有使用STM32CubeMX来配置USART。而还未讲到有关HAL库函数的函数调用,有了STM32CubeMX生成的这个HAL库函数,我们基本不用管协议上的事情了,可以直接调用里面的发送或接收函数来实现UART通信。而我也会在后续继续编写有关HAL库的调用说明,详细说一下HAL库是如何使用的。
! m- j% V( ?! [+ {2 L+ o) R# u
2 F5 q- k% b  {  k

# B2 b7 z, u( [  c  P2 \
1545553-20190504153423351-1993897271.png
赞 收藏 评论0 发布时间:2022-1-13 20:53

举报

0个回答

所属标签

相似技术帖

官网相关资源

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