STM32F103C8T6标准库实战:从外部晶振到纯内部HSI时钟的配置迁移与性能调优

张开发
2026/4/18 5:11:59 15 分钟阅读

分享文章

STM32F103C8T6标准库实战:从外部晶振到纯内部HSI时钟的配置迁移与性能调优
1. 为什么需要从外部晶振切换到内部HSI时钟最近在做一个基于STM32F103C8T6的项目原本使用的是外部8MHz晶振作为时钟源。后来客户提出要降低成本和提高可靠性要求改用内部HSI时钟。这个改动看似简单但实际操作中需要考虑很多细节问题。使用内部时钟最直接的好处就是可以省去外部晶振和相关电路。一个8MHz晶振虽然不贵但批量生产时也能节省不少成本。更重要的是外部晶振在振动、高温等恶劣环境下容易出现稳定性问题。我曾经遇到过因为晶振失效导致整个系统崩溃的情况改用内部时钟后这类问题就彻底解决了。不过内部时钟也有它的局限性。HSI高速内部时钟的精度比外部晶振要低默认精度在±1%左右。对于需要高精度时钟的应用比如USB通信就不太适合。但在大多数控制类应用中这个精度已经足够用了。另外HSI的最高频率只能到64MHz比使用外部晶振时的72MHz要低一些。2. 硬件改造方案2.1 移除外部晶振电路首先需要把板子上的8MHz晶振和两个负载电容去掉。这里要注意的是有些设计可能还会用到32.768kHz的RTC晶振如果项目用不到RTC功能这个也可以一并移除。我遇到过一些工程师担心直接去掉晶振会不会影响芯片工作。其实STM32在设计时就考虑到了这种情况内部HSI时钟是默认启用的即使没有外部晶振芯片也能正常工作只是时钟精度会有所下降。2.2 检查复位电路移除晶振后建议检查一下复位电路。因为时钟源的改变可能会影响上电时序。标准的10k电阻加0.1uF电容的复位电路在大多数情况下都能正常工作但如果发现系统启动不稳定可以适当调整复位时间常数。3. 软件配置关键步骤3.1 修改SystemInit函数系统时钟的配置主要在system_stm32f10x.c文件中的SystemInit函数里完成。我们需要重写这个函数把原来基于外部晶振的配置改为使用内部HSI。void SystemInit(void) { // 设置Flash延时 FLASH-ACR | FLASH_ACR_PRFTBE; FLASH-ACR ~FLASH_ACR_LATENCY; FLASH-ACR | FLASH_ACR_LATENCY_2; while((FLASH-ACR FLASH_ACR_LATENCY) ! FLASH_ACR_LATENCY_2); // 设置HSI校正值 RCC_AdjustHSICalibrationValue(16); // 开启HSI RCC-CR | RCC_CR_HSION; // 选择HSI作为PLL时钟源并2分频 RCC-CFGR | RCC_CFGR_PLLSRC_HSI_Div2; // 设置PLL倍频为16倍 RCC-CFGR | RCC_CFGR_PLLMULL16; // 使能PLL RCC-CR | RCC_CR_PLLON; while((RCC-CR RCC_CR_PLLRDY) 0); // 选择PLL作为系统时钟源 RCC-CFGR ~RCC_CFGR_SW; RCC-CFGR | RCC_CFGR_SW_PLL; while((RCC-CFGR RCC_CFGR_SWS) ! RCC_CFGR_SWS_PLL); // 设置AHB、APB1、APB2时钟分频 RCC-CFGR | RCC_CFGR_HPRE_DIV1; // AHB SYSCLK 64MHz RCC-CFGR | RCC_CFGR_PPRE2_DIV1; // APB2 64MHz RCC-CFGR | RCC_CFGR_PPRE1_DIV2; // APB1 32MHz }3.2 时钟树分析理解时钟树对正确配置系统时钟非常重要。使用HSI时时钟路径是这样的内部HSI提供8MHz时钟这个时钟经过2分频变成4MHz然后通过PLL倍频16倍得到64MHz最后作为系统时钟SYSCLK输出如果不经过2分频直接使用HSI系统时钟就只有8MHz。经过这样的配置后各总线时钟如下AHB总线64MHzAPB2总线64MHzAPB1总线32MHz因为APB1最大只能到36MHz4. 性能优化与问题排查4.1 延时函数调整时钟频率改变后原来的延时函数需要重新校准。比如原来的1us延时函数是基于72MHz时钟的现在要改为64MHzvoid Delay_us(uint32_t xus) { SysTick-LOAD 64 * xus; // 64MHz时钟下1us需要计数64次 SysTick-VAL 0x00; SysTick-CTRL 0x00000005; while(!(SysTick-CTRL 0x00010000)); SysTick-CTRL 0x00000004; }4.2 外设时钟检查所有使用时钟的外设都需要检查是否在允许的频率范围内。特别是USART波特率可能需要重新计算SPI时钟频率可能需要调整PWM频率会发生变化我曾经遇到过因为没调整USART波特率导致通信失败的问题。后来发现虽然误差在可接受范围内但长时间通信还是会出现错位。4.3 功耗测试使用内部时钟后整体功耗会比使用外部晶振时略高因为HSI的功耗比外部晶振要大一些。在电池供电的应用中这点需要特别注意。可以通过以下方式优化合理使用睡眠模式动态调整时钟频率关闭不使用的外设时钟5. 稳定性测试与生产建议5.1 温度测试内部RC振荡器的频率会随温度变化而漂移建议在产品的整个工作温度范围内测试时钟稳定性。我的经验是在-20°C到70°C范围内频率变化大约在±1%以内对于大多数应用来说已经足够。如果对时钟精度要求特别高可以考虑使用HSI时钟校准功能在软件中加入时钟补偿算法在关键部分使用硬件定时器补偿5.2 批量生产一致性在大批量生产时不同芯片之间的HSI时钟可能会有微小差异。建议在生产测试环节加入时钟校准保留一定的软件调整余量对时序要求严格的部分使用相对时间而非绝对时间我曾经负责过一个量产项目就因为没考虑不同芯片间HSI的差异导致部分产品出现时序问题。后来在产测中加入时钟校准步骤后问题就解决了。5.3 软件兼容性如果项目中有使用到实时操作系统(RTOS)需要检查任务调度器是否受时钟变化影响。大多数RTOS都会使用SysTick定时器时钟频率改变后需要重新配置时间片长度。在FreeRTOS中需要修改configTICK_RATE_HZ对应的时钟配置。我曾经就遇到过因为没改这个配置导致任务调度出问题的案例。

更多文章