“ STM32单片机的时钟系统,涵盖时钟来源、关键节点及产生原理,并通过实例代码展示如何配置时钟。”

01
—
时钟简介
时钟在单片机中非常重要,它是所有外设和内核运行的心脏。主要作用为驱动内核与外设、提供时间基准与同步、通信协议时序产生、实现低功耗等。
02
—
时钟来源
1.HSI:16 MHz 内部 RC 振荡器,精度一般,适合快速启动或备用时钟。
2.HSE:4–26 MHz 外部晶振/时钟输入,精度高,常用作 PLL 输入或直接系统时钟。
3.LSI:约 32 kHz 内部 RC,供独立看门狗(IWDG)和自动唤醒单元(AWU)。
4.LSE:32.768 kHz 外部晶振,专为 RTC 提供高精度、低功耗时钟。
5.PLL:主 PLL 和专用 PLLI2S/PLLSAI。
03
—
时钟树关键节点
1.SYSCLK:系统主时钟,可来自 HSI、HSE 或 PLLP,典型配置 168 MHz。
2.HCLK:AHB 总线时钟,默认 = SYSCLK,可 1/2/4/8/16/128/256/512 分频。
3.PCLK1:APB1 总线时钟,默认 = HCLK/4(最高 42 MHz),定时器可 1/2 倍频。PCLK2:APB2 总线时钟,默认 = HCLK/2(最高 84 MHz),定时器可 1/2 倍频。
4.MCO1/MCO2:可输出 HSI/HSE/LSE/PLL 等时钟到引脚,用于外部同步或测量。
SYSCLK产生原理:
SYSCLK有三个来源,分别为HSI(16 MHz 内部 RC,精度一般,上电默认)、HSE(4–26 MHz 外部晶振,精度高,推荐主用)、PLLCLK(主 PLL 输出,典型 168 MHz,高性能首选),通过RCC_CR寄存器进行选择,下面以PLLCLK产生SYSCLK(HSE → PLL → SYSCLK)为例:
1.选择时钟源
通过RCC_CR寄存器选择HSE外部高速时钟作为时钟源。
2.主 PLL 倍频链路
输入时钟先除以分频系数 M(2–63),降低 PLL 输入频率,确保压控振荡器(VCO)稳定工作。
分频后的时钟乘以倍频系数 N(192–432),得到 VCO 输出频率:_f_VCO=(_f_输入/M)*N。
生成 PLLP 输出(典型 168 MHz),直接作为 SYSCLK 或 HCLK。
/Q 分频:生成 PLLQ 输出(固定 48 MHz),用于 USB OTG FS、SDIO、RNG 等外设。
示例:外部 8 MHz HSE → 设置 M=8, N=336, P=2
f_PLLP=8MHz/8×336÷2=168MHz,即得到_SYSCLK。
3. 时钟切换与输出
•通过 RCC_CFGR 寄存器的SW 位选择 SYSCLK 来源(HSE)。
04
—
HCLK、PCLK1、PCLK2产生原理
1.时钟源选择
选择 PLLCLK(168 MHz)作为 SYSCLK,以获得最高性能。
2.AHB 预分频器
SYSCLK 经过 AHB 预分频器(HPRE) 后生成 HCLK。预分频系数可配置为:
HCLK=SYSCLK/HPRE,其中 HPRE 可选 1、2、4、8、16、64、128、256、512 分频。
3.计算实例
假设配置:
SYSCLK = 168 MHz(PLLCLK)
AHB 预分频系数 HPRE = 1(不分频)
APB1 预分频系数 PPRE1 = 4
APB2 预分频系数 PPRE2 = 2
HCLK=168MHz/1=168MHz
PCLK1=HCLK/4=168/4=42MHz(注:APB1 外设定时器时钟 = 2 × PCLK1 = 84 MHz(因 APB1 分频系数 >1))
PCLK2=HCLK/2=168/2=84MHz(注:APB2外设定时器时钟 = 2 × PCLK1 = 84 MHz(因 APB1 分频系数 >1))

