Featured image of post 那时我们第一次相遇:USART 1

那时我们第一次相遇:USART 1

Usart通信简易原理图

  • GND 供地是为了平衡电压基准,使得双方共用一套电压标准,用于评判高低电压。
  • Tx :发送数据 Rx:接收数据

数据的串并转换

STM32 的串并转化寄存器

image

  • 寄存器 TDR 实现将并行数据转换为串行数据。
  • 寄存器 RDR 实现串行数据转换为并行数据。

串并数据的详细解释

image

  • 串行数据是指数据以一个接一个的方式在时间上连续传输,也就是说,数据位是按顺序逐个发送的。这种方式通常用于长距离传输,因为它可以减少所需的线缆数量。
  • 并行数据则是指数据的多个位在同一时刻通过多条通道同时传输,这种方式在短距离传输中效率较高,但由于受限于线路数量和信号干扰,通常不适合长距离通信。

STM32_Usart 模块完整示意图

image

状态寄存器(SR)

  • SR 寄存器用于指示 USART 的当前状态,包括是否有数据可接收、发送缓冲区是否为空等。

  • 重要位:

    • RXNE(Receive Data Register Not Empty):接收数据寄存器(RDR)非空,表示有数据接收。
    • TXE(Transmit Data Register Empty):发送数据寄存器(TDR)为空,表示可以发送数据。
    • TC(Transmit Complete):发送完成 TDR空&&移位寄存器空。
    • ORE(Overrun Error):接收溢出错误,表示接收的数据被覆盖。
    • FE(Framing Error):帧错误,表示接收到的帧不正确。
    • PE(Parity Error):奇偶校验错误标志位
    • NE(Noise Error):噪声错误标志位

配置寄存器(CR)

序号 名称 描述
0 UE (USART Enable) 启用 USART 外设,必须设置此位才能开始通信。
1 TE (Transmitter Enable) 启用发送器,允许数据发送。
2 RE (Receiver Enable) 启用接收器,允许数据接收。
3 R/W (Receiver/Transmit) 设置为 1 时,选择到接收模式,设置为 0 时,选择到发送模式。
4 M (Word Length) 数据位长度(0=8 位,1=9 位)。
5 WAKE (Wake-up method) 唤醒选择(0=普通模式,1=地址模式)。
6 PCE (Parity Control) 奇偶校验使能(0=禁用,1=启用)。
7 PS (Parity Selection) 奇偶校验选择(0=偶校验,1=奇校验)。
8 PEIE (PE Interrupt Enable) 奇偶校验错误中断使能。
9 TXEIE (TX Interrupt Enable) 发送数据寄存器空中断使能。
10 RXNEIE (RX Interrupt Enable) 接收数据寄存器非空中断使能。
11 TEIE (Transmission Error Interrupt Enable) 发送错误中断使能。
12 LBDIE (LIN Break Detection Interrupt Enable) LIN 中断使能。
13 CTSIE (CTS Interrupt Enable) 清除发送中断使能。
14 CBM (Character Match) 字符匹配模式(用在 LIN 模式下)。
15 OVER8 (Oversampling) 过采样模式选择(0=16 倍过采样,1=8 倍过采样)。

image

  • CR 寄存器主要用于数据帧的配置,数据帧通常由起始位(1 bit)+ 数据位(8~9 bit)+ 停止位(0.5、1、1.5、2 bit)构成。

  • M - 数据位长度

  • PCE - 奇偶校验使能

  • PS - 奇偶选择

  • STOP - 停止位长度

    • STOP: 00 ~ 1 位
    • STOP: 01 ~ 0.5 位
    • STOP: 10 ~ 2 位
    • STOP: 11 ~ 1.5 位
  • TEX - 发送开关

  • REX - 接收开关

  • UE - Usart 使能

    • UE: 0 Usart 禁止
    • UE: 1 Usart 使能

波特率寄存器(BRR)

波特率的定义

波特率:每秒传输码元的个数

BRR 寄存器位数解释

image

双缓冲与连续发送

双缓冲与连续发送概述

  1. 双缓冲

    • 在 USART 中,双缓冲通常指的是使用两个缓冲区来存储待发送的数据。这样,当一个缓冲区正在发送数据时,另一个缓冲区可以准备下一个发送数据,确保数据的连续性。
    • 例如,一个缓冲区用于存放正在发送的数据,另一个缓冲区用于接收新的数据,避免因发送延迟而导致数据丢失。
  2. 连续发送

    • 连续发送是指在没有人为的干预下,USART 能够不断地从缓冲区中读取数据进行发送。这意味着能够在短时间内快速发送多个数据字节,特别适合于需要实时传输大量数据的应用。
    • 在 STM32F103 中,利用 USART 的发送中断和 DMA(直接内存访问)可以实现高效的连续发送。

