news 2026/5/25 11:39:17

Keil串口通信全教程:UART初始化、数据收发(中断/查询模式)+串口调试助手验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Keil串口通信全教程:UART初始化、数据收发(中断/查询模式)+串口调试助手验证

文章目录

    • 一、前期准备
      • 1. 软硬件环境
      • 2. UART核心原理梳理
    • 二、实战1:UART初始化(以USART1为例,9600波特率)
      • 1. 配置思路
      • 2. Keil工程代码实现
    • 三、实战2:查询模式收发数据(基础版)
      • 1. 核心函数编写
      • 2. 串口调试助手验证
        • 步骤1:硬件连接
        • 步骤2:串口调试助手配置
        • 步骤3:验证效果
    • 四、实战3:中断模式收发数据(高效版)
      • 1. 中断配置与代码实现
      • 2. 串口调试助手验证
    • 五、进阶配置:修改波特率(115200bps)
    • 六、Keil调试与问题排查技巧
      • 1. Keil调试验证中断流程
      • 2. 常见问题与解决
        • 问题1:串口无数据输出
        • 问题2:接收数据乱码
        • 问题3:中断不触发
        • 问题4:缓冲区溢出
    • 七、实战扩展:多字节/协议收发

串口通信(UART)是单片机与外设、上位机交互的核心方式,广泛应用于数据打印、指令接收、设备联动等场景。本文基于STM32F103C8T6单片机,结合Keil MDK-ARM开发环境,从底层寄存器配置到实战调试,手把手讲解UART初始化、查询模式收发、中断模式收发,并配套串口调试助手验证方法,零基础也能快速掌握串口开发核心技能。

一、前期准备

1. 软硬件环境

  • 硬件:STM32F103C8T6最小系统板、USB-TTL模块(CH340/PL2303)、杜邦线、电脑(Windows);
  • 软件:Keil MDK-ARM V5.36(需安装STM32F103器件库)、串口调试助手(SSCOM/串口助手V1.4);
  • 基础知识:熟悉STM32 GPIO配置、USART寄存器结构、Keil工程创建流程、C语言基础。

2. UART核心原理梳理

STM32F103的USART1挂载在APB2总线,USART2/3挂载在APB1总线,核心参数:

  • 波特率:数据传输速率(常用9600、115200bps),由波特率寄存器(USART_BRR)配置;
  • 数据帧:1位起始位+8位数据位+1位停止位(无校验),可配置奇偶校验、停止位数量;
  • 收发模式:查询模式(轮询寄存器标志位)、中断模式(数据收发触发中断);
  • 硬件连接:USART_TX(发送)接USB-TTL的RX,USART_RX(接收)接USB-TTL的TX,共地(GND)。

二、实战1:UART初始化(以USART1为例,9600波特率)

初始化是串口通信的基础,需配置GPIO复用、时钟、波特率、帧格式等核心参数。

1. 配置思路

  • 系统时钟72MHz,USART1时钟来自APB2(72MHz),波特率9600bps,计算USART_BRR值:
    分频值 = 72000000 / 9600 = 7500 → BRR寄存器配置为0x1D4C(十进制7500的十六进制);
  • GPIO配置:PA9(USART1_TX)为复用推挽输出,PA10(USART1_RX)为浮空输入;
  • 使能USART1时钟、GPIOA时钟,开启串口收发功能。

2. Keil工程代码实现

#include"stm32f10x.h"#include<stdio.h>// USART1初始化函数(9600波特率,8位数据位,1位停止位,无校验)voidUSART1_Init(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 1. 使能时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);// 2. 配置GPIO(PA9=TX,PA10=RX)// PA9:USART1_TX 复用推挽输出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);// PA10:USART1_RX 浮空输入GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA,&GPIO_InitStructure);// 3. 配置USART参数USART_InitStructure.USART_BaudRate=9600;// 波特率USART_InitStructure.USART_WordLength=USART_WordLength_8b;// 8位数据位USART_InitStructure.USART_StopBits=USART_StopBits_1;// 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);// 4. 使能USART1USART_Cmd(USART1,ENABLE);}// 重定向printf到USART1(方便打印字符串)intfputc(intch,FILE*f){// 等待发送数据寄存器为空while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);// 发送字节USART_SendData(USART1,(u8)ch);returnch;}

