🎓 总站 🏠 本课目录 05 GPIO 06 中断 07 串口通信
智能嵌入式系统设计 · 第7章

串口通信 USART

基于 STM32F103 · 零基础讲解串/并行、同步/异步、单/半/全双工、波特率、数据帧格式与查询/中断/DMA 三种收发方式。

📚 学习进度
0%

🎯学习目标

  • 理解通信的基本概念,了解常见串行通信接口;
  • 熟悉标准库和 HAL 库中 USART 的库函数;
  • 掌握 USART 标准库异步模式的配置方法;
  • 掌握查询方式、中断方式、DMA 方式三种应用;
  • 掌握基于标准库和 HAL 库开发 USART 应用的方法。

1通信方式分类

通信方式可从三个维度分类:

通信方式 按传送方式 按同步方式 按传输方向 串行通信 / 并行通信 同步通信 / 异步通信 单工 / 半双工 / 全双工
图1 · 通信方式三维分类

串行 vs 并行

➡️

串行通信

Serial
通过一根或少量数据线(少于8根)将数据一位一位按顺序依次传送。U盘、USB、RS-485/232、IIC、SPI

并行通信

Parallel
用多条数据线同时传送多位(8/16/32位)。传输量是串行数倍。CPU内部总线、早期并口硬盘/打印机
⭐ 对比要点并行:速度快、占用线多、距离短、易干扰;串行:线少、成本低、距离远,是目前最流行的方式。计算机网络传输均为串行。

2同步/异步 · 三种工作方式

同步通信 vs 异步通信

对比同步通信异步通信
方式连续串行传送,收发时钟严格同步字符(数据帧)为单位,加起始/停止位
速率较高较低
实现需同步时钟,较复杂设备实现简单、成本低

单工 / 半双工 / 全双工

📻

单工

任何时刻只能单方向通信,一端固定发、一端固定收。例:广播、电视、灯塔

📞

半双工

双方都能收发,但不能同时进行。例:对讲机

📱

全双工

双方可同时收发数据。例:手机

3通信传输速率与波特率

  • 传输速率(比特率):每秒传输的二进制位数,单位 bit/s(bps),衡量速度快慢。
  • 字符速率:每秒所传输的字符数。
  • 波特率 = 字符速率 × 每个字符包含的位数
例:波特率计算字符速率 120 字符/秒,每个字符 10 位(1 起始位 + 7 数据位 + 1 校验位 + 1 停止位),则波特率 = 10 位/字符 × 120 字符/秒 = 1200 bps
💡 常用波特率1200、2400、4800、9600、19200、115200 等。收发双方波特率必须一致,否则乱码。

4异步串行通信数据帧格式 ⭐(核心考点)

异步串行通信的标准数据帧由起始位、数据位、校验位、停止位四部分组成。通信传输速率与数据帧格式一起称为通信协议

起始位 数据位 (5~8位) 校验位 停止位 空闲位"1" 逻辑0·1位 1位·校验 1/1.5/2位 ← 一帧数据,按字符为单位传送 →
图2 · 异步串行通信数据帧格式
组成说明
起始位占 1 位,位于帧开头,以逻辑 "0" 表示传输开始
数据位要发送的数据,长度 5~8 位
校验位占 1 位,用于检测数据是否有效(无/奇/偶校验)
停止位一帧结束标志,可为 1、1.5 或 2 位
空闲位传输完毕用 "1" 表示线路无数据传输

5UART 与 RS-232

UART(Universal Asynchronous Receiver Transmitter,通用异步收发传输器)是全双工通用异步串行收/发模块,用于打印调试信息、上下位机通信、ISP 下载等。

⭐ 最简 UART 接口最简单的 UART 由 TxD、RxD、GND 三根线组成:TxD 发送、RxD 接收、GND 信号地,交叉连接(A的TxD接B的RxD)实现两芯片串口通信。

RS-232 接口

RS-232 是美国电子工业协会(EIA)制定的串行通信物理接口标准,规定电气和物理特性,常采用 DB-9 形式。对可靠性要求不高时用三线制(Tx/Rx/GND)即可全双工通信,最高速率约 20kbps。

⚠️ 电平转换(必考)RS-232 采用负逻辑电平,不能与 TTL 电平设备直接相连;微控制器 UART 采用 TTL 电平。因此 RS-232 与 MCU 相连必须经过电平转换(如 MAX232)。
针脚符号功能
2RxD接收数据(输入)
3TxD发送数据(输出)
5GND信号地
7/8RTS/CTS请求发送/清除发送(硬件流控)