STM32F103 双缓冲技术实现

  1. 发送和接收过程中都有着两个缓冲区,第一缓冲区:TDR/RDR 第二缓冲区:移位寄存器

    • 第一层发送缓冲:通过判断 TXE 标志位(TXE=1,TDR 为空,TXE=0,TDR 不为空)来决定是否将数据写入到 TDR 寄存器当中。
    • 第二层发送缓冲:TDR 将数据写入到移位寄存器中,移位寄存器进行串并转换。
    • 第一层接收缓冲:通过判断 RXEN 标志位(RXEN=1,RDR 不为空,RXEN=0,RDR 不为空)来决定是否将数据写入到移位寄存器当中。
    • 第二层发送缓冲:移位寄存器实现串并转换将数据写入到RDR寄存器当中 。
 1//基于寄存器开发的伪代码
 2
 3//数据的单个发送
 4while(TXE:= 0);//等待TDR寄存器为空
 5TDR: data; //将数据写入TDR寄存器当中
 6while(TC==0);//等待全部数据发送完毕
 7//数据的连续发送
 8for(int i=0;i<n;i++)
 9{
10	while(TXE:= 0);
11	TDR: data;
12}
13while(TC==0);
14
15//数据的接收
16while(RXEN:= 0);//当接收移位寄存器没有数据时,代表数据已经完整写入RDR中
17a: RDR; //通过变量读取RDR寄存器中的数据
18//连续接收多个数据
19int arr[MAXSIZE];
20for(int i=0;i<MAXSIZE;i++)
21{
22	while(RXEN:= 0);//当接收移位寄存器没有数据时,代表数据已经完整写入RDR中
23	arr[i]: RDR; //通过变量读取RDR寄存器中的数据
24}

STM32标准库Usart的编程实现

基础5大接口

1void USART_Init();// 初始化(帧格式、波特率)
2void USART_Cmd();// 总开关
3void USART_SendData();//写TDR寄存器
4uint16_t USART_ReceiveData();//读RDR寄存器
5FlagStatus USART_GetFlagStatus();// 读标志位

USART_Init接口

 1// @简介:串口初始化
 2// @参数:USARTx-选择要操作的串口,可以是USART1,USART2,USART3,UART4或USART5
 3// @参数:USART_InitStruct-初始化参数,USART_IinitTypeDef结构体指针类型
 4typedef struct USART_InitTypeDef
 5{
 6  uint32_t USART_BaudRate;            /*!< 此成员配置 USART 通信的波特率。*/
 7                                       
 8  uint16_t USART_WordLength;          /*!< 指定在帧中传输或接收的数据位数。
 9                                           此参数可以是 @ref USART_Word_Length 的一个值 */
10
11  uint16_t USART_StopBits;            /*!< 指定传输的停止位数。
12                                           此参数可以是 @ref USART_Stop_Bits 的一个值 */
13
14  uint16_t USART_Parity;              /*!< 指定奇偶校验模式。
15                                           此参数可以是 @ref USART_Parity 的一个值。
16                                           @note 当启用奇偶校验时,计算出的奇偶校验位会插入到传输数据的最高有效位(当字										   长设置为 9 位数据时为第 9 位;当字长设置为 8 位数据时为第 8 位)。 */
17
18  uint16_t USART_Mode;                /*!< 指定接收或发送模式是否启用或禁用。
19                                           此参数可以是 @ref USART_Mode 的一个值 */
20
21  uint16_t USART_HardwareFlowControl; /*!< 指定硬件流控制模式是否启用或禁用。
22                                           此参数可以是 @ref USART_Hardware_Flow_Control 的一个值 */
23}USART_InitTypeDef;
24
25void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
26
27USART_InitTypeDef USARTInitStruct;//创建结构体变量
28
29//为变量结构体成员赋值
30USARTInitStruct.USART_WordLength= xxx; 
31USARTInitStruct.USART_Parity=xxx;
32USARTInitStruct.USART_StopBits=xxx;
33USARTInitStruct.USART_Mode=xxx;
34USARTInitStruct.USART_BaudRate=xxx; /*!< 此成员配置 USART 通信的波特率。*/
35USARTInitStruct.USART_HardwareFlowControl=xxx;
36
37USART_Init(USARTx,&USARTInitStruct);//调用Init接口

USART_Cmd接口

1// @简介:控制USART总开关的断开和闭合
2// @参数:USARTx-选择要操作的串口,可以是USART1,USART2,USART3,UART4或USART5
3// @参数:NewState-开关状态,ENABLE -闭合,DISABLE -断开
4void USART_Cmd(USART_TypeDef* USARTx, FunctionalStateNewState);
5
6USART_Cmd(USART1, ENABLE); // 闭合USART1开关
7USART_Cmd(USART1, DISABLE); // 断开USART1开关

USART_SendData接口

1// @简介:向TDR写数据
2// @参数:USARTx-选择要操作的串口,可以是USART1,USART2,USART3,UART4或USART5
3// @参数:Data -要写入的数据
4void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
5
6USART_SendData(USART1, 0x5a); // 发送0x5a

USART_ReceiveData接口

1// @简介:从RDR读取数据
2// @参数:USARTx-选择要操作的串口,可以是USART1,USART2,USART3,UART4或USART5
3// @返回值:读取到的数据
4uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
5
6uint8_t a: USART_ReceiveData(USART1);

USART_GetFlagStatus接口

 1// @简介:向TDR写数据
 2// @参数:USARTx-选择要操作的串口,可以是USART1,USART2,USART3,UART4或USART5
 3// @参数:USART_Flag-标志位名称。
 4//可以是USART_FLAG_TXE,USART_FLAG_RXNE,USART_FLAG_ORE,USART_FLAG_TC,USART_FLAG_PE,
 5//USART_FLAG_PE,USART_FLAG_FE,USART_FLAG_NE
 6// @返回值:标志位状态,SET -1, RESET -0
 7FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_Flag);
 8while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
 9while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
10if(USART_GetFlagStatus(USART1,USART_FLAG_PE)==SET){}