【通信协议系列】USART串口通讯协议

一、USART的基本概念

1.1 简介

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步接收器和发送器 ,支持全双工通信,即可以同时发送和接收数据。与UART(通用异步收发器)相比,USART不仅支持异步通信,还支持同步通信模式。

USART具有以下特点:

  • 全双工/半双工:支持同时发送和接收数据。

  • 异步通信:无需时钟同步,通过波特率和起始/停止位实现。

  • 硬件流控制:支持RTS/CTS控制数据流。

  • DMA支持:提高数据传输效率。

1.2 USART和UART的区别

特性UARTUSART
通信模式仅支持异步通信支持同步和异步两种模式
时钟信号无需外部时钟,依赖预定义的波特率同步模式需外部时钟(SCLK引脚)
硬件复杂度较简单更复杂(额外支持同步逻辑)
应用场景简单设备(传感器、蓝牙模块等)高速/时序严格的场景(智能卡、SPI兼容设备等)

1.2.1异步模式(两者均支持)

  • 工作原理

    通过起始位(Start Bit)停止位(Stop Bit) 界定数据帧。

    双方需约定相同的波特率(如9600、115200bps)。

    无需共享时钟,通信双方独立计时。

1.2.2 同步模式(仅USART支持)

  • 工作原理

    通过共享时钟信号(SCLK) 同步数据传输。

    发送方在时钟边沿(上升沿/下降沿)输出数据,接收方同步采样。

  • 优势

    速率更高(时钟直接驱动,无波特率误差问题)。

    时序更精确,抗干扰能力更强。

1.2.3 STM32中的实现差异

  • UART模式

    • 仅使用TX(发送)、RX(接收)引脚。

    • 寄存器配置关闭同步相关功能(如USART_CR2中的CLKEN)。

  • USART同步模式

    • 启用SCLK引脚输出时钟(通过USART_CR2CLKEN位控制)。

    • 需配置时钟极性(CPOL)和相位(CPHA),类似SPI。

二、USART硬件结构

2.1 硬件电路

USRT框图

2.1.1 发送器

TDR(发送数据寄存器)中的数据已转移到发送移位寄存器,则会设置标志位TXE = 1(发送寄存器空),表示可以向TDR(发送数据寄存器)写入新数据了。

发送移位寄存器会在发送器控制的驱动下,向右移位,将数据低位先行的方式,把数据一位一位的发送到TX引脚。

2.1.2 接收器

数据从RX引脚上来,在接收器控制下,数据一位一位的接收,向右移,移位八次之后,就是接收了一位字节。单字节完成接收之后,数据整体的会传到RDR(接受数据寄存器)

数据转移完之后,会置一个标志位RXNE = 1(接收数据寄存器非空),此时此刻就可以吧RDR的数据读走了。

发送接收的时候内部的硬件电路会自动剔除帧头帧尾,所以我们发送接手的时候还是要带帧头帧尾的。

2.1.3 控制逻辑

当发送设备发的太快,接收设备来不及处理,会出现丢弃或覆盖数据的情况,流控就会发挥作用了。

有两个引脚(n的意思是低电平有效):

nRTS(Request To Send):请求接收,输入引脚

nCTS(Clear To Send):请求发送,输出引脚

接法也是RTS->CTS,CTS->RTS,交叉相连。

2.1.4 波特率发生器

其实就是分频器

fPCLKx(x=1,2)的意思是:USART1挂载在APB2,也就是PCLK2的时钟,一般是72M。

其他的USART都挂载在PCLK1的时钟,一般36M。

在红色区域这个时钟进行分频,也就是除于USARTDIV的分频系数。USARTDIC也就是蓝色部分,蓝色部分的左边是整数部分,右边是小数部分,有时候用72M除于整数除不尽,会有误差,小数部分的作用性就体现出来了。

最后通过发送器时钟发送到控制器部分。

如果TE = 1,则发送部分波特率有效

如果RE = 1,则接收部分波特率有效

通过以上的复习,我看到这个江协简化图就感觉一目了然了。

2.2 常用寄存器以及作用

2.2.1 USART_SR / USART_ISR (Status Register / Interrupt & Status Register) - 状态寄存器

作用: 反映USART当前的工作状态和各种事件标志。

