STM32串口通信入门:从零基础到第一个例子跑通
简介这份资源面向正在学习STM32单片机、需要打通双板串口通信的嵌入式初学者与进阶开发者基于正点原子mini板与精英板搭建了一套可实际运行的USART通信方案mini板经USART3PB10、PB11发送数据精英板经USART3接收并通过USART1CH340下载口打印到串口调试助手同时支持LCD屏实时显示接收内容接收成功与发送成功分别以LED10、LED1翻转作为状态指示。资源包共321个文件约7.35MB以69个h头文件、66个c源文件为核心配合Keil工程文件、编译中间产物与hex烧录文件完整保留了工程目录与调试痕迹便于直接编译验证或按需裁剪。若手头没有mini板可用串口助手模拟发送端没有LCD屏时注释掉相应初始化代码即可运行。目前已有4418人学习下载适合用来理解串口收发流程、中断处理与多板协同调试思路。1. 从一根线开始STM32 串口通信到底在做什么很多人第一次听到“STM32 串口通信”脑子里冒出来的是一堆引脚、寄存器、波特率还没开始就想关掉页面。其实你可以先把它想成两个人隔着一条走廊喊话一个人喊“温度 25 度”另一个人听见了点点头记下来。串口通信就是两块芯片之间约定好节奏用一根线发、一根线收把一句话一个字地传过去。STM32 是常见的单片机串口通信是它最基础、最便宜、也最常用的对外说话方式。你手里的开发板想告诉电脑“我准备好了”或者电脑想让它“把灯打开”走串口是最省事的路。这篇入门就是带零基础的你从“这到底是什么”一路走到“第一个例子能跑起来”不深挖寄存器原理先把线接对、把字发出去。2. 为什么新手该先学串口它是最便宜的调试窗口2.1 串口是单片机的“黑匣子”不会它等于闭眼调程序刚上手 STM32 的人最容易犯的错是把程序烧进去然后盯着板子发呆灯不亮到底是程序没跑、引脚接错还是芯片根本没启动这时候串口就是你的黑匣子。只要在代码里加一句“打印一句话”电脑上的串口助手就能看到板子到底走到了哪一步。没有这个窗口你只能靠猜猜一次烧一次血泪经验就是这么攒出来的。串口通信还有一个好处它对硬件要求极低。两根数据线加一根地线就能完成一次对话。你不需要屏幕、不需要网络模块甚至不需要额外的调试器只要一块 STM32 开发板和一个能把 USB 转成串口的模块就能开始。对零基础的人来说门槛越低越容易迈出第一步。我第一次学的时候导师只说了一句先把“Hello”发到电脑上再谈别的。当时不理解后来才发现能稳定收发一句话后面接传感器、接屏幕、接另一个单片机都是在这句话的基础上加内容。串口不是终点它是你和板子之间建立信任的第一条通道。2.2 先分清两个概念串口外设和 USB 转串口新手最容易混淆的是STM32 上的串口引脚和电脑上的 USB 口不是一回事。STM32 输出的是 TTL 电平的串口信号电脑的 USB 口说的是另一套语言。中间需要一个“翻译”也就是 USB 转串口模块常见的是把 USB 转成 TTL 串口的那类小板子。接线的时候记住三根线模块的 TX 接 STM32 的 RX模块的 RX 接 STM32 的 TXGND 接 GND。TX 是“我说”RX 是“我听”所以两边的说和听要交叉接。很多人第一次翻车就是把 TX 对 TX 接上了结果两边都在说没人听串口助手一片空白。提示接线前先断电接完再上电。TX 和 RX 接反不会烧板子但会让你怀疑人生先检查这两根线永远是排查第一步。2.3 波特率是什么两个人说话得先对上节奏串口通信里有一个绕不开的参数叫波特率你可以把它理解成“每秒说多少个字”。两边必须用同一个波特率否则收到的就是乱码。常见的是 9600 和 115200入门先用 9600慢一点但稳等跑通了再改快。除了波特率还有数据位、停止位、校验位这几个参数。入门阶段你只需要记住一组最常见的组合8 位数据位、1 位停止位、无校验简称 8-N-1。STM32 的串口初始化里把这几个参数配成和串口助手一致通信就成功了一半。为什么强调“一致”因为串口没有握手确认发方按自己的节奏发收方按自己的节奏收节奏对不上收到的就是一堆问号。这不是玄学是双方没有对齐时间基准。所以每次换波特率两边都要改只改一边必然乱码。3. 动手前的准备把第一个例子需要的环境和接线搭好3.1 你需要哪些东西一块板、一个转接模块、两根杜邦线入门不需要很贵的设备。一块 STM32 开发板一个 USB 转 TTL 串口模块几根杜邦线再加上电脑上装好开发环境就齐了。开发环境用常见的 STM32 集成开发环境即可新建工程时选和你板子对应的芯片型号这一步选错后面编译能过但跑不起来。串口助手可以用电脑上任意一个能收发的串口工具打开后选对端口号。端口号在设备管理器里能看到插上转接模块后会多出一个串口设备。如果看不到先检查模块驱动有没有装好这是新手第一个常见卡点。注意板子和转接模块要共地也就是 GND 必须连在一起。只接 TX 和 RX 不接地通信会时好时坏这种问题最难查。3.2 第一个例子让 STM32 每隔一秒发一句话下面这段代码是入门最经典的“串口打印”用轮询方式发送不涉及中断逻辑最直白。你只需要把串口初始化好然后在主循环里定时发一句话。#include stm32f10x.h // 按你实际芯片型号替换对应头文件 #include stdio.h /* 串口1初始化9600 波特率8 数据位1 停止位无校验 */ void UART1_Init(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef uart; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); /* PA9 作为 TX复用推挽输出 */ gpio.GPIO_Pin GPIO_Pin_9; gpio.GPIO_Mode GPIO_Mode_AF_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, gpio); /* PA10 作为 RX浮空输入 */ gpio.GPIO_Pin GPIO_Pin_10; gpio.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, gpio); uart.USART_BaudRate 9600; uart.USART_WordLength USART_WordLength_8b; uart.USART_StopBits USART_StopBits_1; uart.USART_Parity USART_Parity_No; uart.USART_Mode USART_Mode_Tx | USART_Mode_Rx; uart.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_Init(USART1, uart); USART_Cmd(USART1, ENABLE); } /* 发送一个字节等发送寄存器空再写下一个 */ void UART1_SendByte(uint8_t data) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, data); } /* 发送字符串 */ void UART1_SendString(char *str) { while (*str) { UART1_SendByte(*str); } } /* 粗略延时仅用于入门演示 */ void Delay(volatile uint32_t count) { while (count--); } int main(void) { UART1_Init(); while (1) { UART1_SendString(Hello STM32\r\n); Delay(8000000); // 大约一秒具体时长和主频有关 } }这段代码做了三件事先把 PA9 和 PA10 配成串口功能再把串口参数设成 9600、8-N-1最后在主循环里反复发同一句话。USART_FLAG_TXE这个标志位的意思是“发送寄存器空了可以放下一个字节了”不加这个判断连续发会丢字。\r\n是回车换行不加的话串口助手会把所有内容挤在一行。烧录进去之后打开串口助手选对端口号波特率设成 9600你应该能看到每秒刷出一行“Hello STM32”。如果看到的是乱码先查波特率如果什么都没有先查 TX/RX 有没有接反、GND 有没有接。3.3 参数怎么改从 9600 换到 115200 要动哪里等你跑通第一句话可以试着把波特率改快。代码里只改一处uart.USART_BaudRate 115200;同时把串口助手的波特率也改成 115200两边一起改才有效。改完重新编译烧录如果出现乱码说明有一边没改对或者板子的实际主频和工程配置不一致。数据位和停止位一般不用动入门阶段保持 8-N-1 最省心。校验位在短距离、低干扰的场景下可以不开等以后接长线或者工业环境再考虑。参数不是越多越好先让通信稳定跑起来比一次配一堆参数更有意义。4. 从发到收让 STM32 听懂你发过去的字4.1 轮询接收最简单但会“卡住”的写法会发之后下一步是收。最简单的接收方式是轮询在主循环里不停问“有没有收到数据”。下面这段代码把收到的字符原样发回去也就是常说的回显。int main(void) { uint8_t ch; UART1_Init(); while (1) { /* 等待接收寄存器非空说明来了一个字节 */ if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) ! RESET) { ch USART_ReceiveData(USART1); // 读走数据标志位自动清除 UART1_SendByte(ch); // 原样发回电脑 } } }USART_FLAG_RXNE表示接收寄存器里有新数据读到数据后这个标志会自动清掉。你在串口助手里发一个字符就能看到它被原样送回来。这个例子的价值在于让你确认“收”这条路是通的。但轮询有个明显问题程序会一直守在这里等别的事干不了。入门阶段先用它建立信心等你要同时点灯、读传感器就得换成中断方式。4.2 中断接收让串口在后台帮你收字中断的思路是平时主程序干自己的事串口一收到数据就“打断”一下把数据存起来然后继续干原来的事。这样接收不占主循环。配置中断需要在初始化里多开一步并写一个中断服务函数。/* 在 UART1_Init 末尾加上这一句开启接收中断 */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 中断服务函数名字要和启动文件里的一致 */ void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { uint8_t data USART_ReceiveData(USART1); UART1_SendByte(data); // 入门演示收到就回发 USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }中断服务函数要尽量短别在里面做延时或者复杂计算否则会拖慢整个系统。入门阶段收到就回发没问题等以后要处理一整条指令建议在中断里只把数据塞进缓冲区主循环再去解析。4.3 两块 STM32 互发把 TX 接到对方的 RX串口不只是和电脑说话两块 STM32 之间也能用同样的方式对话。把板子 A 的 TX 接板子 B 的 RXA 的 RX 接 B 的 TX两块板 GND 相连各自跑一个“发一句话”和“收一句话”的程序就能看到 A 发的字出现在 B 的串口助手上。这里的关键是两边波特率必须一致接线必须交叉。很多新手把两块板都配成发送结果谁都收不到。记住一句话说的人接听的人听的人接说的人。两块板通信跑通之后你就具备了做简单主从系统的基础比如一块板采集数据另一块板负责显示。5. 避坑与排查新手最容易翻车的五个地方5.1 串口助手一片空白什么也收不到现象是程序烧进去了串口助手没有任何显示。原因通常是接线或端口选错TX/RX 接反、GND 没接、串口助手选错了端口号或者波特率两边不一致。解决顺序是先确认设备管理器里能看到串口设备再核对 TX 对 RX、RX 对 TX最后检查两边波特率是否相同。按这个顺序查大部分空白问题都能定位。5.2 收到的是乱码像一堆问号和方块现象是能看到数据在动但全是乱码。原因几乎都是波特率不匹配或者板子实际主频和工程里配置的主频不一致导致实际波特率偏移。解决方法是先把两边都设成 9600 再试确认工程里的晶振频率和板子一致。如果换了板子还乱码优先怀疑主频配置而不是代码逻辑。5.3 发几个字就丢字或者只收到第一个字符现象是发一串字符对方只收到开头一两个。原因常见于发送时没有等发送完成标志连续写数据把寄存器覆盖了或者接收方处理太慢缓冲区溢出。解决方法是发送每个字节前判断USART_FLAG_TXE接收端用中断加缓冲区别在主循环里做长延时。入门阶段先把发送节奏放慢确认稳定再提速。5.4 程序一下载就卡死串口没反应现象是烧录后板子像没跑起来。原因可能是中断服务函数名字写错导致中断来了找不到入口也可能是初始化里开了中断但没配中断优先级。解决方法是核对中断函数名和启动文件里的一致检查中断优先级配置有没有漏。入门先用轮询跑通再上中断能少踩很多坑。5.5 换一块板子就不行了代码明明没改现象是同一份代码在 A 板能跑换 B 板就不行。原因是不同芯片的串口引脚、时钟总线、头文件不一样。解决方法是对照新板子的原理图确认 TX/RX 落在哪个引脚改对应的 GPIO 和时钟配置。串口通信的代码结构可以复用但引脚映射必须按板子改这一步没有捷径。6. 下一步学什么从会发一句话到能做一个小项目跑通“发一句话”和“收一个字符”之后你已经跨过了串口入门最难的门槛。接下来不建议马上去啃寄存器手册而是按“能用的顺序”往上加东西。第一步把发送封装成一个带格式的函数能打印变量比如把温度值拼进字符串发出来这样你就能用串口观察传感器数据。第二步学中断加环形缓冲区让接收一整条指令不丢字这是做命令行式交互的基础。第三步定一个简单的通信协议比如“开头一个标志字节 数据 结尾一个标志字节”两块板之间按这个格式收发你就有了一个最小可用的主从系统。学习路径可以按这个顺序走先轮询收发再中断收发然后缓冲区加协议解析最后接一个真实传感器做数据上报。每一步都只加一个新东西加完立刻用串口助手验证别一次改太多。下面这张表可以帮你判断自己走到哪一步阶段能做什么验证方式入门定时发一句话串口助手看到固定字符串进阶收到字符并回显发一个字符收到一个字符提高中断接收不丢字连续发一串字符全部收到实战按协议收发数据两块板按约定格式对话我第一次带新人时总想一次把中断、缓冲区、协议全讲完结果对方当场就懵了。后来改成一次只加一个功能每加一个就让他自己用串口助手看一眼进度反而快。从那以后我每次教串口都强制让对方先把“Hello”发出来再往下走发不出来就查线不查代码。希望这份入门指南能帮你把第一句话发出去剩下的路一句一句加就行。本文还有配套的精品资源点击获取