TIM定时器

STM32 时钟树详解

STM32F10x 时钟源、分频链路、外设时钟与标准库配置方法

面向嵌入式入门,以 STM32F103(标准外设库) 为主。
搞清楚时钟树,才能正确计算定时器周期、UART 波特率、ADC 采样时间。


一、为什么要懂时钟树

STM32 片内并不是“只有一个时钟”,而是由 RCC(Reset and Clock Control) 把多种时钟源、分频器、倍频器组织成一棵树:

时钟源 → SYSCLK → HCLK → PCLK1 / PCLK2 → 各外设时钟
                ↘ PLL / USB / ADC / RTC / TIM …

对定时器来说,最关键的一点是:

TIM 计数时钟不一定等于 APB 总线时钟。
当 APB 预分频系数 ≠ 1 时,定时器时钟会自动 ×2

常见 72 MHz 工程里:

时钟频率说明
SYSCLK / HCLK / PCLK272 MHz系统、AHB、APB2
PCLK136 MHzAPB1 上限 36 MHz
TIM2~TIM772 MHzAPB1 分频为 2 → 定时器 ×2
TIM1 / TIM872 MHzAPB2 不分频 → 定时器 = PCLK2

所以教材里写 “TIM 时钟 72 MHz” 是对的,但 不是因为 PCLK1 也是 72 MHz


二、时钟树总览

官方数据手册中的 RCC 时钟树(F103):

STM32F103 RCC 时钟树

用流程图概括主干:


三、时钟源:每个时钟做什么

3.1 HSI — 高速内部时钟

项目内容
全称High Speed Internal
典型频率8 MHz(片内 RC)
作用上电默认系统时钟;也可作 PLL 输入(经 /2)
优点无需外部晶振,启动快
缺点精度较差(温度/电压影响),不适合精确波特率、USB

复位后 MCU 默认跑在 HSI。很多 SystemInit() 会在启动阶段切到 HSE+PLL。

3.2 HSE — 高速外部时钟

