【STM32】串口通信乱码(认识系统时钟来源)
使用 stm32f407 与电脑主机进行串口通信时,串口助手打印乱码,主要从以下方面进行排查:
- 检查传输协议设置是否一致(波特率、数据位、停止位、校验位)
- 检查MCU外部晶振频率是否和库函数设置的一致
最终发现是外部晶振频率和库函数不一致的问题。
一、时钟分析
1、认识时钟源
我们要检查的是 APB2总线的时钟源是否设置正常,因为我们当前使用的串口 USART1 与 APB2 总线(高速总线)相连,从下图看,时钟源有三个:
- HSI:高速内部时钟,RC振荡器,频率为16MHz
- HSE:高速外部时钟,接外部时钟源,频率范围为4MHz~26MHz
- PLL:锁相环倍频输出,其时钟输入源可选择为 HSI/M、HSE/M(本质还是 由HSE或HSI控制)
就结果而言,选择的时钟源是 PLLCLK。(若想了解,可以参考最后一部分)
2、计算系统时钟
现在已经知道了选择的是 PLLCLK 作为时钟源,那么我们就可以顺着这条路线计算系统时钟的值。正点原子 stm32f407 的外设时钟频率 HSE = 8 M
① 输入 HSE
② 经过 M 分频,得到的结果为 HSE / M = 8 / M
③ ④ ⑤ ⑥ 经过 N 倍频,VCO的输出为 (HSE / M ) * N
⑦ 再次 P 分频就得到 SYSCLK = (HSE / M ) * N / P
二、解决外部晶振频率和库函数不一致的问题
从上面可知,选择的系统时钟频率 SYSCLK = (HSE / M ) * N / P,配置文件预期的 SYSCLK = 144MHz,其余参数也都指定了
实际上 HSE 需要视开发板具体情况而定,stm32f4 的 HSE 为 8 MHz,然而配置文件中配置的频率是 25 M,为了不影响原本的SYSCLK,我们需要修改 HSE 和 PLL_M。
- HSE = 8 M = 8000000
- PLL_M = (HSE / SYSCLK ) * N / P = 8
1、修改 HSE
HSE 在程序中的体现为宏定义 HSE_VALUE ,该宏定义在 stm32f4xx.h 文件中
这里有两种修改方法,可任选一种修改
2、修改 PLL_M
分频数 M 在程序中的体现是宏定义 PLL_M,该宏定义在 system_stm32f4xx.c 文件中
三、为什么可以确定时钟源为 PLLCLK 而不是 HSE
stm32 在启动的时候就会调用 SystemInit 函数,这个函数就包含了初始化外设的时钟源。这个函数定义在 system_stm32f4xx.c 中。我们直接找到 SetSysClock 函数,这之前的都是将控制寄存器位清零的操作。
我们进入到 SetSysClock 函数,首先是HSE使能,等待时钟准备就绪。刚上电的时候 HSE 晶振不稳定,需要等待 6 个晶振时钟周期。
PLL 使能,等待时钟准备就绪。一开始 PLL 处于被锁定状态,这里需要等待 PLL 解锁。
一切准备就绪,然后将 PLL 设为系统时钟。
参考文章: