不少工程师在做多机串口通讯、RS485 地址帧、自定义串口协议时,都会用到9 位数据格式,但一上手就遇到各种问题:配置后不进中断、收不到数据、怀疑 HAL 库有 BUG。
ST 官方 LAT1361 应用笔记直接把这件事讲透:STM32 全系列 USART/LPUART 都支持 9 位数据,你遇到的问题基本都是配置或用法不对,不是芯片也不是库的问题。
资料获取:【应用笔记】LAT1361 STM32的USART能否支持9位数据格式话题
1. 官方明确结论
- STM32 所有型号的 USART 都支持 9 位数据格式
- L0、G4、F1、F4、H7、L4 等全部支持
- 9 位模式下无校验位,M 位配置为
01 - HAL 库完全支持,不存在 BUG
2. 9 位数据格式是什么样的?
根据 USART_CR1 的 M [1:0] 控制:
- M=01 + PCE=0 → 9 位数据 + 起始位 + 停止位
- 第 9 位可以用来做地址位、命令帧标记、自定义协议位
这是 RS485 多机通讯最常用的格式。
3. CubeMX 正确配置(关键步骤)
- Word Length:设为 9 Bits
- Parity:必须设为 None(9 位模式无校验)
- 使能 NVIC 中断(如果用中断方式)
- 建议 Over Sampling = 16
注意:选 9 位就不能开校验!开校验会变成 8 位数据 + 校验位,不是真正的 9 位。
4. 9 位数据收发怎么写?(HAL 库正确用法)
因为是 9 位,数据必须用 uint16_t 来存放。
4.1 定义数组(必须 16 位)
uint16_t TxData[5];
uint16_t RxData[5];
4.2 中断方式收发
HAL_UART_Transmit_IT(&huart1, (uint8_t *)TxData, 5);
HAL_UART_Receive_IT(&huart1, (uint8_t *)RxData, 5);
虽然强转成uint8_t*,但底层会按半字(16bit)处理。
4.3 DMA 方式(更稳定)
DMA 配置要点:
- Data Width:Half Word(半字)
- 发送:Normal 模式
- 接收:可设 Circular 模式
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)TxData, 5);
HAL_UART_Receive_DMA(&huart1, (uint8_t *)RxData, 5);
5. 客户遇到的 “9 位不进中断” 问题根因
LAT1361 里客户的问题:
- 配置 9 位数据
- RXNE 置 1,但不进中断
- 数据读不出
官方定位结果:不是库问题,是硬件引脚未连接 / GPIO 配置错误。换一个 USART,检查 GPIO 跳线后,立刻正常。
6. 9 位模式最容易踩的 4 个坑
- 开了 9 位又开校验位 → 格式错误,直接不工作
- 用 uint8_t 存 9 位数据 → 高位丢失
- 中断 / NVIC 未开启 → 收到数据不触发
- GPIO 复用配置错 → 波形都没有
7. LAT1361 最终小结
- STM32 USART 完全支持 9 位数据格式
- 9 位必须搭配无校验
- 数据用 uint16_t 存储
- 中断 / DMA 都支持,HAL 库无 bug
- 不工作优先查:配置、GPIO、引脚连接
只要按官方这套方法配置,9 位串口通讯可以稳定使用。
214