三、实战2:查询模式收发数据(基础版)

查询模式通过轮询USART状态标志位实现数据收发,逻辑简单,适合低频率数据交互。

1. 核心函数编写

// 查询模式:发送单个字节voidUSART1_SendByte(u8 data){// 等待TXE标志位(发送数据寄存器空)while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE));USART_SendData(USART1,data);}// 查询模式:发送字符串voidUSART1_SendString(u8*str){while(*str!='\0'){USART1_SendByte(*str);str++;}// 等待发送完成while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);}// 查询模式:接收单个字节(阻塞式)u8USART1_ReceiveByte(void){// 等待RXNE标志位(接收数据寄存器非空)while(!USART_GetFlagStatus(USART1,USART_FLAG_RXNE));returnUSART_ReceiveData(USART1);}// 主函数测试intmain(void){u8 recv_data;// 初始化USART1USART1_Init();// 上电发送欢迎信息USART1_SendString((u8*)"STM32 USART1 Test (查询模式)\r\n");USART1_SendString((u8*)"请输入字符:\r\n");while(1){// 接收单个字节recv_data=USART1_ReceiveByte();// 回显接收到的字符USART1_SendByte(recv_data);// 接收到换行符,发送提示if(recv_data=='\r'){USART1_SendString((u8*)"\r\n已接收字符,等待下一次输入...\r\n");}}}

2. 串口调试助手验证

步骤1:硬件连接
  • STM32 PA9(USART1_TX)→ USB-TTL RX;
  • STM32 PA10(USART1_RX)→ USB-TTL TX;
  • STM32 GND → USB-TTL GND;
  • USB-TTL插入电脑USB口,安装驱动(CH340/PL2303)。
步骤2:串口调试助手配置
  • 打开串口调试助手(如SSCOM);
  • 选择对应COM口(电脑设备管理器查看);
  • 配置参数:波特率9600、8位数据位、1位停止位、无校验、无流控;
  • 点击“打开串口”。
步骤3:验证效果
  • 编译Keil工程,下载程序到STM32;
  • 串口调试助手接收区显示“STM32 USART1 Test (查询模式) 请输入字符:”;
  • 在发送区输入任意字符(如“123”),点击发送,接收区回显该字符;
  • 输入回车(\r),接收区显示“已接收字符,等待下一次输入…”,验证查询模式收发正常。

四、实战3:中断模式收发数据(高效版)

查询模式会阻塞主程序,中断模式通过收发中断实现异步通信,适合高频率、实时性要求高的场景。

1. 中断配置与代码实现

#include"stm32f10x.h"#include<stdio.h>u8 recv_buf[100];// 接收缓冲区u8 recv_len=0;// 接收数据长度u8 recv_flag=0;// 接收完成标志(回车触发)// USART1初始化(含中断配置)voidUSART1_Init(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;// 1. 使能时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);// 2. GPIO配置GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA,&GPIO_InitStructure);// 3. USART参数配置USART_InitStructure.USART_BaudRate=9600;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);// 4. 中断配置// 开启接收中断USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);// NVIC配置NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;// 抢占优先级1NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;// 子优先级0NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);// 5. 使能USART1USART_Cmd(USART1,ENABLE);}// 重定向printfintfputc(intch,FILE*f){while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);USART_SendData(USART1,(u8)ch);returnch;}// USART1中断服务函数voidUSART1_IRQHandler(void){u8 recv_data;// 接收中断触发if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET){recv_data=USART_ReceiveData(USART1);// 读取接收数据if(recv_data!='\r')// 未接收到回车,存入缓冲区{recv_buf[recv_len]=recv_data;recv_len++;// 防止缓冲区溢出if(recv_len>=99)recv_len=0;}else// 接收到回车,标记接收完成{recv_buf[recv_len]='\0';// 字符串结束符recv_flag=1;// 置位完成标志recv_len=0;// 重置长度}USART_ClearITPendingBit(USART1,USART_IT_RXNE);// 清除中断标志}}// 主函数测试intmain(void){USART1_Init();printf("STM32 USART1 Test (中断模式)\r\n");printf("请输入字符串(回车结束):\r\n");while(1){if(recv_flag==1)// 检测到接收完成{// 回显接收到的字符串printf("已接收:%s\r\n",recv_buf);// 重置标志recv_flag=0;printf("请继续输入:\r\n");}// 主循环可执行其他任务(如LED闪烁),不被串口阻塞}}

