简介
串口通信是嵌入式开发中最基础、最常用的通信方式之一,无论是与上位机调试、传感器数据读取,还是设备间通信,都离不开串口。STM32F407 系列芯片提供了多达 6 个 USART/UART 接口,支持异步通信、同步通信、智能卡模式等多种功能。本文从串口基础原理出发,详细讲解 STM32F407 串口的配置方法、代码实现、中断接收、DMA 传输等高级功能,同时提供完整的代码示例和调试技巧,帮助你快速掌握 STM32 串口通信技术。
一、串口通信核心概念与分类
1.1 基本概念
串口通信(Serial Communication)是指数据一位一位地顺序传输,具有线路简单、成本低等优点,广泛应用于嵌入式系统中。
关键参数:
- 波特率:每秒传输的二进制位数,常见值有 9600、115200 等
- 数据位:每个字符的数据位数,通常为 8 位
- 停止位:数据传输结束的标志,通常为 1 位
- 校验位:用于检测传输错误,可选无校验、奇校验、偶校验
1.2 同步通信与异步通信
串口通信按时钟同步方式可分为同步通信和异步通信两种:
异步通信(Asynchronous):
- 不需要专用时钟线,通过起始位和停止位来同步数据
- 发送和接收方使用各自独立的时钟源
- 优点:线路简单,仅需 TX/RX 两根线
- 缺点:波特率误差累积可能导致通信错误
- 适用场景:大多数串口通信场景,如与PC、传感器通信
同步通信(Synchronous):
- 需要专用时钟线(SCLK),发送方提供时钟信号
- 接收方根据时钟信号采样数据
- 优点:通信速率更高,精度更可靠
- 缺点:需要额外的时钟线
- 适用场景:高速数据传输,如与SPI设备通信
1.3 STM32F407 串口分类
STM32F407 系列芯片提供了多种串口接口,按功能可分为三类:
| 串口类型 | 功能特点 | 适用场景 |
|---|---|---|
| USART (Universal Synchronous/Asynchronous Receiver/Transmitter) | 支持异步和同步通信,功能最完整 | 全双工通信、需要时钟同步的场景 |
| UART (Universal Asynchronous Receiver/Transmitter) | 仅支持异步通信,功能简化 | 一般异步通信场景 |
| LPUART (Low Power UART) | 低功耗串口,适合电池供电设备 | 低功耗应用场景 |
STM32F407 串口资源:
- USART1、USART2、USART3、UART4、UART5、USART6
- 支持最高波特率 4.5Mbps
- 支持硬件流控制(RTS/CTS)
- 支持 DMA 传输
二、串口通信原理与硬件连接
2.1 通信原理
串口通信基于 RS-232 或 TTL 电平标准:
- TTL 电平:逻辑 0 为 0V,逻辑 1 为 3.3V/5V(STM32 使用 3.3V)
- RS-232 电平:逻辑 0 为 +3~+15V,逻辑 1 为 -3~-15V(需要电平转换芯片)
数据传输格式:
- 起始位(1 位,低电平)
- 数据位(5-9 位,通常 8 位)
- 校验位(0 或 1 位,可选)
- 停止位(1-2 位,通常 1 位)
2.2 硬件连接
STM32 与 PC 连接:
- 通过 USB-TTL 转换模块(如 CH340、CP2102)连接
- STM32 端:TX 接模块 RX,RX 接模块 TX,GND 共地
- PC 端:通过 USB 口连接,安装对应驱动
STM32 与其他设备连接:
- 直接 TTL 电平连接(距离短,无干扰)
- 通过 RS-485 转换模块连接(距离长,抗干扰)
三、STM32F407 串口配置与代码实现
3.1 标准库配置步骤
以 USART1 为例,使用标准库配置串口的基本步骤:
- 使能串口时钟和 GPIO 时钟
- 配置 GPIO 为复用功能
- 配置串口基本参数(波特率、数据位、停止位、校验位)
- 使能串口
- 配置中断(可选)
- 配置 DMA(可选)
3.2 代码实现(USART1,115200 波特率)
#include"stm32f4xx.h"/** * @brief 初始化 USART1 * @param 无 * @retval 无 */voidUSART1_Init(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 1. 使能时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);// 2. 配置 GPIOGPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);// 3. 将 GPIO 引脚连接到 USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);// TXGPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);// RX// 4. 配置 USART1USART_InitStructure.USART_BaudRate=115200;// 波特率USART_InitStructure.USART_WordLength=USART_WordLength_8b;// 数据位USART_InitStructure.USART_StopBits=USART_StopBits_1;// 停止位USART_InitStructure.USART_Parity=USART_Parity_No;// 无校验USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;// 无硬件流控制USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;// 收发模式USART_Init(USART1,&USART_InitStructure);// 5. 使能 USART1USART_Cmd(USART1,ENABLE);}/** * @brief 串口发送一个字节 * @param USARTx: 串口编号 * @param Data: 要发送的字节 * @retval 无 */voidUSART_SendByte(USART_TypeDef*USARTx,uint8_tData){// 等待发送缓冲区为空while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);// 发送数据USART_SendData