一、开篇:定时器是什么?能做什么?

你可以把定时器想象成单片机里的「高精度智能秒表」,它是嵌入式开发里最常用的核心外设之一,能帮我们完成很多重要的工作:

  • 基础定时:比如每隔 1 秒让 LED 闪一下,每隔 100 毫秒采集一次传感器数据。
  • PWM 波形输出:比如做的 LED 呼吸灯(通过改变 PWM 占空比调节亮度)、电机调速、舵机控制。
  • 外部信号测量:比如测量一个方波信号的频率、脉宽。

本文就结合CW32F003 GTIM 通用定时器、48MHz 系统时钟、1kHz PWM 呼吸灯 项目,用大白话 + 类比 + 图表,把定时器的时钟知识和计算方法讲得明明白白。


二、核心概念扫盲(配生活类比)

在开始计算之前,我们先把 4 个最核心的概念搞清楚,这是后面所有计算的基础。

1. 系统时钟(PCLK):芯片的「原始超快心跳」

  • 定义:单片机给定时器提供的原始时钟信号,是定时器的 “动力来源”。
  • CW32F003 默认值48MHz(每秒跳 48,000,000 次,非常快!)。

2. 预分频系数(PSC 硬件值):给心跳「减速的齿轮」

3. 定时器计数频率(TCLK):计数器的「实际工作心跳」

  • 定义:经过预分频器 “减速” 后,计数器 CNT 每秒钟自动加多少次,单位是 Hz(次 / 秒)。
  • 生活类比:就像体育老师的「高精度秒表」,如果计数频率是 1MHz,就是每秒 “滴答” 1,000,000 次,每 1 微秒(μs)走 1 格。
  • CW32F003 常用值:我们一般会把它设成1MHz(1μs 加 1 次),因为这样算 ARR 的时候特别方便,不用算小数。

4. 三个核心寄存器:PSC/CNT/ARR

这三个寄存器是定时器的 “心脏”,对应 GTIM 功能框图上半部分,用一个表格 + 一个简单的信号流向图来说明:

表格

寄存器名称 英文全称 核心作用 生活类比(秒表)
PSC Prescaler 预分频器寄存器,存储「预分频系数 - 1」的值 秒表的 “模式切换键”,切换秒针走的速度
CNT Counter 当前计数值寄存器,自动从 0 开始往上加 秒表的 “当前读数指针”
ARR Auto-Reload Register 自动重装载值寄存器,存储计数的 “终点值”,CNT 数到这里会自动清零 秒表的 “倒计时终点”,到了就自动重置

定时器信号流向图(必看!)

graph LR
    A[系统时钟<br/>PCLK<br/>48MHz] --> B[预分频器<br/>PSC寄存器<br/>减速]
    B --> C[定时器计数频率<br/>TCLK<br/>比如1MHz]
    C --> D[计数器<br/>CNT<br/>自动+1]
    E[重装载寄存器<br/>ARR<br/>存储终点值] --> D
    D -->|数到ARR就清零| D
    D --> F[溢出事件<br/>触发PWM输出/中断]

三、万能公式推导(一步步来,小白也能推)

我们的目标是:已知系统时钟频率和目标 PWM 频率,算出 PSC 寄存器值和 ARR 寄存器值

第一步:推导「预分频系数」和「PSC 寄存器值」

我们的思路是:先把高频的系统时钟,分频成一个好算的整数计数频率(比如 1MHz、10MHz),方便后面算 ARR。

  1. 预分频系数的公式:预分频系数的作用是 “把系统时钟分成 N 份取 1 份”,所以:预分频系数系统时钟频率你想要的定时器计数频率
  2. PSC 寄存器值的公式(关键!为什么要减 1?):这里是新手最容易踩坑的地方,我们结合硬件设计解释:
    • 单片机的 PSC 寄存器是从 0 开始编号的(就像数组的下标从 0 开始,楼层的 0 层)。
    • 当你给 PSC 写 0 时,硬件实际是 1分频(不分频)。
    • 当你给 PSC 写 1 时,硬件实际是 2分频
    • 所以:PSC 寄存器值 = 预分频系数 - 1

第二步:推导「ARR 寄存器值」

