STM32串口通信基础与HAL库实现
1. STM32串口通信基础与实验目标
在嵌入式系统开发中,串口通信是最基础也最常用的外设功能之一。STM32系列微控制器内置了USART(通用同步异步收发器)模块,能够灵活地实现设备与上位机之间的数据交互。本次实验的核心目标是使用STM32F103C8T6开发板,通过USART1模块向上位机(Windows系统)持续发送"Hello Windows!"字符串。
串口通信的本质是两位设备通过TX(发送)和RX(接收)两根信号线,按照约定的协议进行数据交换。在STM32中,USART模块支持全双工通信,意味着可以同时进行数据的发送和接收。对于初学者而言,理解以下几个关键参数至关重要:
- 波特率:决定数据传输速度,常见值有9600、115200等。本实验采用115200bps,即每秒传输115200位数据。
- 数据位:每个字符包含的位数,通常为8位。
- 停止位:标志一个字符传输结束,本实验使用1位停止位。
- 校验位:用于错误检测,本实验不启用。
提示:在嵌入式开发中,串口通信不仅是调试利器(通过printf输出调试信息),更是设备间通信的基础协议。掌握好串口通信,将为后续学习I2C、SPI等更复杂的通信协议打下坚实基础。
2. 硬件准备与环境搭建
2.1 所需硬件清单
要完成本实验,需要准备以下硬件设备:
- STM32F103C8T6开发板(蓝色药丸板)
- USB转TTL模块(如CH340、CP2102等)
- 杜邦线若干(建议使用母对母)
- Windows电脑(安装好串口调试助手)
2.2 硬件连接示意图
正确的硬件连接是实验成功的前提。按照以下方式连接设备:
STM32F103C8T6 USB转TTL模块 PA9(TX) ------> RX PA10(RX) ------> TX GND ------> GND 3.3V ------> 3.3V(可选,为模块供电)注意:STM32的TX引脚应连接USB转TTL的RX引脚,RX连接TX,这是初学者最容易接反的地方。如果连接后无法通信,首先检查这两根线是否接反。
2.3 开发环境配置
软件方面需要准备:
- Keil MDK-ARM开发环境(建议V5.25以上版本)
- STM32CubeMX图形化配置工具
- 串口调试助手(如SSCOM、Putty等)
安装STM32F1的Device Family Pack(DFP)包:
- 打开Keil,点击Pack Installer图标
- 搜索"STM32F1",安装最新版本的STM32F1xx_DFP
- 安装完成后,在新建项目时就能选择STM32F103C8系列芯片
3. 使用HAL库实现串口通信
3.1 CubeMX工程配置
STM32CubeMX极大简化了外设初始化流程。新建工程后,按以下步骤配置:
- 选择STM32F103C8Tx芯片
- 在Pinout视图中启用USART1:
- Mode选择"Asynchronous"
- 自动配置PA9为USART1_TX,PA10为USART1_RX
- 配置USART1参数:
- Baud Rate: 115200
- Word Length: 8 Bits
- Stop Bits: 1
- Parity: None
- Hardware Flow Control: Disable
- 时钟配置:
- HCLK设置为72MHz(STM32F103的最高主频)
- 在USART1配置中确保波特率准确显示为115200
生成代码时,选择Toolchain为MDK-ARM,并勾选"Generate peripheral initialization as a pair of .c/.h files"。
3.2 关键代码实现
CubeMX生成的代码已经完成了USART1的初始化,我们只需调用HAL库的发送函数即可。在main.c文件中添加以下代码:
/* 用户代码开始 0 */ uint8_t greeting[] = "Hello Windows!\r\n"; /* 用户代码结束 0 */ /* 在main函数的while循环中添加 */ while (1) { HAL_UART_Transmit(&huart1, greeting, sizeof(greeting)-1, HAL_MAX_DELAY); HAL_Delay(1000); // 每秒发送一次 }代码解析:
HAL_UART_Transmit函数参数依次为:USART句柄、发送数据缓冲区、数据长度、超时时间sizeof(greeting)-1是为了不发送字符串结尾的'\0'字符HAL_MAX_DELAY表示无限等待直到发送完成\r\n是回车换行符,确保每次发送后光标移动到下一行开头
3.3 重定向printf实现调试输出
为了方便调试,可以重定向printf到串口。在usart.c文件中添加以下代码:
#include <stdio.h> #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); return ch; }然后在工程属性的Target选项卡中,勾选"Use MicroLIB"。现在就可以使用printf输出了:
printf("System initialized!\r\n");4. 调试与问题排查
4.1 常见问题及解决方案
无输出或乱码
- 检查波特率是否匹配(双方必须严格一致)
- 确认硬件连接正确(TX-RX交叉连接)
- 测量晶振是否起振(部分板载晶振质量不佳)
只能接收部分字符
- 检查地线是否连接良好
- 尝试降低波特率测试(如改为9600)
- 检查电源稳定性(可并联100uF电容)
Keil编程后无反应
- 检查BOOT0和BOOT1引脚状态(正常运行时BOOT0应接地)
- 确认程序是否成功烧录(查看Keil输出窗口的编程进度)
4.2 逻辑分析仪调试
在没有示波器的情况下,Keil内置的逻辑分析仪是强大的调试工具。设置方法:
- 进入Debug模式,点击View -> Analysis Windows -> Logic Analyzer
- 点击Setup,添加要观察的信号:
- 输入"USART1_SR"观察状态寄存器
- 或直接监控PA9引脚
- 设置Display Type为"Bit"
- 运行程序,可以看到串口输出的波形时序
正常波形应该呈现规律的脉冲序列,每个字符的起始位为低电平,接着是8位数据位(LSB先发送),最后是高电平的停止位。
4.3 性能优化建议
- 中断方式:当前查询方式会阻塞CPU,实际项目中建议使用中断或DMA
- 环形缓冲区:建立发送/接收缓冲区提高通信效率
- 协议设计:添加帧头、校验和等提高通信可靠性
- 功耗优化:通信间隔期间可进入低功耗模式
5. 进阶应用与扩展
5.1 中断方式实现
修改CubeMX配置,启用USART1全局中断。然后修改发送代码:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { HAL_UART_Transmit_IT(&huart1, greeting, sizeof(greeting)-1); } } // 在main中启动第一次发送 HAL_UART_Transmit_IT(&huart1, greeting, sizeof(greeting)-1);5.2 自定义通信协议
一个简单的协议示例:
#pragma pack(1) typedef struct { uint8_t header; // 0xAA uint8_t cmd; uint8_t len; uint8_t data[32]; uint8_t checksum; } UART_Frame; #pragma pack() void SendFrame(uint8_t cmd, uint8_t* data, uint8_t len) { UART_Frame frame; frame.header = 0xAA; frame.cmd = cmd; frame.len = len; memcpy(frame.data, data, len); uint8_t sum = 0; for(int i=0; i<offsetof(UART_Frame, checksum); i++) sum += ((uint8_t*)&frame)[i]; frame.checksum = sum; HAL_UART_Transmit(&huart1, (uint8_t*)&frame, sizeof(frame), HAL_MAX_DELAY); }5.3 与Windows应用交互
可以使用Python的pyserial库开发上位机程序:
import serial ser = serial.Serial('COM3', 115200, timeout=1) while True: data = ser.readline().decode('ascii').strip() if data: print(f"Received: {data}") if data == "Hello Windows!": ser.write(b"ACK\r\n")6. 项目总结与工程实践建议
通过这个基础实验,我们实现了STM32与Windows系统之间的简单串口通信。在实际项目开发中,还需要注意以下几点:
抗干扰设计:
- 信号线使用双绞线
- 适当添加终端电阻(如120Ω)
- 在TX/RX线上串联33Ω电阻
错误处理机制:
- 添加超时重发功能
- 实现软件校验(如CRC16)
- 监控线路状态(如使用RS485时需要DE/RE控制)
多任务集成:
- 在RTOS中创建专用通信任务
- 使用消息队列传递通信数据
- 设置合理的任务优先级
生产测试考虑:
- 预留测试点(如引出TX/RX到排针)
- 实现自动化测试脚本
- 添加版本查询指令(如发送"VER?"返回固件版本)
串口通信作为嵌入式开发的基石,其稳定性和可靠性直接影响整个系统的表现。建议初学者在掌握基础用法后,进一步研究以下方向:
- 硬件流控制(RTS/CTS)
- 多串口协同工作
- 高速串口(如STM32H7系列的12.5Mbps)
- 无线串口(如通过蓝牙模块透传)
最后分享一个调试技巧:当通信异常时,可以尝试短接板载TX和RX引脚,发送的数据应立即回显,这是验证串口硬件是否正常的快速方法。