05
—
STM32F4xx 系列提供两路可编程时钟输出(MCO1 和 MCO2),用于将内部时钟信号输出到外部引脚(PA8 和 PC9),供外部设备同步或测试使用。在工程师调试过程中可以使用此功能测试时钟系统是否正常工作。
1.时钟源选择
MCO1:可选时钟源包括 HSI(16 MHz)、HSE(外部晶振)、LSE(32.768 kHz)、PLLCLK 。
MCO2:可选时钟源包括 SYSCLK(系统主时钟)、HSE、PLLCLK、PLLI2SCLK 。
2.分频器配置
每路 MCO 输出均支持 1~16 级分频(通过 MCO1DIV 或 MCO2DIV 配置),公式为:
f MCO = f 时钟源 /MCODIV
例如,若 PLLCLK=168 MHz,分频系数=2,则 MCO 输出频率为 84 MHz。
3.输出使能
通过 RCC_CFGR 寄存器的 MCO1ON/MCO2ON 位使能输出,并配置 GPIO 引脚为复用功能模式。
4.计算实例
以 MCO1 为例,假设系统配置如下:
PLLCLK = 168 MHz、MCO1 分频系数 = 4、时钟源选择 = PLLCLK
_f_MCO1=168MHz/4=42MHz
以 MCO2 为例,假设系统配置如下:
SYSCLK = 168 MHz、MCO2 分频系数 = 2、时钟源选择 = SYSCLK
_f_MCO2=168MHz/2=84MHz
06
—
除了常用的SYSCLK、HCLK、PCLK1、PCLK2时钟,以及MCO1/MCO2输出功能,stm32f4xx系列单片机还有看门狗时钟、RTC时钟、PLL48CLK时钟等,下面进行简单介绍。
1.看门狗时钟
stm32f4xx单片机有独立看门狗和窗口看门狗,由于窗口看门狗时钟由PCLK1产生,上面已经介绍。独立看门狗(IWDG)使用 内部低速时钟 LSI 作为时钟源,其频率典型值为 32 kHz(实际范围 30–60 kHz)。
IWDG时钟=LSI频率/预分频系数;
预分频系数由寄存器IWDG_PR的 PR[2:0] 位配置,可选 8 种分频比(/4、/8、/16、/32、/64、/128、/256、/256)。
2.RTC时钟
RTC 时钟可以从LSE、LSI、HSE_RTC三个时钟源中选择一个作为输入时钟(RTCCLK),实际使用时为了方便分频获得1Hz时钟,一般使用LSE(32.768 kHz) 作为 RTCCLK,因其频率与 2¹⁵(32768)匹配。
配置方法为:
选择异步分频系数,PREDIV_A=127(分频值=128);
计算同步分频系数,PREDIV_S=32768/(128*1)−1=255;
配置结果,_f_ck_spre=32768/((127+1)×(255+1))=128×25632768=1Hz。
3.PLL48CLK 时钟
PLL48CLK 是专为 USB OTG FS、SDIO、RNG(硬件随机数发生器) 等外设提供的 48 MHz 高精度时钟(典型 8 MHz 或 25 MHz),时钟源经过PLL产生PLL48CLK 。配置防范为:
时钟源选择:可选HSE和HSI,由于精度更高,尝试用HSE作为时钟源;
PLL 分频/倍频链路:f PLL48CLK = f HSE *N /( M*Q),其中M(2~63)、N(192~432)、Q(2~15);
计算实例:f PLL48CLK = 8×7 8MHz×336 = 56 2688 =48MHz,其中HSE = 8 MHz、M = 8、N = 336、Q = 7。
07
—
选择外部HSE(25MHz),配置fSYSCLK为168MHz,fAHB=168MHz ,fAPB1=42MHz ,fAPB2=84MHz,MCO1输出42MHz,MCO2输出84MHz。

main.c
int main(void){ //选择HSE(25MHz),m=25,n=336,p=2,q=7,系统时钟设置为168M, HCLK=168M, PCLK1=HCLK/4=42MHz, PCLK2=HCLK/2=84MHz HSE_SetSysClock(25, 336, 2, 7); // LED 端口初始化 LED_GPIO_Config(); // MCO1 输出PLLCLK, PLLCLK = 168 MHz、MCO1 分频系数 = 4、时钟源选择 = PLLCLK, fMCO1=168MHz/4=42MHz HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_4); // MCO2 输出SYSCLK,SYSCLK = 168 MHz、MCO2 分频系数 = 2、时钟源选择 = SYSCLK, fMCO2=168MHz/2=84MHz HAL_RCC_MCOConfig(RCC_MCO2,RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_2); while (1) { LED2( ON ); // 亮 Delay(0x5FFFFF); LED2( OFF ); // 灭 Delay(0x5FFFFF); }}
clk_config.c
/* * 使用HSE时,设置系统时钟的步骤 * 1、开启HSE ,并等待 HSE 稳定 * 2、设置 AHB、APB2、APB1的预分频因子 * 3、设置PLL的时钟来源 * 设置VCO输入时钟 分频因子 m * 设置VCO输出时钟 倍频因子 n * 设置PLLCLK时钟分频因子 p * 设置OTG FS,SDIO,RNG时钟分频因子 q * 4、开启PLL,并等待PLL稳定 * 5、把PLLCK切换为系统时钟SYSCLK * 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟 *//* * m: VCO输入时钟 分频因子,取值2~63 * n: VCO输出时钟 倍频因子,取值50~432 * p: PLLCLK时钟分频因子 ,取值2,4,6,8 * q: OTG FS,SDIO,RNG时钟分频因子,取值4~15 * 函数调用举例,使用HSE设置时钟 * SYSCLK=HCLK=168MHz,PCLK2=HCLK/2=84MHz,PCLK1=HCLK/4=42MHz * HSE_SetSysClock(25, 336, 2, 7); * HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法 */void HSE_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q) { RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; /* Enable Power Control clock */ __HAL_RCC_PWR_CLK_ENABLE(); /* The voltage scaling allows optimizing the power consumption when the device is clocked below the maximum system frequency, to update the voltage scaling value regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /* Enable HSE Oscillator and activate PLL with HSE as source */ 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 = 7; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { while(1) {}; } /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 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) { while(1) {}; } /* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported */ if (HAL_GetREVID() == 0x1001) { /* Enable the Flash prefetch */ __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); }}
08
—
工程代码链接:
https://gitee.com/ylm1101111/stm32_basic.git
0