这一章在干嘛?
串口通信实验:USART/UART 概念、波特率、帧格式、TX/RX 引脚复用、HAL 库阻塞与中断收发、printf 重定向、回环实验。理解后调试效率翻倍。
17.1 串口简介
17.1.1 数据通信的基础概念
| 术语 | 含义 |
|---|---|
| 单工 | A→B 单向 |
| 半双工 | A↔B 双向但不能同时 |
| 全双工 | A↔B 可同时收发 |
| 串行 | 数据一位一位发送 |
| 并行 | 数据一次多位发送 |
| 同步 | 带时钟线 |
| 异步 | 无时钟线,靠波特率约定 |
USART = 通用同步异步收发器,常用异步模式即「串口」。
17.1.2 串口通信协议
串口帧格式:
[起始位 0] [数据位 D0..D7] [校验位 P] [停止位 1]
| 参数 | 常用值 |
|---|---|
| 波特率 | 9600 / 115200 / 921600 |
| 数据位 | 8 |
| 校验位 | None |
| 停止位 | 1 |
| 流控 | None |
原书图 17.1.2.1:串口帧格式示意图
双方波特率误差不能超过 2%,否则数据错位。
17.1.3 STM32 的 USART/UART
F407 有 6 个 USART + 2 个 UART,USART 支持同步/异步,UART 仅异步。
USART1/2/3 在 APB2(84 MHz),USART4/5/6 + UART7/8 在 APB1(42 MHz × 2 = 84 MHz,但分频后是 42 MHz)。
17.2 硬件设计
USART1 TX → PA9,RX → PA10(开发板已经通过 CH340 转 USB 接出)。
17.3 程序设计
17.3.1 编程步骤
- 开启 GPIOA / USART1 时钟;
- 初始化 PA9/PA10 为复用推挽/浮空输入;
HAL_UART_Init(&huart1)配置 115200-8-N-1;- 发送:
HAL_UART_Transmit(&huart1, buf, len, timeout); - 接收:
HAL_UART_Receive_IT(&huart1, buf, 1);+ 回调。
17.3.2 关键代码
// 阻塞发送
HAL_UART_Transmit(&huart1, (uint8_t *)"Hello\n", 6, 100);
// 中断接收
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
HAL_UART_Transmit_IT(&huart1, &rx_byte, 1); // 回环
HAL_UART_Receive_IT(&huart1, &rx_byte, 1); // 重启接收
}
}
原书图 17.3.2.1:USART 框图
原书图 17.3.2.2:HAL_UART 收发流程图
17.3.3 printf 重定向
让 printf("...") 直接发到串口:
int fputc(int ch, FILE *f) {
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 10);
return ch;
}
MDK 勾选 Use MicroLIB。
MicroLIB 不支持浮点 printf:要用 sprintf + HAL_UART_Transmit 自己拼。
17.4 下载验证
XCOM 串口助手打开 COMx 115200 → 看到「Hello World」并支持键入字符回环。
原书图 17.4.1:串口助手回环实验现象
串口常用参数 115200-8-N-1 含义?
115200 波特率、8 数据位、无校验、1 停止位。
USART 与 UART 的区别?
USART 支持同步/异步,UART 仅异步。
为什么中断接收后要再调一次
HAL_UART_Receive_IT?HAL 中断模式只触发一次,必须手动重启。
printf 重定向的两个前提?
实现 fputc + 勾选 MicroLIB。