2.2.2 USART_DR (Data Register) - 数据寄存

作用: 读写同一个物理寄存器,但具有不同的逻辑功能。

  • 写操作 (CPU -> USART): 写入的是发送数据寄存器 (TDR)。CPU将要发送的数据写入此寄存器。

  • 读操作 (CPU <- USART): 读取的是接收数据寄存器 (RDR)。CPU从此寄存器读取接收到的数据。

2.2.3 USART_BRR (Baud Rate Register) - 波特率寄存器

作用: 设置USART的波特率。

2.2.4 USART_CR1 (Control Register 1) - 控制寄存器1

作用: 配置USART的核心工作模式、中断使能等。

2.2.5 USART_CR2 (Control Register 2) - 控制寄存器2

作用: 主要配置停止位、时钟输出、LIN模式、智能卡模式等。

2.2.6 USART_CR3 (Control Register 3) - 控制寄存器3

作用: 配置DMA、硬件流控、错误中断、半双工模式等。

三 、USART通讯模式

3.1 轮询模式

程序通过不断检查USART的状态寄存器(如USART_SR)来判断是否有数据接收。这种方式简单但效率较低。

while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
uint8_t data = USART_ReceiveData(USART1);

3.2 中断模式

中断模式允许程序在接收到数据时被中断处理函数唤醒。

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
​
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

3.3 DMA模式

DMA(直接内存访问)允许数据在内存和外设之间直接传输,无需CPU干预。这种方式适用于大数据量传输。

DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Channel = DMA1_Channel5;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)SendBuff;
DMA_InitStruct.DMA_DIR = DMA_DIR_PERIPH_TO_MEMORY;
DMA_InitStruct.DMA_BufferSize = sizeof(SendBuff);
DMA_InitStruct.DMA_PeripheralInc = DMA_PINC_DISABLE;
DMA_InitStruct.DMA_MemoryInc = DMA_MINC_INCREMENT;
DMA_InitStruct.DMA_Mode = DMA_NORMAL;
DMA_Init(&DMA_InitStruct);

四、USART通讯原理

USART支持两种主要通讯模式:异步模式同步模式

4.1 数据帧结构

异步通讯(常用):

数据以帧的形式传输。一个标准数据帧包括:

  • 起始位:1位逻辑0。

  • 数据位:数据帧的有效载荷,低位先行,8或9位,可选奇偶校验位。

问:何为低位先行?

如果我要发0xF,即0000 1111,则从右边开始读,即11110000依次发送到引脚上。

  • 校验位(可选):用于数据验证,一般分为奇校验和偶校验

问:何为奇校验和偶校验?

奇校验: 0000 1111 1 0000 0111 0(确保1的个数为奇数) 偶校验: 0000 1111 0 0000 1110 1(确保1的个数为偶数)

  • 停止位:用于数据帧间隔,固定为高电平。

以下是一个无校验位的标准数据帧

一下是有校验位的数据帧

可以比对一下。

同步模式(少用):

数据传输依赖于时钟信号,通常用于高速通信。此时,数据帧结构简化,无需起始位和停止位,但需要主设备提供时钟信号。

4.2 波特率

波特率是数据传输速率,单位为bps(bit per second)。常见的波特率包括:9600、115200、57600等。波特率决定了数据传输的速度。

波特率计算

发送器和接收器的波特率由波特率寄存器BRR里的DIV确定 计算公式:波特率 = fPCLK2/1 / (16 * DIV)

问:如何配置BRR寄存器呢?

根据上面的公式,以9600为例:

波特率 = fPCLK2/1 / (16 * DIV)

9600=72M / (16*DIV)=72 000 000 / (16 x DIV)

解得DIV=468.75

二进制:111010100.11(前面补零)

4.3 时钟同步

在异步通信中,发送器和接收器的时钟是独立的,但通过波特率采样点保持同步。

4.4 实际分析

0x55,9600,8位数据,1位停止位,无校验

0x55,9600,8位数据,1位停止位,偶校验

0x55,9600,8位数据,2位停止位,无校验

1/9600=104us,因此每个波形的时间为104us

五、USART配置

5.1 标准库配置过程