6STM32 的 USART 内部结构

USART 内部由三部分构成:波特率发生器、发送/接收控制单元、数据收发寄存器单元

波特率发生器USART_BRR 收发控制单元CR1/2/3 · SR 发送 TDR→移位TXE/TC 接收 移位→RDRRXNE TxD RxD
图3 · USART 内部结构框图

关键状态位(SR 寄存器)

标志位含义
TXE发送数据寄存器空(数据已转移到移位寄存器,可写下一个)
TC发送完成
RXNE读数据寄存器非空(收到数据,可读出)
IDLE检测到总线空闲
ORE/NE/FE/PE过载/噪声/帧/校验 错误标志

USART 接口与引脚

STM32F103 大容量产品有 5 个串口:USART1/2/3 功能全,UART4/UART5 不支持同步模式(只有异步功能)。USART 异步模式至少需 Rx、Tx 两个引脚,使用复用 I/O 功能。

串口TX 引脚RX 引脚GPIO 配置
USART1 (APB2)PA9PA10TX:复用推挽 / RX:浮空输入
USART2 (APB1)PA2PA3同上
USART3 (APB1)PB10PB11同上
⭐ 引脚配置(必考)TX 引脚配为复用推挽输出(AF_PP),RX 引脚配为浮空输入(IN_FLOATING)

7USART 三种编程模式 ⭐(核心考点)

🔄

查询(轮询)方式

循环查询 SR 状态位(TXE/RXNE)决定是否收发。简单但占用 CPU。

🔔

中断方式

使能中断,事件发生时进 ISR 处理。CPU 利用率高。

DMA 方式

大批量数据连续传输,几乎不占 CPU。

中断方式:主要中断事件

发送期间:发送完成(TC)、清除发送(CTS)、发送数据寄存器空(TXE);接收期间:空闲检测(IDLE)、溢出错误(ORE)、接收数据寄存器非空(RXNE)、校验错误(PE)等。

中断标志使能位STM32 定义事件
TXETXEIEUSART_IT_TXE发送数据寄存器空
TCTCIEUSART_IT_TC发送完成
RXNERXNEIEUSART_IT_RXNE接收数据就绪(可读)
IDLEIDLEIEUSART_IT_IDLE检测到空闲线路

DMA 方式

USART 收发分别映射到不同 DMA 通道,如 USART1_Rx → DMA1 通道5USART1_Tx → DMA1 通道4,适合大批量数据连续传输。

8USART 标准库函数与编程步骤

USART 标准库函数定义在 stm32f10x_usart.c,头文件声明共 29 种函数。

初始化结构体

typedef struct {
  uint32_t USART_BaudRate;          // 波特率,如 115200
  uint16_t USART_WordLength;        // 数据位 8b/9b
  uint16_t USART_StopBits;          // 停止位 1/0.5/2/1.5
  uint16_t USART_Parity;            // 校验 No/Even/Odd
  uint16_t USART_Mode;              // Rx / Tx
  uint16_t USART_HardwareFlowControl; // 硬件流控
} USART_InitTypeDef;

常用库函数

函数功能
USART_Init()初始化串口参数
USART_Cmd()使能/失能串口
USART_SendData()发送单个数据
USART_ReceiveData()接收数据
USART_GetFlagStatus()查询状态标志(TXE/TC/RXNE…)
USART_ITConfig()使能串口中断
USART_GetITStatus()查询中断状态
USART_ClearITPendingBit()清除中断标志
USART_DMACmd()配置 DMA 与 USART 通道

标准库配置步骤(7 步)

