【bug 解决】串口输出字符乱码的问题
今天的blog 是关于串口输出字符乱码的问题【非编码问题导致 而是由于时钟配置】
文章目录
- 探索
- UART的波特率
- 理想情况
- 实际问题:
- 高波特率下误差的放大效应
- 误差的相对影响:
- 总结原因:
- 检查并优化时钟源精度:
- 计算实际波特率误差:
- 实测与改进
在用keil编程,用stm32H7的板子进行串口通信输出 发现一个问题,就是串口输出的字符大部分都是乱码的 (如下图)

然后也在网上查了很多资料,说是编码的问题
但是后面发现 其实不是编码的问题 而是波特率的问题,(之前的波特率什么的是和单片机的配置能对的上的)我这个波特率设置的是115200,然后换成了9600之后就可以通信了。如果有小伙伴尝试过了各种编码配置还是不行的话 不妨试试把波特率改一改。
至于,原因,我去用ai探索了一下
探索
UART的波特率
在嵌入式系统中,UART的波特率是根据外设时钟频率和内部波特率分频寄存器的值计算出来的。
理想情况
如果我们希望波特率为 BaudRate,并且UART外设的时钟频率是 F_UART_CLK,那么计算公式通常是 BaudRate = F_UART_CLK / (16 * UartDiv) (对于STM32的OverSampling=16模式) 或者其他类似公式。
实际问题:
UartDiv 寄存器通常只能存储整数值。这意味着,即使理论计算出来需要一个小数(例如 10.5)才能达到精确的波特率,硬件也只能选择最接近的整数(例如 10 或 11)。这种取整会引入一个小的误差。
时钟源的精度: 您MCU内部的时钟源(例如内部高速振荡器 HSI)本身可能就不够精确。虽然外部晶振(HSE)精度高,但如果您的系统使用了相对不那么精确的内部RC振荡器作为主时钟,然后这个时钟又通过分频提供给UART,那么最终UART的实际时钟频率就可能与您期望的频率存在微小偏差。 例如,一个标称8MHz的HSI,实际可能是7.9MHz或8.1MHz。
高波特率下误差的放大效应
这就是为什么 115200 会乱码而 9600 不会的核心原因:
比特持续时间:
在 9600 bps 下,每个比特的持续时间是 1/9600 ≈ 104.17 微秒。
在 115200 bps 下,每个比特的持续时间是 1/115200 ≈ 8.68 微秒。
误差的相对影响:
假设您的UART实际波特率与期望值有 X 微秒的绝对误差(例如,由于时钟不准或取整导致每个比特的持续时间比理论值长或短了 X 微秒)。
对于 9600 bps:X 微秒的误差相对于 104.17 微秒 是一个较小的百分比。接收方在采样时,即使采样点略微偏离了理想中心,也可能仍然落在该比特的有效范围内,从而正确读取。
对于 115200 bps:X 微秒的相同误差相对于 8.68 微秒 是一个大得多的百分比。这个误差可能导致接收方在错误的时间点采样,例如在比特转换的边缘采样,或者完全跳过一个比特,从而导致读取错误,表现为乱码。
简单来说,高速率下,每个比特的时间间隔非常短,容错空间变得极小。一点微小的时钟频率偏差或波特率计算的取整误差,在高倍率累积下,就会导致发送方和接收方在多个比特传输后失去同步,进而产生您看到的乱码。
总结原因:
您观察到的现象几乎总是意味着您的STM32上的USART1所依赖的实际时钟频率存在误差,导致其产生的实际波特率与PC端设定的 115200 不完全匹配。而 9600 波特率由于其每个比特的持续时间更长,对这种微小偏差的容忍度更高,所以能够正常通信。
可能的解决方向 (如果未来仍需使用 115200):
检查并优化时钟源精度:
如果您现在使用的是内部高速振荡器(HSI),强烈建议您切换到外部晶振(HSE)作为主时钟源。外部晶振通常具有更高的精度和稳定性,可以大大减少时钟频率的偏差。
在STM32CubeMX中,检查Clock Configuration,确保USART1的时钟源是经过PLL精确分频后的高速时钟,并且主时钟源(HSE)是稳定且准确的。
计算实际波特率误差:
如果您没有外部晶振,或者怀疑计算问题,可以在CubeMX中配置完时钟后,查看UART配置页面,它会显示基于当前时钟配置下,目标波特率(如115200)的实际波特率和计算误差百分比。如果这个误差百分比超过 2% ~ 3%,那么在高波特率下就很容易出问题。
实测与改进
最终可以看到对比的前后,发现正常了
还真被他说对了,我用cubemx配置时钟的时候,确实用的是HSI,所以为了验证一下,我打算尝试配置一下HSE ,甚至把sysclk配置成了最高频率550MHz,用115200的波特率还是不行,还是会有乱码
于是又去找原因,发现这一块也要配置,我用的是USART1,我之前配置的是CSI给USART1,给的频率太低了
于是把USART1的时钟输入选择PCLK2
最终成功了!!
在AI的帮助下,总结~~
CSI的特性: CSI 是STM32内部的低速RC振荡器,通常频率较低(例如,在H7系列中为4MHz),并且精度不如外部晶振(HSE)。
与550MHz SYSCLK的脱节: 尽管配置了 HSE 作为主时钟并达到了 550MHz 的 SYSCLK,但 USART1 并没有使用这个高速精确的时钟,而是独立地从 CSI 获得时钟。
波特率计算误差: 如果 USART1 使用一个4MHz的 CSI 时钟来生成 115200 波特率,那么计算出来的分频系数几乎不可能是整数,导致巨大的波特率误差。而对于 9600 波特率,由于其低速特性,即使基准时钟不那么精确,也可能因为分频系数的近似能够提供一个相对可接受的误差,从而正常工作。
🌈 okok 完结撒花!!~~