01.自己动手配置时钟树

01.自己动手配置时钟树

在上一期,我们已经成功搭建了一个STM32F103的工程模板,基于BSP-SYSTEM-HARDWARE-APP四层架构实现,这一期,我们将要自己动手配置时钟树。

一、为什么要配置时钟树?

为什么需要自己动手配置时钟树?因为时钟是单片机运行的基础,时钟配置不正确的话,单片机运行会产生各种各样的问题,为了避免后期踩坑,前期加强对单片机时钟树的理解是必要的。

时钟是单片机的“心跳”。所有的 CPU 内核、外设、总线、定时器 都依赖时钟运行。
如果时钟配置错误,常见问题包括:

  • 串口波特率不对(通信失败)
  • SysTick 延时不准(RTOS 任务调度混乱)
  • 外设(ADC、PWM、CAN、USB 等)速率异常
  • MCU 超频 / 欠频运行,导致死机或性能不足

因此,正确配置时钟树是稳定运行的基础

二、STM32F103 时钟树结构概览

STM32F103 的时钟系统主要由以下部分组成:

  1. 时钟源
    • HSI:高速内部时钟(8 MHz)
    • HSE:高速外部时钟(常用 8 MHz 或 16 MHz 晶振)
    • PLL:锁相环,可倍频(最大输出 72 MHz)
  2. 总线时钟
    • SYSCLK:系统时钟(由 HSI/HSE/PLL 选择)
    • AHB:高级总线(驱动 CPU、DMA、SRAM)
    • APB1:低速外设总线(USART2/3、I2C、CAN 等)
    • APB2:高速外设总线(GPIO、USART1、ADC 等)
  3. 外设时钟
    • 每个外设的工作频率由对应的 APB1/APB2 分频决定。

三、目标时钟配置

在 STM32F103 中,常见的几种系统时钟配置方案如下:

  1. 使用外部 8MHz 晶振 HSE → PLL → 72MHz SYSCLK
    • 最常用方案,外部晶振精度高,系统稳定。
  2. 使用外部 16MHz 晶振 HSE → PLL → 72MHz SYSCLK
    • 一些开发板(比如野火、正点原子)如采用 16MHz 晶振,同样需要通过 PLL 倍频到 72MHz。
  3. 使用内部 HSI 8MHz → PLL → 64MHz SYSCLK
    • 不依赖外部晶振,成本低,但内部 RC 振荡器精度有限,适合对时钟要求不高的场景。
  4. 使用内部 HSI 8MHz 直通 SYSCLK
    • 系统直接运行在 8MHz,最低功耗,通常用于低速调试。

四、系统时钟配置代码实现

我们在 System 层编写了 sys.c 模块,用于统一管理系统时钟。
代码结构如下:

void systemclock_config(void)
{
   
   
    //USE_SYSTEM_CLOCK这个宏定义可在bsp_config.h文件中定义
    if (USE_SYSTEM_CLOCK == 64000000)
    {
   
   
         systemclock_hsi_64m_hclk1();
    }
    else if (USE_SYSTEM_CLOCK == 8000000)
    {
   
   
         systemclock_hsi_8m();
    }
    else
    {
   
   
        systemclock_hse_72m();
    }
}

通过配置 USE_SYSTEM_CLOCK 宏,我们就可以灵活切换不同的时钟方案,而不用修改底层实现。

关键实现思路

1.HSE 配置并倍频到 72MHz

void systemclock_8m_hse_32k_lsi_72m_hclk1(void)
{
   
   
  // 复位RCC寄存器,恢复默认值
    RCC_DeInit();

    // 开启外部高速晶振 HSE 
    RCC_HSEConfig(RCC_HSE_ON);

    // 等待 HSE 启动稳定
    while (RCC_WaitForHSEStartUp() == ERROR);
     
    // 使能 Flash 预取缓存
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    // 设置 Flash 延时周期:72MHz 时需设置为 2
    FLASH_SetLatency(FLASH_Latency_2);
 
    // AHB = HCLK = SYSCLK / 1 = 72MHz
    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    // APB1 = PCLK1 = HCLK /2 = 36MHz
    RCC_PCLK1Config(RCC_HCLK_Div2);

    
    // APB2 = PCLK2 = HCLK = 72MHz
    RCC_PCLK2Config(RCC_HCLK_Div1);
 
    // PLLCLK = HSE * 9 = 72MHz
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

    // 开启PLL
    RCC_PLLCmd(ENABLE);

    // 等待PLL就绪 */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

    // 选择PLL作为系统时钟源
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    //等待PLL作为系统时钟源
    while(RCC_GetSYSCLKSource() != 0x08);

    //更新系统时钟
    SystemCoreClockUpdate();
      
}

void systemclock_16m_hse_32k_lsi_72m_hclk1(void)
{
   
   
     
    // 复位RCC寄存器,恢复默认值
    RCC_DeInit();

    // 开启外部高速晶振 HSE 
    RCC_HSEConfig(RCC_HSE_ON);

    // 等待 HSE 启动稳定
    while (RCC_WaitForHSEStartUp() == ERROR);
     
    // 使能 Flash 预取缓存
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    // 设置 Flash 延时周期:72MHz 时需设置为 2
    FLASH_SetLatency(FLASH_Latency_2);
 
    // AHB = HCLK = SYSCLK / 1 = 72MHz
    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    // APB1 = PCLK1 = HCLK /2 = 36MHz
    RCC_PCLK1Config(RCC_HCLK_Div2);

    
    // APB2 = PCLK2 = HCLK = 72MHz
    RCC_PCLK2Config(RCC_HCLK_Div1);
 
    // PLLCLK = HSE * 9 = 72MHz
    RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);

    // 开启PLL
    RCC_PLLCmd(ENABLE);

    // 等待PLL就绪 */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

    // 选择PLL作为系统时钟源
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    //等待PLL作为系统时钟源
    while(RCC_GetSYSCLKSource() != 0x08);

    //更新系统时钟
    
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值