USART串口通信从电路原理到代码实现:STM32零基础入门第XXX步(详细解析)
主题 | 内容 | 教学目的/扩展视频 |
---|---|---|
串口通信重点课程 |
什么是USART串口,电路原理,单片机内部寄存器,固件库说明。加载相关文件,驱动程序分析,printf的使用。什么是中断,中断的程序设计,还有哪些中断。 | 熟悉串口的使用,熟练使用printf函数。介绍printf函数的高级使用方法,介绍各中断。 |
师从洋桃电子,杜洋老师
📑文章目录
一、USART串口基础认知
1. 什么是USART?
USART(Universal Synchronous/Asynchronous Receiver/Transmitter)是一种通用串行通信接口,具备以下特点:
2. 典型应用场景
二、硬件电路设计要点
1. USB转TTL电路(CH340C模块)
(图1:USART通信连接原理图)
STM32 CH340C
PA9(TX) ---> RX
PA10(RX) ---> TX
GND ---> GND
注意事项:
2. 单片机端电路保护
三、STM32内部寄存器解析
1. 关键寄存器组成
寄存器名称 | 功能描述 | 常用配置值 |
---|---|---|
USART_CR1 | 控制寄存器1 | UE=1(使能USART) |
USART_CR2 | 控制寄存器2(停止位设置) | STOP[1:0]=00(1位停止位) |
USART_BRR | 波特率寄存器 | 根据公式计算得出 |
2. 波特率计算公式
波特率 = fCK / (16 * USARTDIV)
/*
示例:115200bps @72MHz主频
USARTDIV = 72000000/(16*115200) = 39.0625
BRR = 0x273 // 整数部分39=0x27,小数0.0625*16=1
*/
四、固件库函数说明(标准外设库)
1. 初始化结构链
void USART1_Init(u32 bound){ //串口1初始化并启动
├── GPIO端口设置
├── USART1_TX PA.9
├── USART1_RX PA.10
├── Usart1 NVIC 配置
├── USART 初始化设置
参数结构体解析:
typedef struct {
uint32_t USART_BaudRate; // 波特率
uint16_t USART_WordLength; // 数据位(USART_WordLength_8b/9b)
uint16_t USART_StopBits; // 停止位(USART_StopBits_1/1.5/2)
uint16_t USART_Parity; // 校验位(USART_Parity_No/Even/Odd)
uint16_t USART_Mode; // 工作模式(USART_Mode_Rx | USART_Mode_Tx)
} USART_InitTypeDef;
2. 常用库函数列表
函数名称 | 功能描述 |
---|---|
USART_Cmd() | 使能/禁用USART |
USART_SendData() | 发送单字节数据 |
USART_ReceiveData() | 接收单字节数据 |
USART_GetFlagStatus() | 查询状态标志位 |
USART_ITConfig() | 中断使能控制 |
五、驱动程序逐行解析
1. 初始化配置流程
#include "stm32f10x.h"
#include "usart.h"
int main(void) {
RCC_Configuration(); // 时钟设置
USART1_Init(115200); // 初始化参数配置
while(1) {
// 发送方法:轮询方式
USART_SendData(USART1, 0x55); // 写入发送数据寄存器
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)); // 等待发送完成
delay_ms(1000); // 延时控制发送间隔
}
}
2. 关键代码解析
RCC配置函数:
void RCC_Configuration(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
}
USART初始化函数:
void USART1_Init(u32 bound){ //串口1初始化并启动
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启ENABLE/关闭DISABLE中断
USART_Cmd(USART1, ENABLE); //使能串口
}
▲ 完整工程代码示例⏬USART串口发送程序
六、上位机测试方法
1. 串口助手设置参数
参数项 | 设置值 |
---|---|
波特率 | 115200 |
数据位 | 8 |
停止位 | 1 |
校验位 | None |
流控制 | 无 |
2. 数据接收验证
当单片机发送0x55
(二进制01010101)时:
▲ ⏬DYS串口助手 V1
七、进阶应用技巧
1. 字符串发送优化
USART1专用的printf函数
当同时开启2个以上串口时,printf函数只能用于其中之一,其他串口要自创独立的printf函数
调用方法:USART1_printf("123"); //向USART2发送字符123
*/
void USART1_printf (char *fmt, ...){
char buffer[USART1_REC_LEN+1]; // 数据长度
u8 i = 0;
va_list arg_ptr;
va_start(arg_ptr, fmt);
vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr);
while ((i < USART1_REC_LEN) && (i < strlen(buffer))){
USART_SendData(USART1, (u8) buffer[i++]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
va_end(arg_ptr);
}
2. 中断接收配置
void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)
u8 Res;
//以下是字符串接收到USART1_RX_BUF[]的程序,(USART1_RX_STA&0x3FFF)是数据的长度(不包括回车)
//当(USART1_RX_STA&0xC000)为真时表示数据接收完成,即超级终端里按下回车键。
//在主函数里写判断if(USART1_RX_STA&0xC000),然后读USART1_RX_BUF[]数组,读到0x0d 0x0a即是结束。
//注意在主函数处理完串口数据后,要将USART1_RX_STA清0
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){ //接收中断(接收到的数据必须是0x0d 0x0a结尾)
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
printf("%c",Res); //把收到的数据以 a符号变量 发送回电脑
if((USART1_RX_STA&0x8000)==0){//接收未完成
if(USART1_RX_STA&0x4000){//接收到了0x0d
if(Res!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
else USART1_RX_STA|=0x8000; //接收完成了
}else{ //还没收到0X0D
if(Res==0x0d)USART1_RX_STA|=0x4000;
else{
USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ; //将收到的数据放入数组
USART1_RX_STA++; //数据长度计数加1
if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
八、常见问题排查表
现象 | 可能原因 | 解决方法 |
---|---|---|
无任何数据接收 | 1. 线序接反(TX-RX交叉) 2. 波特率不匹配 |
检查硬件连接 核对双方波特率 |
接收数据乱码 | 1. 地线未连接 2. 时钟源偏差 |
确保共地 使用精准晶振 |
只能发送不能接收 | RX引脚配置错误 | 检查GPIO模式设置 |
实验建议:使用逻辑分析仪捕获实际通信波形,观察起始位、数据位、停止位的时序关系
九、相关资源
[1] 洋桃电子B站课程-STM32入门100步
[2] STM32F103xx官方数据手册
[3] STM32F103X8-B数据手册(中文)
[4] STM32F103固件函数库用户手册(中文)
[5] USART串口发送程序
[6] DYS串口助手 V1
[7] CH340C 数据手册
💬 技术讨论(请在评论区留言~)
📌 下期预告:下一期将探讨USART发送程序
重点课程
,欢迎持续关注!点击查阅🔍往期【STM32专栏】文章
版权声明:本文采用[CC BY-NC-SA 4.0]协议,转载请注明来源
实测开发版:洋桃1号开发版(基于STM32F103C8T6)
更新日志:v1.0 初始版本(2025-02-27)
作者:触角01010001