串口轮询:收发数据与 printf 打印
源码路径:
example/HC32F460JEUA/2.usart/uart_polling/source/main.c
1. 功能简介
这个例子做两件事:
- 回显(Echo):你在电脑串口助手里发一个字符,单片机原样发回来。发
A收到A,发hello收到hello。这是验证串口通不通的经典测试。 - printf 打印:程序启动时会往串口打印一句
test,证明printf已经被成功「接」到串口上了。
「轮询」是什么意思?就是 CPU 不停地去问:「有数据来了吗?有数据来了吗?」——问到了就处理。这和「中断」相对(中断是数据来了主动通知 CPU)。轮询最简单直观,适合入门;缺点是 CPU 一直在原地打转问,干不了别的事。
学会这个例子,你就拥有了串口调试能力——以后任何程序都能用 printf 把内部状态打到电脑上看,这是嵌入式开发最基本的生存技能。
2. 硬件准备
用 HC32F460JEUA KIT 开发板,板载有 USB 转串口,一根 USB 线搞定,不用额外接线。
|
|
如果你的板子没有板载转串口芯片,就要外接一个 USB-TTL 模块(如 CH340、CP2102),接法是交叉连:
|
|
两个新手必踩的坑:
- TX 接 RX,RX 接 TX(交叉),不是 TX 接 TX。想想「我的嘴对着你的耳朵」。
- 一定要共地(GND 相连),否则没有共同参考电平,通信必失败。
电脑端准备一个串口助手软件(如 sscom、友善串口助手、或 VSCode 串口插件),波特率设 115200。
3. 完整代码
|
|
4. 代码分段讲解
4.1 fputc 重定向——printf 能用的秘密
|
|
这是整个例子里最值得记住的一段。
C 语言的 printf 底层最终会一个字符一个字符地调用 fputc() 把内容「打」出去。默认情况下 fputc 不知道该往哪打(单片机又没显示器)。我们只要自己重写一个 fputc,在里面写「把这个字符从串口发出去」,printf 就自动改道走串口了。
从此以后,printf("温度 = %d\n", temp); 打印的内容就会出现在电脑串口助手里。这就是嵌入式调试的「打印大法」。
Keil (MDK) 环境下用这个方法,通常还要在工程里勾选 Use MicroLIB(微库),否则
printf会很大甚至链接不过。
4.2 初始化结构体 = 串口参数
|
|
这几行就是把「8-N-1」翻译成代码。要和串口助手那头设的一模一样。
4.3 波特率单独设
|
|
注意波特率不在初始化结构体里,而是单独一个函数设置。它内部会根据当前系统时钟频率算出分频系数,所以前面 BSP_CLK_Init() 必须先调,否则算出来的波特率是错的(→ 乱码)。
4.4 主循环:轮询回显
|
|
这就是「轮询」的精髓:CPU 在 while(1) 里反复检查 UsartRxNoEmpty 标志。一旦有数据,就读出来再发回去,形成回显。
4.5 错误处理别漏
UsartRxErrProcess() 检查三种错误(帧错误、校验错误、溢出错误)并清除标志。溢出错误(Overrun)尤其重要:如果数据来得太快、CPU 没及时读走,新数据会把旧数据冲掉并置位溢出标志,不清的话串口可能就卡住不再收了。
5. 实验现象
- 上电后,红灯亮(初始化完成的标志)。
- 电脑串口助手里立刻收到一行
test(printf 打印的)。 - 你在串口助手里发送任意字符,会原样收到同样的字符(回显)。发
123收123。
6. 常见问题
Q1:串口助手全是乱码 锟斤拷?
最经典的问题,按顺序排查:
- 串口助手波特率是不是 115200?(第一嫌疑)
- 数据位/停止位/校验是不是 8-N-1?
- 代码里
BSP_CLK_Init()调了没?没调时钟没对,波特率就是错的。
Q2:什么都收不到?
- 串口助手选的 COM 口对不对?(设备管理器里看 CH340 是哪个 COM)
- 外接 USB-TTL 的话,TX/RX 交叉了吗?GND 接了吗?
- 红灯亮了吗?没亮说明初始化就卡住了(可能
USART_UART_Init返回失败,被while(1)困住)。
Q3:printf 打印的中文乱码?
- 串口助手的编码要和源文件编码一致(一般选 GBK 或 UTF-8 试试)。英文一般不会乱。
Q4:能发但收不到回显?
- 检查 RX 引脚(PA10)复用配了没、接线对不对。发得出去说明 TX 没问题,收不到就是 RX 那条链路的事。
Q5:printf 打印很卡、或者程序变得很大编不过?
- Keil 里勾上 Use MicroLIB。
7. 小结
- 串口轮询 = CPU 反复查
UsartRxNoEmpty标志,有数据就处理。 - 配置顺序:开时钟 → 配引脚复用 →
USART_UART_Init→USART_SetBaudrate→ 使能收发。 - 重写
fputc就能让printf走串口,这是头号调试技能。 - 乱码找波特率,收不到找接线和 COM 口。
- 别忘处理接收错误(尤其溢出)。
8. 拓展应用
串口是通往无数项目的大门:
- 调试打印:任何项目都能用
printf输出变量、状态、日志。学会它,你的开发效率翻倍。 - 上位机通信:单片机采集数据(温度、电流),通过串口发给电脑上的 Python/C# 程序画曲线、存数据库。
- 蓝牙 / WiFi 模块:HC-05 蓝牙、ESP8266 WiFi 这类模块都是串口通信的,学会串口就能用手机/网络远程控制单片机。
- GPS 模块:GPS 定位模块输出的 NMEA 数据也是走串口,接进来解析就能做定位设备。
- 多机通信:两块单片机用串口互联,一主一从传数据。
- 命令行控制:做一个简单的串口命令解析器,在串口助手里敲
led on、led off就能控制设备,非常适合调试和演示。
下一步建议:把轮询升级成中断接收,CPU 就不用死等了,可以边收数据边干别的事。原理和「按键中断」那章相通。