STM32(4)--时钟树

1 STM32时钟系统

STM32有多种时钟源,主要是以下这几种。

时钟源 全称 特点 典型频率
HSE 高速外部时钟 精度高,接外部石英晶体。最常用 4MHz - 26MHz
HSI 高速内部时钟 成本低、启动快,但精度受温度影响。 16MHz (RC振荡器)
PLL 锁相环 核心角色,负责把低频倍增为高频。 168MHz+
LSE 低速外部时钟 专门给实时时钟(RTC)用。 32.768kHz
LSI 低速内部时钟 给独立看门狗(IWDG)用,低功耗。 32KHz到40kHz

其中HSE,LSE是外部的。如果没有,就会自动用内部的HSI和LSI。

HSI和HSE对比:

特性 HSI (High-Speed Internal) HSE (High-Speed External)
来源 芯片内置的 RC 振荡器 外部石英晶体或有源晶振
精度 较低(误差约 ±1% 至 ±5%) 极高(通常以 ppm 百万分比计)
稳定性 差(受温度、电压影响极大) 非常稳定
成本 零成本(无需外围电路) 需要购买晶振、电容并占用引脚
启动时间 极快(微秒级,瞬间唤醒) 较慢(毫秒级,需等待起振稳定)
功耗 相对略低 略高

也就是说一般是实验用HSI还是可以,但是如果要用到高精度的时钟,比如USB,CAN,高波特率UART,ETH等,就必须用HSE才行。实际上一个晶振也不贵,小几块钱,一般的板子都会配。

对于STM32,时钟的基本流程就是:时钟源 -> 锁相环(PLL)倍频 -> 系统时钟(SYSCLK) -> 总线分频 -> 外设。

以F103为例看看具体的时钟路径:

初始阶段:启动外部HSE 8MHz晶振。

加压阶段: 外部 8MHz 的 HSE 信号进入 PLL。通过倍频(如 9 倍),产生72MHz的超高频信号。

核心枢纽: 这个 72MHz 信号被选作 SYSCLK(系统时钟)。它是单片机的心脏跳动频率。

分流阶段: SYSCLK 经过 AHB 预分频器分发给不同的总线:

HCLK: 供给 CPU 核心、内存、DMA,通常也是 72MHz。

PCLK1 (APB1): 低速总线,最高 36MHz。连接串口 2-5、定时器等。

PCLK2 (APB2): 高速总线,最高 72MHz。连接 GPIO、串口 1、ADC 等。

这个是之前我发过的配置的图:

这里不能选HSE,应就是没开。下面会写一下怎么开。

2 HSI/HSE

HSI是内部晶振,HSE是外部晶振。

开启 HSE 硬件接口:

1 切换到 Pinout & Configuration(引脚和配置)选项卡。

2 在左侧列表中找到 System Core -> RCC。

3 在右侧的 Mode 面板中,找到 High Speed Clock (HSE)。

4 根据你的硬件连接选择对应模式:

Crystal/Ceramic Resonator(无源晶振): 如果你的电路板上焊接的是普通的金属壳两脚或四脚晶振。

BYPASS Clock Source(有源晶振): 如果你使用的是外部提供的有源时钟信号(例如从 ST-Link 提供的 MCO 时钟)。

之后就可以看到完整的时钟配置,可以选择HSE了。

在HCLK直接填入希望的频率168,其它的会帮你自动算好。

LSE/LSI目前没用到,查了一下,只有在超低功耗,独立看门狗,时间戳等场景采用。所以这里先暂时不写了。

至于PLL,这个基本上是纯硬件的,可以参考之前的文章。https://blog.csdn.net/fanged/article/details/156566722

在待机时,PLL将被禁止。然后STM32还有一个PLL2S,是给I2S提供时钟的,这个后面再看吧。

3 分频

这个倒是STM32的特色之一吧。就是 AHB、APB1、APB2这几个。

HCLK: 供给 CPU 核心、内存、DMA,通常也是 168MHz。

PCLK1 (APB1): 低速总线,最高 84MHz。连接串口 2-5、定时器等。

PCLK2 (APB2): 高速总线,最高 168MHz。连接 GPIO、串口 1、ADC 等。

外设名称 所属总线 配置频率 说明
UART1 APB2 84 MHz UART1 是高速串口,通常挂在更快的 APB2 上。
UART2 ~ UART6 APB1 42 MHz 其余串口(如 UART2, 3, 4, 5)为了节能通常挂在 APB1。
I2C1, I2C2, I2C3 APB1 42 MHz 所有的 I2C 接口在 F4 系列中都属于低速总线 APB1。
ADC1, 2, 3 APB2 84 MHz ADC 需要高速时钟进行高频采样,固定在 APB2。

但是I2C实际的速率是400KHz。

所以这里还会再芯片里面再分,把42M切成400K。这部分是硬件完成的。

4 代码

在界面上配置了时钟,其实就是CubeMX帮你完成了代码,最后还是得回到代码的流程,在mian.h中。其实核心的也就10来行,和上面的配置图完全对应。真不多。重在理解。

cpp 复制代码
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }

这里再对比一下树莓派Pico的时钟初始化。

cpp 复制代码
#include "hardware/pll.h"
#include "hardware/clocks.h"
#include "hardware/xosc.h"

void init_clock_manual() {
    // 1. 初始化外部晶振 (XOSC) - Pico 板载通常是 12MHz
    xosc_init();

    // 2. 配置 PLL_SYS (系统倍频器)
    // 公式: Fout = (Fref / REFDIV) * FBDIV / (POSTDIV1 * POSTDIV2)
    // 这里将 12MHz 经过 PLL 变成 125MHz
    pll_init(pll_sys, 1, 1500 * MHZ, 6, 2);

    // 3. 切换系统时钟源到 PLL_SYS
    clock_configure(clk_sys,
                    CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
                    CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
                    125 * MHZ,
                    125 * MHZ);

    // 4. 配置外设时钟 (clk_peri)
    // 外设时钟通常直接挂在 clk_sys 上,用于串口、SPI、I2C 等
    clock_configure(clk_peri,
                    0,
                    CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
                    125 * MHZ,
                    125 * MHZ);
}

可以看出,树莓派Pico的总线只有1个,就是clk_sys。而STM32使用了APB1,甚至APB2。查了一下资料据说是可以更好控制能耗。而Pico用了多层AHB总线矩阵(Multi-layer AHB Crossbar)可以避免一条总线带来的问题。。

好了,先到这吧。。。

相关推荐
List<String> error_P2 小时前
STM32启动流程及相关概念
单片机·嵌入式硬件
__万波__2 小时前
STM32L475蜂鸣器实验
stm32·单片机·嵌入式硬件
qq_401700412 小时前
经典78M05 LDO经典应用电路
单片机·嵌入式硬件
欢乐熊嵌入式编程3 小时前
BLE 蓝牙开发入门:用手机控制开发板 LED
单片机·ble蓝牙开发·嵌入式入门
小美单片机4 小时前
External model DLL ”ADC083XDLL“ not found_proteus仿真报错解决方法
c语言·单片机·51单片机·proteus·课程设计·课设
Tyrion.Mon4 小时前
沁恒PD协议诱骗芯片CH224A/CH224Q--IIC研究(0x60~0x8F)
单片机·硬件工程
田甲4 小时前
基于STM32L051和HDC2080的低功耗温湿度计
单片机·嵌入式硬件·温湿度计·hdc2080
List<String> error_P5 小时前
STM32 GPIO HAL库常用函数
stm32·单片机·hal库