2. 串口调试助手验证

  • 硬件连接、串口助手配置同查询模式;
  • 下载程序后,串口助手接收区显示“STM32 USART1 Test (中断模式) 请输入字符串(回车结束):”;
  • 在发送区输入任意字符串(如“hello stm32”),点击发送;
  • 串口助手接收区回显“已接收:hello stm32”,且主程序可同时执行其他任务(如添加LED闪烁代码,验证中断不阻塞主循环)。

五、进阶配置:修改波特率(115200bps)

实际开发中115200bps更常用,仅需修改USART_Init中的波特率参数,并重新计算BRR值:

// 波特率改为115200USART_InitStructure.USART_BaudRate=115200;

STM32F103 APB2时钟72MHz时,115200波特率的BRR值由硬件自动计算,无需手动配置,仅需同步修改串口调试助手的波特率为115200即可。

六、Keil调试与问题排查技巧

1. Keil调试验证中断流程

  • 编译工程后,点击“Debug”进入调试模式;
  • 打开“Watch & Call Stack Window”,添加recv_flagrecv_lenrecv_buf
  • 启动调试(Run),在串口助手发送字符串,暂停调试后查看变量:
    • recv_len随接收字符递增;
    • 发送回车后,recv_flag变为1,recv_buf存储完整字符串;
  • 断点调试:在USART1_IRQHandler函数内添加断点(F9),触发接收中断时自动暂停,分析中断执行流程。

2. 常见问题与解决

问题1:串口无数据输出
  • 排查点1:GPIO配置错误(PA9是否为复用推挽,PA10是否为浮空输入);
  • 排查点2:时钟未使能(RCC_APB2Periph_USART1/RCC_APB2Periph_GPIOA);
  • 排查点3:USART未使能(USART_Cmd(USART1, ENABLE));
  • 排查点4:硬件连接错误(TX/RX交叉连接,未共地)。
问题2:接收数据乱码
  • 排查点1:波特率不匹配(Keil配置与串口助手波特率一致);
  • 排查点2:系统时钟错误(确认STM32主频为72MHz,而非8MHz);
  • 排查点3:硬件干扰(缩短杜邦线,远离电源模块)。
问题3:中断不触发
  • 排查点1:未开启接收中断(USART_ITConfig(USART1, USART_IT_RXNE, ENABLE));
  • 排查点2:NVIC优先级配置错误(抢占/子优先级未合理分配);
  • 排查点3:中断标志未清除(USART_ClearITPendingBit)。
问题4:缓冲区溢出
  • 解决方法:在中断服务函数中增加缓冲区长度判断,超出阈值时重置长度;
  • 优化方案:采用环形缓冲区,提升数据存储效率。

七、实战扩展:多字节/协议收发

实际项目中常需收发结构化数据(如传感器数据、控制指令),可基于中断模式扩展:

