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)可以避免一条总线带来的问题。。

好了,先到这吧。。。

相关推荐
HQB202610 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science12 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn12 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
沉淀的.晴天13 小时前
can总线
stm32
桀人13 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯14 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C14 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路14 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc15 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院15 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法