现在我们有了好算的定时器计数频率,接下来算 ARR,决定最终的 PWM 频率。

  1. PWM 周期的公式:PWM 周期就是 CNT 从 0 数到 ARR 再回到 0 的总时间,CNT 每加 1 次的时间是 1/定时器计数频率,一共要加 ARR+1 次(因为从 0 到 ARR 是 ARR+1 个数),所以:周期定时器计数频率
  2. PWM 频率的公式:频率是周期的倒数(1 秒有多少个周期),所以:频率定时器计数频率
  3. ARR 寄存器值的公式(变形一下):我们把上面的公式变形,已知目标 PWM 频率,求 ARR:寄存器值定时器计数频率目标频率

四、实战计算演练

已知条件

  • 系统时钟(PCLK):48MHz(CW32F003 默认)
  • 目标 PWM 频率:1kHz(周期 1ms,呼吸灯用)
  • 我们选的「好算的定时器计数频率」:1MHz(1μs 加 1 次)

计算过程(一步步来)

第一部分:算 PSC(预分频器)
  1. 算预分频系数:预分频系数
  2. 算 PSC 寄存器值(别忘了减 1!):寄存器值
  3. 对应你的代码:
    GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV48; // 库函数宏,本质就是写47
    
第二部分:算 ARR(自动重装载值)
  1. 算 ARR 寄存器值:寄存器值
  2. 对应你的代码:
    GTIM_InitStruct.ReloadValue = 999;
    
第三部分:验证一下(确保没错)

我们把算出来的 PSC 和 ARR 代回 PWM 频率公式,验证一下:频率完美!完全符合我们的需求!


五、额外补充:占空比怎么算?(CCR 寄存器)

做呼吸灯还用到了 CCR 比较寄存器,,非常简单:

  • CCR 作用:决定 PWM 的「高电平时间」或「低电平时间」。
  • 占空比公式:占空比寄存器值寄存器值
  • 对应你的项目(50% 占空比):寄存器值
  • 对应你的代码:
    GTIM_SetCompare4(500);
    

六、结合 GTIM 功能框图,再加深理解

我们把之前讲的所有概念,对应到CW32F003 GTIM 功能框图上,你就能彻底看懂硬件是怎么工作的了:

  1. 时钟来源:框图左上角的 PCLK 就是系统时钟(48MHz),通过选择器进入预分频器。
  2. 预分频器:框图里写着「/1, …, /32768」的模块,由 CR0.PRS 控制,对应我们算的 PSC。
  3. 核心计数器:框图中间的「16 位计数器 CNT」,自动从 0 开始加,对应我们的 CNT 寄存器。
  4. 重装载寄存器:框图里的「重载寄存器 ARR」,给 CNT 设终点,对应我们的 ARR 寄存器。
  5. PWM 输出通道:框图最下面的「CH4 捕获比较」和「输出控制」模块,对应我们的 CCR 寄存器和 PC02 引脚输出。

七、常见问题与避坑指南(小白必看)

1. 坑点一:PSC 寄存器值忘记减 1

  • 现象:PWM 频率是预期的一半,或者完全不对。
  • 解决:永远记住 PSC寄存器值 = 预分频系数 - 1

2. 坑点二:GPIO 引脚没有设为复用推挽输出

  • 现象:代码配置都对,但 PC02 引脚没有 PWM 波形输出,灯不亮。
  • 解决:必须把 GPIO 设为 GPIO_MODE_AF_PP(复用推挽输出),普通推挽输出是连不上定时器的。

3. 坑点三:PWM 极性和 LED 接线不匹配

  • 现象:灯常亮或者常灭,不会呼吸。
  • 解决:灌电流接法(LED 负极接 PC02)设为低电平有效,拉电流接法设为高电平有效。

八、总结与快速查表

1. 一句话总结

  • 系统时钟是 “原始心跳”,预分频器是 “减速齿轮”,计数频率是 “实际工作心跳”,CNT 是 “当前读数”,ARR 是 “终点”。
  • 计算步骤:先选好算的计数频率→算 PSC(减 1)→算 ARR(减 1)。

2. 快速计算表(CW32F003 48MHz 系统时钟)

表格

目标 PWM 频率 推荐计数频率 预分频系数 PSC 寄存器值 ARR 寄存器值
1kHz 1MHz 48 47 999
2kHz 1MHz 48 47 499
5kHz 1MHz 48 47 199
10kHz 1MHz 48 47 99
100Hz 48kHz 1000 999 479

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