串口发送

  1. 使能USART时钟:通过RCC寄存器使能USART的时钟。(USART1是APB2,其他都是APB1的)

  2. 配置GPIO引脚:将TX和RX引脚配置为复用推挽输出浮空或上垃输入

  3. 配置USART参数:设置波特率、数据位、停止位、校验位等。

  4. 启用USART:通过USART_CR1寄存器使能USART。

void Serial_Init(void)
{
    /*1.开启时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  //开启USART1的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //开启GPIOA的时钟
    
    /*2.GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  //将PA9引脚初始化为复用推挽输出
    
    /*3.配置USART参数*/
    USART_InitTypeDef USART_InitStructure;                  //定义结构体变量
    USART_InitStructure.USART_BaudRate = 9600;              //波特率
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制,不需要
    USART_InitStructure.USART_Mode = USART_Mode_Tx;         //模式,选择为发送模式
    USART_InitStructure.USART_Parity = USART_Parity_No;     //奇偶校验,不需要
    USART_InitStructure.USART_StopBits = USART_StopBits_1;  //停止位,选择1位
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;     //字长,选择8位
    USART_Init(USART1, &USART_InitStructure);               //将结构体变量交给USART_Init,配置USART1
    
    /*4.USART使能*/
    USART_Cmd(USART1, ENABLE);                              //使能USART1,串口开始运行
}

5.2 HAL配置过程:

防止只能一次下载,我们先配置Serial Wire

接下来配置PA9和PA10,我们可以看到对应的是usart1

配置Usart1

发送代码:

/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */
​
/* USER CODE BEGIN 2 */
char message[] = "Hello World!\n";//新建字符数组
/* USER CODE END 2 */
​
while (1)
  {
    /*
    &huart1:第一个参数是操作串口的指针,由于操作地址,则加“&”
    (uint8_t*)message:第二个参数是发送信息的指针。由于HAL_UART_Transmit函数在这个参数要求为uint_8,因此强转。
    strlen(message):第三个是发送信息的长度
    100:第四个参数是超时时间,也可以用“HAL_MAX_DELAY”代表无限长发送超时时间
    */
      HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), 100);
      HAL_Delay(1000);
    /* USER CODE END WHILE */
​
    /* USER CODE BEGIN 3 */
  }
​

硬件连接

RX(单片机)-TX(USB转TTTL)

TX(单片机)-RX(USB转TTL)

现象:

中断接收:

配置三个引脚

配置中断控制器

但要注意的是,这里不能将中断事件USART写在USART1_IRQHandler,因为在USART1_IRQHandler只有一个中断向量,而在“接收数据寄存器非空中断”、“发送数据寄存器空中断”和”线路空闲中断“等好几个中断都用了此处的中断处理函数,所以要做一些判断才能确定当前是否因为什么原因而触发的中断。

点击这里,跳转过去。

在2622行左右发现这个函数,复制HAL_UART_RxCpltCallback(这个函数会在接收完成前执行),把执行函数放在里面。代码如下

/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */
​
/* USER CODE BEGIN PV */
uint8_t receiveData[2];
/* USER CODE END PV */
​
/* USER CODE BEGIN 0 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_Receive_IT(&huart1, receiveData, 2);
          HAL_UART_Transmit_IT(&huart1, receiveData, 2);
          GPIO_PinState state = GPIO_PIN_RESET;
          if(receiveData[1] == '0'){
              state = GPIO_PIN_SET;
          }
          if(receiveData[0] == 'A'){
              HAL_GPIO_WritePin(A_GPIO_Port, A_Pin, state);
          }else if(receiveData[0] == 'B'){
              HAL_GPIO_WritePin(B_GPIO_Port, B_Pin, state);
          }else if(receiveData[0] == 'C'){
              HAL_GPIO_WritePin(C_GPIO_Port, C_Pin, state);
          }
          HAL_UART_Receive_IT(&huart1, receiveData, 2);//开启串口接收
}
/* USER CODE END 0 */
​
/* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, receiveData, 2);//开启串口接收
/* USER CODE END 2 */
​
int main(void)
{
    /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
​
  HAL_UART_Receive_IT(&huart1, receiveData, 2);//开启串口接收
  /* USER CODE END 2 */
     while (1)
  {
  }
    
}

串口指令如下:

