2026/8/21 16:42:46

STM32 单片机USART 串口配置

STM32 单片机USART 串口配置 目录1、基础概念2、原理图分析​3、USART技术分析4、代码实现5、代码单片机向电脑发送数据1、基础概念1、什么是USART:USART是单片机或嵌入式系统中非常常用的一个外设模块,全程是 Universal Synchronous/Asynchronous Receiver/Transmitter (通用同步/异步收发器).USART 的主要功能是进行串行通信也就是把并行数据如 CPU 内部的数据转换为串行数据发送出去把接收到的串行数据重新转换为并行数据给 CPU 使用。串口硬件中数据传递的一种方式而且是常用方式。后续开发中WiFi蓝牙LoRaZigBee4/5G都可以按照串口方式进行数据传递和设备控制。数据按照【串行数据传递格式】完成设备之间的通信。并行和串行并行 多跟数据线数据多个位同时发送类似高速公路。串行一根数据线数据一位一位的依次发送。串行情况下数据传递的工作模式分为三种单工设备区分发送端和接收端有且只允许从发送端到接收端进行数据传递半双工 每一台设备即是发送端也是接收端。但是在通信过程中设备同一个周期内仅可以充当一个角色。例如 此时A设备发送数据到B设备同一个时间周期内不允许B发送数据到A全双工:每一台设备即是发送端也是接收端。同时在数据传递过程中允许设备之间进通信进行发送和接收操作。例如A设备发送数据到B设备同时B设备可以发送数据到A设备。STM32开发中使用的串口USART通常情况下是全双工模式利用两个数据线进行数据通信。同步和异步同步类似于无人机仿生机械臂同传技术。视觉同传操作同传数据同步传递是发送端和接收端在同一个【时间参考】中进行数据传递因为不可逾越的数据传递延迟问题存在一定的数据丢失和期望数据同步滞后性。异步学习舞蹈老师完成一个节拍动作之后学员进行模仿。数据异步传递A发送数据完成之后B进行数据解析可以满足数据安全性和完整性。串口中使用的通常情况下都是异步传递方式保证数据的完整性和安全性2、原理图分析CH340 : USB to UART Bridge Chip 功能是 把电脑的USB 信号转换成串口信号UART/USART让电脑能和单片机通过串口通信。模块功能USB Type-C 接口连接电脑通过 USB 传输信号CH340C 芯片把 USB 信号转成串口信号TXD、RXD 引脚串口通信线接到单片机的 USART 引脚Q1、Q2 及 D2、R17、R21...用于自动控制单片机的BOOT0和RESET实现自动下载功能类似 STM32 的 ISP 下载数据传输流程从电脑发送给单片机电脑软件串口助手 / ISP工具↓USB 传输协议复杂的包格式↓CH340C 芯片↓转换为 UART 信号TXD、RXD↓单片机 USART 接收RX 引脚单片机发送给电脑单片机 USART 发送TX 引脚↓CH340C 芯片将 UART 转换为 USB↓电脑 USB 驱动虚拟 COM 口↓电脑串口调试助手显示数据以 USART1 为例USART1 的TX 和 RX 分别是 PA9 和 PA1。3、USART技术分析在STM32文档中可以找到 USART 的章节。框图重点发送器控制是通过寄存器CR1控制涉及到的寄存位有TEPSSBK接收器控制是通过寄存器CR1控制涉及到的寄存位有REPCE,数据寄存器USARTx_DR是根据MCU读操作和写操作行为区分数据走向例如USARTx_DR 10; MCU写操作数据会存储到TDR寄存器中USART外设自行控制数据转移到【发送移位寄存器】通过发送器进行数据发送u8 data USARTx_DR; MCU读操作USART外设会将存在RDR寄存器中的数据提供给MCU使用。数据是在MCU执行读操作之前已经通过RX引脚读取到DR寄存器内部通过接收器控制完成。USART中断控制对应寄存器为CR1涉及到中断标志控制为有TXEIE TCIE RXNEIEIDLEIE。IE Interrupt EnableNRZ 数据格式波特率USART波特率是对应当前数据的发送速度波特率越高对应发送速度越高反之速度降低。波特率越高传递距离越短。波特率计算公式具体参考stm32 文档。总之代码设置波特率要和串口助手的波特率一致否则会出现乱码或者接收不到数据。USART中断USART只有一个中断入口函数 USARTx_IRQHandler()但有多个中断源可以触发,常用的USART中断标志位有RXNE(接收寄存器有新数据) 和 IDLE(接收线空闲——一帧结束)。名称场景RXNE接收到数据最常用TXE发送下一个字节TC一帧发送完毕IDLE一帧接收完毕空闲检测在串口配置中通过 CR1 寄存器开启相应的中断使能在中断处理函数中注意要将 SR 寄存器的中断标志位清除否则中断会反复进入。不同中断有不同的清楚方式标志位含义何时产生如何清除是否必须清除RXNE接收寄存器非空收到一个字节读取 USART_DR自动清除✅ 必须TXE发送寄存器空一个字节发送完成写 USART_DR自动清除✅ 必须TC传输完成最后一个字节发送完USART_ClearITPendingBit()或读写寄存器✅ 必须IDLE空闲帧检测接收线空闲1帧时间先读 SR再读 DR清除✅ 必须ORE/FE/PE溢出/帧错误/校验错误通信异常读 SR 再读 DR 清除✅ 必须4、代码实现总体代码流程如下步骤说明①打开 GPIO 和 USART1 的时钟②配置引脚复用功能PA9 → TX, PA10 → RX③配置串口参数波特率、数据位、校验、停止位等④使能 USART1⑤编写发送和接收函数或使用中断/DMA重点位第三步和第四步先看相关开发寄存器分析寄存器名全称作用USART_SR状态寄存器 (Status Register)标志发送、接收状态如 TXE、RXNE 等USART_DR数据寄存器 (Data Register)发送或接收的数据存放处USART_BRR波特率寄存器 (Baud Rate Register)设置通信速率USART_CR1控制寄存器1 (Control Register 1)开启 USART、配置数据位、使能发送接收USART_CR2控制寄存器2 (Control Register 2)设置停止位、时钟相关设置USART_CR3控制寄存器3 (Control Register 3)控制流、DMA、中断等扩展功能重点位 CR1 和 CR2CR1:需要配置的有 USART使能字长校验控制使能校验选择发送使能接收使能具体需要看STM32 文档。CR2:配置停止位。波特率寄存器此外还需要配置 DR数据寄存器 和SR串口状态寄存器,具体看STM32 文档。5、代码单片机向电脑发送数据STM32 单片机通过 USART1 的 TX 引脚把数据发送到电脑usart.h#ifndef _USART_H #define _USART_H #include stm32f10x.h //定义宏引脚 #define GPIOA_RCC_APB2_CLOCK_ENABLE (0x01 2) //开启时钟使能 #define USART1_RCC_APB2_CLOCK_ENABLE (0x01 14) //开启时钟使能 #define Floating_Input_Mode (0x04) //浮空输入模式 #define Alternate_Function_Push_Pull_Output_Mode (0x0B) //复用推挽输出 /** USAR1 初始化函数要求用户提供目标波特率数据常用波特率 4800 9600 115200 param brr 用户提供的波特率参数 */ void USART1_Init(u32 brr); /** 发送数据 一个字节 */ void USART1_SendByte(u8 byte); /** 连续发送一段缓冲区数据 */ void USART1_SendBuffer(u8 *buffer,u16 count); /** 发送字符串 */ void USART1_SendString(const char * str); #endifusart.c#include usart.h void USART1_Init(u32 brr) { // 1. 配置 USART1 对应引脚 GPIO 工作模式 RCC-APB2ENR | GPIOA_RCC_APB2_CLOCK_ENABLE; GPIOA-CRH ~(0x0F 4); GPIOA-CRH | (Alternate_Function_Push_Pull_Output_Mode 4); GPIOA-CRH ~(0x0F 8); GPIOA-CRH | (Floating_Input_Mode 8); // 2. 配置 USART1 串口相关功能 RCC-APB2ENR | USART1_RCC_APB2_CLOCK_ENABLE; USART1-CR1 | (0x01 3); // USART1 CR1 TE 寄存器位开启 USART1-CR1 | (0x01 2); // USART1 CR1 RE 寄存器位开启 USART1-CR1 ~(0x01 12); USART1-CR1 ~(0x03 9); // USART1 CR2 STOP 寄存器为明确为 01 个停止位。 USART1-CR2 ~(0x03 12); // USART1 发送和接收 BRR 波特率配置。 // 利用参数波特率计算 USART_DIV 数据 float usart_div 72000000 / (16 * brr); // 计算器波特率寄存器整数位内容 u32 div_mantissa (u32)usart_div; // 计算器波特率寄存器小数位内容 u32 div_fraction (u32)((usart_div - div_mantissa) * 16); // 存储 div_mantissa 和 div_fraction 到 USART1 BRR 寄存器中 USART1-BRR | (div_mantissa 4) | div_fraction; // USART1 UE 寄存器为配置开启 USART1 工作 // 【注意】开启 USRAT1 需要在所有配置完成之后如果先开启 USART1 // 相关配置无法完成。类似于 出发前准备好所有内容。 USART1-CR1 | (0x01 13); } void USART1_SendByte(u8 byte) { while (0 (USART1-SR (0x01 6))); USART1-DR byte; } void USART1_SendBuffer(u8 *buffer, u16 count) { while (count--) { USART1_SendByte(*buffer); buffer 1; } } void USART1_SendString(const char * str) { while (*str) { USART1_SendByte((u8)(*str)); str 1; } }mian.c#include usart.h int main(void) { USART1_Init(9600); while (1) { USART1_SendString(Hello USART1\r\n); Delay_ms(2000); } }6、printf--串口重定向先来说C语言中的printf底层逻辑跳转printf查看定义可以看到如下#pragma __printf_argsextern _ARMABI int printf(const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1)));这是因为因为printf是 C 标准库函数其具体实现代码已被编译成二进制库文件如.lib或.a工程中只有头文件声明没有源码。但是printf实际是调用底层的fputc函数一个字符一个字符发送。那么只需要对fputc重新定义即可调用printf实现串口发送。///重定向c库函数printf到串口DEBUG_USART重定向后可使用printf函数 int fputc(int ch, FILE *f) { /* 发送一个字节数据到串口DEBUG_USART */ USART_SendData(DEBUG_USART, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) RESET); return (ch); }