2026/2/14 17:32:12
网站建设
项目流程
可以做公众号的网站,如何做国外网站彩票的推广,兰州市七里河建设局网站,搜索公司信息的软件手把手教你用 Keil 玩转 STM32 串口通信#xff1a;从零到“Hello World”的完整实战当你的 STM32 不说话#xff1f;可能是 UART 没调通你有没有遇到过这样的场景#xff1a;代码烧进去了#xff0c;开发板也上电了#xff0c;但串口助手却一片漆黑——没有一个字输出。或…手把手教你用 Keil 玩转 STM32 串口通信从零到“Hello World”的完整实战当你的 STM32 不说话可能是 UART 没调通你有没有遇到过这样的场景代码烧进去了开发板也上电了但串口助手却一片漆黑——没有一个字输出。或者更糟屏幕上全是乱码像外星人发来的密文。别急这几乎是每个嵌入式新手都会踩的坑。而问题的核心往往就出在UART 配置上。今天我们就来彻底解决这个问题。不讲虚的只说干货——带你用Keil MDK STM32F103C8T6实现稳定可靠的串口收发做到“我说你听你说我回”真正打通 MCU 和 PC 之间的第一条数据通道。整个过程将涵盖硬件连接、工程搭建、时钟配置、GPIO映射、波特率计算、数据收发逻辑以及常见问题排查。全程基于标准外设库StdPeriph让你看懂每一行代码背后的含义。准备好了吗我们开始。为什么是 UART它凭什么成为嵌入式的“普通话”在五花八门的通信协议中UART 虽然古老却是最实用的一种。它不需要同步时钟线只需要两根线TX 和 RX就能完成全双工通信适合点对点、低速到中速的数据传输。STM32 几乎每款芯片都集成了多个 USART/UART 外设。以经典的STM32F103C8T6俗称“蓝丸子”为例USART1挂载在 APB2 总线最高时钟 72MHz支持高速通信USART2挂载在 APB1 总线最高时钟 36MHzUART3同样在 APB1功能略少它们都能实现异步串行通信支持可编程波特率如 9600、115200、8位或9位数据位、奇偶校验、1~2位停止位等参数。更重要的是所有调试日志、AT指令交互、Bootloader升级几乎都依赖 UART。可以说不会 UART等于不会嵌入式开发。先搞明白UART 是怎么传数据的UART 的通信是“异步”的意味着发送方和接收方没有共享时钟信号。那它是如何保持同步的呢答案是双方提前约定好波特率。比如我们都设为 115200 bps即每秒传送 115200 个比特。然后靠这个节奏来采样每一位数据。一个典型的数据帧结构如下字段内容说明起始位1 bit低电平表示帧开始数据位8 bit常用低位先发校验位可选1 bit用于简单错误检测停止位1 或 2 bit高电平帧结束标志举个例子你要发字符AASCII 0x41 0b01000001实际在线上传输的顺序是[起始位] 1 0 0 0 0 0 1 0 [停止位] ↑ LSB ↑ MSB注意低位在前STM32 的 UART 模块通过几个关键寄存器控制这一切USART_DR写入要发送的数据或读取接收到的数据USART_SR查看状态比如 TXE发送缓冲空、RXNE接收非空USART_BRR设置波特率分频系数USART_CR1~CR3启用发送/接收、中断、DMA 等功能只要把这些寄存器配对了UART 就能跑起来。引脚怎么接别让 GPIO 成了拦路虎再好的配置如果引脚没接对也是白搭。对于 STM32F103C8T6 来说USART1_TX→ PA9USART1_RX→ PA10这两个引脚必须配置为复用功能模式PA9TX复用推挽输出AF_PPPA10RX浮空输入IN_FLOATING为什么这么配TX 是输出要驱动外部电路所以用推挽RX 是输入等待对方送信号进来不用上下拉避免干扰原始电平。同时别忘了开启对应外设时钟这是很多初学者忽略的关键一步。STM32 默认关闭所有外设时钟以省电所以我们得手动打开RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);APB2因为 USART1 属于高速总线 APB2而 GPIOA 也在同一组必须一起开。波特率怎么算别让误差毁了一切波特率不准通信必崩。理想情况下接收端应在每位中间采样但如果频率偏差太大±3%就会采样错位导致乱码。STM32 的波特率由以下公式决定$$\text{BaudRate} \frac{f_{PCLK}}{16 \times (\text{DIV_Mantissa} \frac{\text{DIV_Fraction}}{16})}$$其中- 若是 USART1APB2$ f_{PCLK} 72MHz $- 若是 USART2/3APB1$ f_{PCLK} 36MHz $我们想要115200 bps代入计算$$\frac{72000000}{16 \times 115200} ≈ 39.0625$$所以整数部分DIV_Mantissa 39小数部分DIV_Fraction 10.0625 × 16 1幸运的是标准库已经帮我们封装好了USART_InitStructure.USART_BaudRate 115200;内部会自动计算并写入 BRR 寄存器。但建议你在设计时优先选择能让分频结果为整数的波特率例如 72MHz 下 115200 刚好接近整除误差仅 0.15%非常安全。上手写代码从初始化到回环测试下面这段代码是你实现 UART 通信的“最小可行系统”。#include stm32f10x.h #define BUFFER_SIZE 64 void USART1_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 1. 开启时钟GPIOA 和 USART1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 2. 配置 PA9 为复用推挽输出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); // 3. 配置 PA10 为浮空输入RX GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); // 4. 配置 USART1 参数 USART_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_Rx | USART_Mode_Tx; // 收发模式 USART_Init(USART1, USART_InitStructure); // 5. 启动 USART1 USART_Cmd(USART1, ENABLE); } // 发送单字节 void USART_SendChar(USART_TypeDef* USARTx, uint8_t ch) { while (!USART_GetFlagStatus(USARTx, USART_FLAG_TXE)); // 等待发送缓冲空 USART_SendData(USARTx, ch); } // 发送字符串 void USART_SendString(USART_TypeDef* USARTx, char *str) { while (*str) { USART_SendChar(USARTx, *str); } } int main(void) { char rxBuffer[BUFFER_SIZE]; int len 0; USART1_Config(); USART_SendString(USART1, STM32 UART通信已启动\r\n); while (1) { if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { // 收到数据 rxBuffer[len] USART_ReceiveData(USART1); // 判断是否收到换行符或缓冲满 if (len BUFFER_SIZE - 1 || rxBuffer[len-1] \n) { rxBuffer[len] \0; // 添加字符串结束符 USART_SendString(USART1, 你输入的是: ); USART_SendString(USART1, rxBuffer); len 0; // 清空缓冲区 } } } }关键点解读RCC_APB2PeriphClockCmd()必须先开时钟否则后面配置无效。GPIO_Mode_AF_PP复用推挽TX 才能正常输出高/低电平。USART_FLAG_RXNE表示接收数据寄存器非空可以读取。主循环采用轮询方式监听数据适合入门学习后续可升级为中断或 DMA。运行效果你在串口助手输入任意内容MCU 会原样回显并加上前缀你输入的是: 。Keil 工程怎么建一步步带你走通流程现在回到 Keil uVision教你从零创建一个可用的工程。第一步新建项目打开 Keil uVisionProject → New uVision Project保存路径不要有中文选择芯片型号STM32F103C8✅ 提示Keil 会自动加载对应的启动文件startup_stm32f10x_md.s第二步添加源文件你需要把以下文件加入项目system_stm32f10x.c系统时钟初始化startup_stm32f10x_md.s启动汇编Keil 自动加stm32f10x_usart.c,stm32f10x_gpio.c,stm32f10x_rcc.c标准外设库源码你的主程序main.c建议建立如下分组Project ├── User ← main.c ├── Drivers ← stm32f10x_xx.c ├── CMSIS ← core_cm3.c, startup file └── Config ← system_stm32f10x.c第三步配置编译选项右键“Target” → Options for Target【Output】标签页✔ Generate HEX File方便后期使用下载工具【Debug】标签页Use ST-Link Debugger选择仿真器Settings → Connect: SWD → Max Clock 设为 4MHz稳定优先【C/C】标签页Define:USE_STDPERIPH_DRIVER, STM32F10X_MDInclude Paths:.\Inc .\Libraries\CMSIS .\Libraries\StdPeriph_Driver\inc【User】标签页可选在 After Build/Rebuild 中勾选 “Run #1”输入C:\Program Files\STMicroelectronics\Software\Flash Loader Demonstrator\FlashLoader.exe $LH这样编译后可自动调用 STM32 Flash Loader 工具下载程序。硬件怎么连一根 USB-TTL 搞定一切你需要一块USB 转 TTL 模块常用 CH340G 或 CP2102 芯片模块引脚接 STM32GNDGNDTXDPA10 (RX)RXDPA9 (TX)VCC3.3V慎接5V⚠️ 注意事项-不要同时接 ST-Link 和 USB-TTL 的 VCC可能导致电源冲突- 如果使用独立供电确保共地GND 连在一起- PA9/PA10 不要接其他负载避免影响通信电平PC 端使用串口助手如 XCOM、SSCOM、PuTTY打开对应 COM 口波特率设为 1152008-N-1。上电后你应该立刻看到STM32 UART通信已启动接着输入任何内容比如hello 回车会收到你输入的是: hello恭喜你已经打通了第一道通信关卡遇到问题怎么办这些“坑”我都替你踩过了别慌下面是高频故障排查清单现象可能原因解决方法完全无输出未开启 RCC 时钟检查RCC_APB2PeriphClockCmd是否包含 USART1 和 GPIOA输出乱码波特率不一致双方确认都是 115200且主频配置正确下载失败ST-Link 驱动未装 / 接线松更新驱动检查 SWCLK/SWDIO 是否接触良好收不到数据RX 引脚配置错误确保 PA10 是IN_FLOATING不是模拟输入或其他模式程序跑飞堆栈溢出或中断未处理增大栈大小添加HardFault_Handler打印异常串口助手收不到回车缺少\r\nWindows 串口通常需要\r\n才能换行显示还有一个隐藏陷阱串口助手默认发送的是 ASCII 字符但可能带 CR/LF。如果你只判断\n记得在助手里勾选“发送新行”。进阶思路下一步你可以做什么你现在掌握的是“轮询 缓冲区”的基础模型。接下来可以尝试1. 改用中断接收减少 CPU 占用提升响应速度USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART1_IRQn);在USART1_IRQHandler()中处理接收事件。2. 重定向printf让 C 标准库的printf直接输出到串口int fputc(int ch, FILE *f) { USART_SendChar(USART1, ch); return ch; }之后就可以直接printf(ADC Value: %d\r\n, value);调试了。3. 结合传感器做数据上报比如读取 DHT11 温湿度通过串口传给 PC 显示。4. 对接 ESP8266/WiFi 模块用 AT 指令控制模块联网实现远程监控。写在最后UART 是起点不是终点当你第一次看到自己的 STM32 在串口助手中说出“Hello World”那种成就感就像第一次点亮 LED 一样纯粹。但请记住UART 不是用来炫技的而是解决问题的工具。它是你调试系统的耳朵和嘴巴是你与设备对话的语言。掌握了它你就拿到了进入嵌入式世界的第一把钥匙。未来你可以用 HAL 库、CubeMX 快速生成代码也可以玩 FreeRTOS 多任务调度甚至用 DMA 实现零拷贝通信。但无论技术如何演进理解底层原理的人永远拥有更强的掌控力。如果你正在学习 STM32不妨现在就打开 Keil照着这篇文章动手试一遍。只有亲手让代码跑起来才算真正学会。有任何问题欢迎留言讨论。我们一起把每一个“不说话”的板子变成会思考的智能终端。热词索引Keil、STM32、UART、USART、串口通信、波特率、GPIO、RCC、中断、DMA、Hex文件、SWD、标准外设库、嵌入式系统、调试器