5.3 使用printf()所需配置

1、在stm32f1xx_hal.c包含#include<stdio.h>

#include "stm32f1xx_hal.h"
#include <stdio.h>
extern UART_HandleTypeDef huart1;   //声明串口

2、stm32f1xx_hal.c 中添加fget和fput函数

int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 

int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}

3、main.c添加

 #define RX_BUFFER_SIZE  256
char RxBuffer[RX_BUFFER_SIZE]; 

 
  while (1)
  {
    /* USER CODE END WHILE */
			printf("Hello\n");
			HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }

<think>好的,我现在需要回答用户关于USART通信协议的问题,包括原理、实现和应用。首先,我需要回顾一下USART的基本概念。USART是通用同步异步收发器,支持同步和异步两种模式。根据用户提供的引用资料,USART嵌入式系统和物联网中应用广泛,比如串口通信。 接下来,用户提到的引用[1]和[2]中有关于USART的工作原理、数据帧结构、波特率等内容。我需要整理这些信息,确保涵盖用户关心的原理、实现和应用。需要注意的是,用户要求使用中文回答,并且所有行内数学表达式要用$...$格式,独立公式用$$...$$。例如,波特率的计算可能需要用公式表示,比如$波特率 = \frac{1}{T_{bit}}$。 然后,我需要检查是否有相关的LaTeX语法错误。比如在异步通信中,数据帧结构可能包括起始位、数据位、校验位和停止位,可以用列表形式呈现。同时,用户要求生成相关问题,我需要根据内容提出几个相关的问题,比如USART与UART的区别,或者波特率设置的影响因素。 在实现部分,引用[2]提到了USART的硬件连接和驱动流程,可能需要简要说明配置步骤,比如初始化GPIO、设置波特率、使能中断等。应用场景部分,可以引用[1]提到的物联网、工业控制等例子。 最后,确保回答结构清晰,分点说明,并在引用的地方正确添加引用标识,如[^1]。同时,生成的三个相关问题需要与USART相关,帮助用户进一步学习。整个过程要保持自然,避免使用Markdown格式,只使用换行和段落分隔。</think>### USART通信协议详解 #### 一、基本原理 USART(通用同步/异步收发器)是一种串行通信协议,支持同步和异步两种模式: 1. **异步模式**:通信双方无需共享时钟,通过约定波特率实现时序同步。数据帧结构包括: - 起始位(1位,低电平) - 数据位(5-9位) - 校验位(可选奇偶校验) - 停止位(1-2位,高电平)[^1][^2] 波特率计算公式为: $$ 波特率 = \frac{1}{T_{bit}} $$ 其中$T_{bit}$为单个比特的传输时间。 2. **同步模式**:通过时钟线(CLK)同步数据,适用于高速通信场景。 #### 二、实现要点 1. **硬件连接**: - TX(发送端)与RX(接收端)交叉连接 - 同步模式需额外连接时钟线 - 电平转换芯片(如MAX232)用于TTL与RS232电平转换 2. **配置步骤**: - 初始化GPIO引脚为复用功能模式 - 设置波特率(如115200bps),需满足: $$ 波特率 = \frac{f_{CLK}}{16 \times USARTDIV} $$ 其中$USARTDIV$为分频系数 - 配置数据位、停止位、校验模式 - 使能发送/接收中断(可选) ```c // STM32配置示例 USART_InitTypeDef USART_InitStruct; USART_InitStruct.BaudRate = 9600; USART_InitStruct.WordLength = USART_WordLength_8b; USART_InitStruct.StopBits = USART_StopBits_1; USART_InitStruct.Parity = USART_Parity_No; USART_Init(USART1, &USART_InitStruct); ``` #### 三、核心应用场景 1. **物联网设备通信**:传感器数据上传、固件升级 2. **工业控制系统**:PLC与HMI设备通信 3. **调试接口**:通过printf重定向实现调试信息输出 4. **金融终端设备**:POS机、密码键盘的数据传输 #### 四、关键技术特性 1. **误差控制**:允许时钟偏差不超过$±4.5\%$(异步模式) 2. **中断机制**:支持发送完成、接收就绪等中断类型 3. **多处理器通信**:通过地址字节实现总线设备寻址
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小张要努力o!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值