项目内容
全称High Speed External
频率范围4 ~ 16 MHz(最小系统板常见 8 MHz
作用高精度主时钟源;经 PLL 倍频得到 72 MHz;USB 必须依赖 HSE
接入方式外部晶体 + 负载电容,或外部时钟直接喂 OSC_IN

开启后要等 HSERDY 置位,再切换系统时钟,否则可能锁死或跑飞。

3.3 PLL — 锁相环倍频

项目内容
全称Phase Locked Loop
输入HSE(可选先 /2),或 HSI/2
倍频×2 ~ ×16(PLLMUL
输出上限SYSCLK ≤ 72 MHz(F103);若用 HSI 作 PLL 输入,手册限制约 64 MHz
作用把 8 MHz 晶振倍到 72 MHz,供内核与多数外设

经典配置:

HSE 8 MHz → PLL ×9 → PLLCLK 72 MHz → SYSCLK

3.4 LSI — 低速内部时钟

项目内容
典型频率约 40 kHz(不可精确)
作用独立看门狗 IWDG 时钟;也可作 RTC 时钟源
特点低功耗、始终可用,但频率飘移大

3.5 LSE — 低速外部时钟

项目内容
典型频率32.768 kHz 晶振
作用RTC 首选时钟;也可输出校准时钟
特点精度高,适合日历/闹钟;位于备份域,可用 VBAT 维持

3.6 其他派生时钟(常被忽略)

时钟来源用途
CSS时钟安全系统HSE 故障时自动切回 HSI,并可产生 NMI
MCO主时钟输出(PA8)把 SYSCLK/HSI/HSE/PLL/2 引出到引脚,方便示波器测量
USBCLKPLLCLK /1 或 /1.5USB 需 48 MHz(72 MHz 时选 /1.5)
ADCCLKPCLK2 /2,/4,/6,/8ADC 工作时钟,手册建议 ≤14 MHz
IWDGCLKLSI独立看门狗
RTCCLKLSE / LSI / HSE÷128实时时钟
FCLK= HCLKCortex-M3 自由运行时钟(调试等)
SysTickHCLK 或 HCLK/8系统滴答定时器

四、总线时钟:SYSCLK → HCLK → PCLK

4.1 SYSCLK(系统时钟)

三选一:

SW 选择来源
00HSI
01HSE
10PLLCLK

F103 最大值:72 MHz

4.2 HCLK(AHB 时钟)

HCLK = SYSCLK / AHB_Prescaler

AHB 预分频可选 /1, 2, 4, …, 512

HCLK 供给:

  • Cortex-M3 内核
  • 存储器、DMA
  • AHB 外设(如部分互联型外设)
  • 再分出 APB1 / APB2

常见工程:AHB 不分频 → HCLK = 72 MHz

4.3 PCLK1 / PCLK2(APB 时钟)

总线预分频上限(F103)挂载外设举例
APB1/1,2,4,8,1636 MHzTIM2~7、USART2/3、I2C、SPI2/3、DAC、PWR、BKP
APB2/1,2,4,8,1672 MHzGPIO、AFIO、USART1、SPI1、ADC、TIM1/8

72 MHz 典型设置:

HCLK = 72 MHz
PCLK2 = HCLK / 1 = 72 MHz
PCLK1 = HCLK / 2 = 36 MHz

五、定时器时钟:最容易算错的地方

5.1 规则

对挂在 APBx 上的定时器:

APBx 预分频定时器时钟 TIMxCLK
= 1(不分频)TIMxCLK = PCLKx
> 1TIMxCLK = PCLKx × 2

5.2 72 MHz 工程对照

定时器所在总线APB 预分频PCLKTIM 时钟
TIM2 / 3 / 4 / 5 / 6 / 7APB1/236 MHz72 MHz
TIM1 / TIM8APB2/172 MHz72 MHz

因此 PSC/ARR 计算时,内部时钟模式统一按 72 MHz 来:

计数频率 = TIM_CLK / (PSC + 1)
溢出周期 = (ARR + 1) / 计数频率

例:PSC = 7200-1ARR = 10000-1 → 周期 1 s。

5.3 若你改了 APB1 分频

例如把 APB1 改成不分频(仅当 HCLK ≤ 36 MHz 才合法):

  • PCLK1 = 36 MHz
  • TIM2 时钟 = 36 MHz(不再 ×2)
  • 原来按 72 MHz 写的 PSC/ARR 全部会翻倍变慢

改时钟树后,务必同步检查所有依赖频率的外设。


六、如何配置时钟(标准库)

6.1 启动默认路径:SystemInit()

上电复位后,启动文件会调用 SystemInit()(在 system_stm32f10x.c)。
库里通常用宏选择目标频率,例如:

#define SYSCLK_FREQ_72MHz  72000000

对应内部会执行类似 SetSysClockTo72() 的流程:开 HSE → 等就绪 → 配 Flash 等待周期 → 配 AHB/APB 分频 → 配 PLL → 切 SYSCLK 到 PLL。

板子是 8 MHz 晶振 时,一般无需手改;若晶振是 12 MHz / 16 MHz,必须改 PLLMULPLLXTPRE,否则 SYSCLK 会超限或偏低。

6.2 标准库常用 RCC API

函数作用
RCC_HSEConfig()开/关/旁路 HSE
RCC_WaitForHSEStartUp()等待 HSE 稳定
RCC_PLLConfig()选 PLL 输入与倍频
RCC_PLLCmd()使能 PLL
RCC_SYSCLKConfig()选择 SYSCLK 源
RCC_HCLKConfig()AHB 预分频
RCC_PCLK1Config() / RCC_PCLK2Config()APB1 / APB2 预分频
RCC_GetClocksFreq()读出当前各总线频率
RCC_ADCCLKConfig()ADC 预分频
RCC_USBCLKConfig()USB 预分频
RCC_LSEConfig() / RCC_LSICmd()低速时钟
RCC_RTCCLKConfig()RTC 时钟源
RCC_MCOConfig()PA8 输出时钟
RCC_xxxPeriphClockCmd()打开外设时钟门控

使用任何外设前,必须先 RCC_APBxPeriphClockCmd(..., ENABLE),否则写寄存器无效。

6.3 手写一套 72 MHz 配置(理解用)

下面逻辑与库内 SetSysClockTo72 等价,便于对照时钟树:

void SystemClock_Config_72MHz(void)
{
    ErrorStatus HSEStartUpStatus;

    /* 复位 RCC 到默认(HSI 作 SYSCLK) */
    RCC_DeInit();

    /* 打开 HSE,等待就绪 */
    RCC_HSEConfig(RCC_HSE_ON);
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    if (HSEStartUpStatus != SUCCESS) {
        /* HSE 失败:可停在这里,或退回 HSI */
        return;
    }

    /* Flash:72 MHz 需要 2 个等待周期,并开预取 */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK;PCLK2 = HCLK;PCLK1 = HCLK/2 */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK2Config(RCC_HCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* PLL = HSE * 9 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
    }

    /* 切换 SYSCLK → PLL,并确认 */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while (RCC_GetSYSCLKSource() != 0x08) {
    }
}

配置顺序建议:

  1. 先稳定时钟源(HSE/HSI)
  2. 再配 Flash latency(频率升高前)
  3. 再配总线分频
  4. 再配并启动 PLL
  5. 最后切换 SW 到 PLL,并轮询 SWS

6.4 外设时钟门控示例

/* GPIO / AFIO / USART1 在 APB2 */
RCC_APB2PeriphClockCmd(
    RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1,
    ENABLE);

/* TIM2 / USART2 在 APB1 */
RCC_APB1PeriphClockCmd(
    RCC_APB1Periph_TIM2 | RCC_APB1Periph_USART2,
    ENABLE);

/* ADC 额外还要配 ADCCLK 分频 */
RCC_ADCCLKConfig(RCC_PCLK2_Div6);   /* 72/6 = 12 MHz */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

七、运行时查看当前时钟

调试时别猜频率,直接读:

RCC_ClocksTypeDef clocks;
RCC_GetClocksFreq(&clocks);

/* clocks.SYSCLK_Frequency
 * clocks.HCLK_Frequency
 * clocks.PCLK1_Frequency
 * clocks.PCLK2_Frequency
 * clocks.ADCCLK_Frequency
 */

也可用 MCO 把时钟引到 PA8,用示波器量:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef gpio;
gpio.GPIO_Pin = GPIO_Pin_8;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);

RCC_MCOConfig(RCC_MCO_PLLCLK_Div2);  /* 输出 PLL/2 = 36 MHz */

八、和定时器、串口相关的计算清单

8.1 定时器

  1. 确认该 TIM 在 APB1 还是 APB2
  2. 看 APB 预分频是否 >1,决定是否 ×2
  3. 得到 TIM_CLK 后再算 PSC / ARR

8.2 USART

波特率分频基于 PCLK(不是 TIM 那种 ×2 规则):

  • USART1 → PCLK2
  • USART2/3 → PCLK1

改 APB 分频后,波特率寄存器要重算。

8.3 SysTick

CMSIS 里常见:

SysTick_Config(SystemCoreClock / 1000);  /* 1 ms */

SystemCoreClock 应等于 HCLK。若你手动改过时钟,记得调用:

SystemCoreClockUpdate();

九、配置检查清单

检查项建议
外部晶振频率PLL 倍频匹配,SYSCLK ≤ 72 MHz
Flash 等待48~72 MHz 用 FLASH_Latency_2
APB1≤ 36 MHz
USBPLL 必须开,USBCLK = 48 MHz
ADCADCCLK ≤ 14 MHz
HSE 失败做好 CSS 或回退 HSI 的处理
改分频后重算 TIM / USART / ADC / SysTick
外设使用前打开对应 RCC_APBxPeriphClockCmd

十、一张表记住“谁给谁供时”

名称典型值(72M 工程)主要消费者
HSI8 MHz默认启动、备份时钟源
HSE8 MHzPLL 输入、高精度外设
PLLCLK72 MHzSYSCLK、USB(再分频)
SYSCLK72 MHz整棵树的根
HCLK72 MHz内核、DMA、存储器、SysTick
PCLK136 MHzAPB1 外设总线
PCLK272 MHzAPB2 外设总线
TIMxCLK(APB1)72 MHzTIM2~7(因 ×2)
TIMxCLK(APB2)72 MHzTIM1/8
ADCCLK12 MHz 等ADC
USBCLK48 MHzUSB
LSE32.768 kHzRTC
LSI~40 kHzIWDG、可选 RTC

理解这张表之后,再去看定时器 PSC/ARR、串口波特率,就不会“频率对不上”了。