步骤操作
声明 GPIO 和 USART 初始化结构体
使能 GPIO 时钟和串口时钟(RCC_APB2PeriphClockCmd
TX 配复用推挽输出、RX 配浮空输入
设置波特率、数据位、停止位、校验位
USART_Init() 初始化串口
USART_Cmd() 使能串口
编写应用程序(若用中断则写 USARTx_IRQHandler()

9UART 的 HAL 库函数

HAL 库 UART 函数定义在 stm32f1xx_hal_uart.c。三种收发方式各有对应函数:

方式发送接收
轮询HAL_UART_Transmit()HAL_UART_Receive()(带超时)
中断HAL_UART_Transmit_IT()HAL_UART_Receive_IT()
DMAHAL_UART_Transmit_DMA()HAL_UART_Receive_DMA()

中断接收完成会回调 HAL_UART_RxCpltCallback(),发送完成回调 HAL_UART_TxCpltCallback(),用户在回调内编写处理程序。

💡 HAL_UART_Transmit 四参数① huart(句柄指针 huart1~5);② pData(数据缓冲区指针,uint8_t*);③ Size(数据大小);④ Timeout(超时等待时间)。超时未发完返回 HAL_TIMEOUT。

重点例题

例题1:标准库——串口1 回显(查询方式收发字符) 思路:开 USART1+GPIOA 时钟 → PA9 复用推挽、PA10 浮空 → 配 115200/8/N/1 → 主循环查 RXNE,收到就回发。
void USART_Init_Config(void) {
  GPIO_InitTypeDef gp; USART_InitTypeDef us;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
  // PA9 = TX 复用推挽输出
  gp.GPIO_Pin=GPIO_Pin_9; gp.GPIO_Speed=GPIO_Speed_50MHz;
  gp.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&gp);
  // PA10 = RX 浮空输入
  gp.GPIO_Pin=GPIO_Pin_10; gp.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&gp);
  // 115200 / 8位 / 1停止 / 无校验 / 收发
  us.USART_BaudRate=115200; us.USART_WordLength=USART_WordLength_8b;
  us.USART_StopBits=USART_StopBits_1; us.USART_Parity=USART_Parity_No;
  us.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  us.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
  USART_Init(USART1,&us); USART_Cmd(USART1,ENABLE);
}
int main(void){
  char Temp; USART_Init_Config();
  while(1){
    if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)){   // 收到数据
      Temp=USART_ReceiveData(USART1);
      USART_SendData(USART1,Temp);                     // 原样回发
      while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // 等发完
    }
  }
}
关键点:发送前后用 TXE/TC 标志判断;TX=复用推挽、RX=浮空输入;收发双方波特率必须一致。
例题2:printf 重定向到串口 思路:重写 fputc()(输出)和 fgetc()(输入),勾选 Keil 的 Use MicroLIB,并 #include <stdio.h>
int fputc(int ch, FILE *f) {           // printf 重定向
  USART_SendData(USART1, (uint8_t)ch);
  while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // 等寄存器空
  return ch;
}
int fgetc(FILE *f) {                   // scanf/getchar 重定向
  while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
  return (int)USART_ReceiveData(USART1);
}
// 之后即可: printf("点亮LED灯\n"); ch=getchar();
提示:输出字符串时若丢失第一个字符,可在发送前调用 USART_ClearFlag(USARTx,USART_FLAG_TC) 复位 TC 标志。
例题3:HAL 库——中断方式回显
/* main 中开启接收中断 */
HAL_UART_Receive_IT(&huart1, (uint8_t*)&RxBuffer, 1);
/* 接收完成回调:回发并重新开启接收 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  HAL_UART_Transmit(&huart1,(uint8_t*)&RxBuffer,1,0);
  HAL_UART_Receive_IT(&huart1,(uint8_t*)&RxBuffer,1); // 必须重新开启
}
关键点:HAL 中断接收是"一次性"的,回调里必须重新调用 HAL_UART_Receive_IT() 才能持续接收。

🎯自测(点击展开)

串行通信和并行通信的区别?
串行用一根/少量线一位一位传送,线少成本低距离远;并行用多条线同时传多位,速度快但占线多距离短。
单工、半双工、全双工分别举一个例子?
单工:广播/电视;半双工:对讲机;全双工:手机。
异步串行数据帧由哪几部分组成?
起始位(1位逻辑0)、数据位(5~8位)、校验位(1位)、停止位(1/1.5/2位),空闲时为"1"。
波特率怎么计算?
波特率 = 字符速率 × 每个字符包含的位数。如 120字符/秒 × 10位 = 1200bps。
USART 的 TX、RX 引脚应配置为什么模式?
TX 配复用推挽输出(AF_PP),RX 配浮空输入(IN_FLOATING)。
USART 有哪三种编程(收发)方式?
查询(轮询)方式、中断方式、DMA 方式。DMA 适合大批量数据连续传输。
RS-232 与 STM32 相连为什么要电平转换?
RS-232 用负逻辑电平,MCU 的 UART 用 TTL 电平,二者不兼容,需经 MAX232 等芯片转换。

📝强化题库

选择题点选即时判分;填空题输入后"检查"或"显示答案"。

已答 0/0答对 0正确率
已答 0/0答对 0