常见代码问题与解答:(二)因外部晶振频率改变导致 MCU 锁死的原因及处理方法
上一篇下一篇函数内可以释放内存却无法将外部指针置 NULL目 录因外部晶振频率改变导致 MCU 锁死的原因及处理方法1故障现象典型场景2根本原因时钟系统崩溃导致内核停摆3解决方法强制进入“安全启动模式”4根本修复修正代码中的时钟配置5预防措施因外部晶振频率改变导致 MCU 锁死的原因及处理方法1故障现象典型场景将程序烧录至 MCU 后芯片“死机”再无任何反应。调试器无论何种型号无法连接目标芯片IDE 报错提示找不到设备或读不到 ID。部分工具软件如 keil在尝试连接时可能会抛出误导性错误如No target connected或Not a genuine ST Device!。重新上电、多次尝试复位均无效芯片仿佛“永久变砖”。2根本原因时钟系统崩溃导致内核停摆现代 MCU 的时钟系统工作原理如下外部晶振HSE PLL锁相环是生成高速系统时钟的核心环节。软件代码在初始化时必须告诉 MCU外部晶振的实际频率MCU 才能正确配置 PLL 参数分频/倍频将频率锁定在目标值。如果代码中的 HSE 数值与实际焊接的晶振频率严重不符则会因时钟系统崩溃导致内核停摆。例如 STM32F407VET6 开发板系统时钟最高支持 168MHz一般厂家用的 HSE 外部高速晶振都是 8MHz代码往往设置的是sys_stm32_clock_init(336, 8, 2, 7);PLL 倍频系数 N336进入 PLL 前的分频系数 M8出 PLL 后的分频系数 P2出 PLL 后的分频系数 Q7时钟树的配置一般如下如果用的另一个厂家的板子HSE 晶振频率为 25MHz那么按照源代码计算系统时钟 25÷8×336÷2 525MHz远超 168MHz。导致的直接后果MCU 时钟混乱内核停摆一上电就锁死完全不给调试器介入的机会。此时即使按复位键也没用因为大多数调试器在连接时MCU 都会先完整地跑一遍启动代码包括错误的时钟配置然后才在某个时机由调试器接管。但往往在启动阶段芯片就已经锁死了。3解决方法强制进入“安全启动模式”绕过用户 Flash 里的错误代码让 MCU 从芯片厂固化在 ROM 里的启动代码bootloader启动。此时系统时钟使用内部默认的低速时钟HSI/HSI48 等完全不依赖外部晶振和错的那段代码。BOOT0 是从硬件层面在芯片取第一条指令之前就改变了程序入口是唯一彻底的绕行方案。具体操作步骤将 3.3V 引脚和 BOOT0 引脚短接然后按 Reset 按键复位然后重新用 Keil 烧录正确的代码或者用 Jflash 之类的工具先全片擦除后烧录正确的代码。4根本修复修正代码中的时钟配置以stm32f407系列单片机为例在成功擦除并恢复连接后必须修正代码才能再次下载核对板载晶振看晶振上的丝印确认频率常见为 8MHz, 12MHz, 25MHz。修改 HSE_VALUE 宏标准库stm32f4xx.h中#defineHSE_VALUE((uint32_t)25000000U)/* 改为实际值这里实际值为25MHz */HAL 库stm32f4xx_hal_conf.h中同理修改。重新计算 PLL 参数HAL 库示例/* 以下为 25MHz 晶振产生 168MHz 主频的配置之一 */#defineHSE_VALUE((uint32_t)25000000U)/* 修改在main.c文件里调用时钟初始化函数 *//* PLL_M 25, PLL_N 336, PLL_P 2 *//* SYSCLK HSE / PLL_M * PLL_N / PLL_P 25/25 * 336 / 2 168MHz */sys_stm32_clock_init(336,25,2,7);// sys_stm32_clock_init(plln, pllm, pllp, pllq)如果使用 CubeMX直接在 Pinout Configuration → RCC → HSE 中填入 25MHz然后去 Clock Configuration 标签页让工具自动求解生成代码。5预防措施拿到一块新板子或别人给的例程第一件事就是看晶振配置一定要和MCU和实际晶振相符合