// 示例:接收自定义协议(帧头0xAA + 数据 + 校验位 + 帧尾0xFF)voidUSART1_IRQHandler(void){staticu8 protocol_buf[20];staticu8 protocol_len=0;u8 recv_data;if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET){recv_data=USART_ReceiveData(USART1);// 帧头检测if(protocol_len==0&&recv_data!=0xAA)return;// 存入协议缓冲区protocol_buf[protocol_len]=recv_data;protocol_len++;// 帧尾检测(假设协议长度固定为8字节)if(protocol_len==8&&protocol_buf[7]==0xFF){// 校验位验证(示例:前6字节和 = 第7字节前的校验位)u8 check_sum=0;for(u8 i=1;i<6;i++)check_sum+=protocol_buf[i];if(check_sum==protocol_buf[6]){// 协议校验通过,处理数据printf("协议接收成功:");for(u8 i=0;i<8;i++)printf("%02X ",protocol_buf[i]);printf("\r\n");}protocol_len=0;// 重置}// 超时/溢出处理if(protocol_len>=19)protocol_len=0;USART_ClearITPendingBit(USART1,USART_IT_RXNE);}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 5:41:39

【游戏AI架构升级】:行为树优化的7种高阶策略全公开

第一章&#xff1a;行为树优化的核心理念 行为树作为一种强大的任务调度与决策建模工具&#xff0c;广泛应用于游戏AI、机器人控制和自动化系统中。其核心优势在于将复杂的行为逻辑分解为可复用、可组合的节点&#xff0c;从而提升系统的可维护性与扩展性。然而&#xff0c;随着…

作者头像 李华
网站建设 2026/5/25 15:05:18

纤维协程异常处理实战(99%开发者忽略的关键细节)

第一章&#xff1a;纤维协程异常处理的核心挑战在现代高并发系统中&#xff0c;纤维&#xff08;Fiber&#xff09;作为一种轻量级线程模型&#xff0c;被广泛应用于协程调度。然而&#xff0c;其异常处理机制相较于传统线程更为复杂&#xff0c;主要源于执行上下文的动态切换与…

作者头像 李华
网站建设 2026/5/24 10:45:50

纤维协程超时配置避坑手册(资深架构师20年经验总结)

第一章&#xff1a;纤维协程超时配置的核心概念在现代高并发服务架构中&#xff0c;纤维协程&#xff08;Fiber Coroutine&#xff09;作为一种轻量级执行单元&#xff0c;广泛应用于提升系统吞吐量与资源利用率。超时配置是保障协程不无限阻塞、避免资源泄漏的关键机制。合理的…

作者头像 李华
网站建设 2026/5/26 1:29:06

【高并发系统设计必修课】:纤维协程调度模型全剖析

第一章&#xff1a;纤维协程的任务调度在现代高并发系统中&#xff0c;纤维协程&#xff08;Fiber Coroutine&#xff09;作为一种轻量级执行单元&#xff0c;显著提升了任务调度的效率与灵活性。与操作系统线程不同&#xff0c;纤维协程由用户态调度器管理&#xff0c;避免了内…

作者头像 李华
网站建设 2026/5/25 12:51:37

还在手动处理API响应?Symfony 8自动格式化功能全揭秘

第一章&#xff1a;Symfony 8 响应格式化的变革意义Symfony 8 在响应格式化机制上的演进&#xff0c;标志着框架在构建现代化 API 方面迈出了关键一步。通过内置更智能的序列化策略和内容协商机制&#xff0c;开发者能够以声明式方式定义响应结构&#xff0c;大幅减少手动处理 …

作者头像 李华
网站建设 2026/5/25 16:43:14

揭秘PHP 8.6性能瓶颈:如何利用新特性打造超强监控系统

第一章&#xff1a;PHP 8.6 的性能监控面板PHP 8.6 引入了内置的轻量级性能监控面板&#xff0c;开发者无需依赖第三方扩展即可实时查看脚本执行效率、内存使用和函数调用堆栈。该功能专为开发与调试环境设计&#xff0c;可通过配置快速启用&#xff0c;帮助定位性能瓶颈。启用…

作者头像 李华