高级定时器

STM32 高级定时器详解(从零开始)

你发的这份文档是 TIM1/TIM8 高级控制定时器的参考手册。我来从最基础的概念讲起,帮你建立完整的理解。

第一部分:定时器是什么?

定时器的本质就是一个自动数数的计数器。给它一个时钟脉冲,它就数一下。

复制代码
时钟脉冲:  __|¯|__|¯|__|¯|__|¯|__|¯|__|¯|__|¯|__|¯|__

计数器值:    0    1    2    3    4    5    6    7  ...

就这么简单。所有的定时器功能(PWM、输入捕获、输出比较...)都是在这个"数数"的基础上做文章。


第二部分:时基单元------定时器的心脏

时基单元由 4 个寄存器 组成,控制计数器"怎么数":

1. PSC(预分频器)------ 控制数数的速度

时钟太快了?用 PSC 先把时钟除一下再送给计数器。

复制代码
原始时钟 240 MHz:  ||||||||||||||||||||||||  太快了!

PSC = 239 后:
计数器时钟 = 240MHz / (239+1) = 1MHz

也就是每 1μs 数一下

公式:计数器时钟 = 定时器时钟 / (PSC + 1)

2. CNT(计数器)------ 当前数到几了

这就是那个一直在数数的寄存器,你可以随时读取它的值。

3. ARR(自动重载寄存器)------ 数到多少就归零

复制代码
ARR = 999 时:

CNT:  0 → 1 → 2 → ... → 998 → 999 → 溢出! → 0 → 1 → ...
                                         ↑
                                    产生更新事件(UEV)

4. RCR(重复计数器)------ 高级定时器独有

普通定时器每次溢出都产生更新事件。重复计数器让你可以"每 N+1 次溢出才产生一次更新事件"。

复制代码
RCR = 2 时:
溢出第1次 → 不更新(RCR: 2→1)
溢出第2次 → 不更新(RCR: 1→0)
溢出第3次 → 更新! (RCR: 0→重载为2)

主要用于电机控制 PWM 中减少中断频率。


第三部分:回答你的问题------Auto-Reload Preload (ARPE)

ARPE 到底控制的是哪个寄存器?

控制的是 ARR(自动重载寄存器)

ARR 寄存器其实在硬件内部有两层结构

复制代码
你写入的地方           实际起作用的地方
┌──────────────┐      ┌──────────────┐
│  预装载寄存器  │ ───→ │   影子寄存器   │ ←→ 与CNT比较
│ (Preload)    │      │  (Shadow)    │
└──────────────┘      └──────────────┘
   你能读写的             真正干活的

ARPE = 0(Disable,你当前的配置):

复制代码
你写 ARR = 500
        ↓ 立刻生效!
影子寄存器 = 500  (计数器马上用新值)

ARPE = 1(Enable):

复制代码
你写 ARR = 500
        ↓ 先存着,不生效
预装载寄存器 = 500
        ↓ 等到下次更新事件(UEV)
影子寄存器 = 500  (这时才真正生效)

为什么要这么设计?

用 PWM 举例。假设你正在输出一个 PWM 波,想改变频率(改 ARR):

没有预装载(ARPE=0)------可能出问题:

复制代码
ARR原来=1000,CNT正在数到800

此刻你改 ARR=500 → 立刻生效!

但 CNT 已经是 800 > 500 了!
计数器不知道什么时候该溢出,只能一直数到最大值才回来
→ 这一个周期的波形就乱了

有预装载(ARPE=1)------安全:

复制代码
ARR原来=1000,CNT正在数到800

此刻你改 ARR=500 → 先存着

CNT继续: 800 → 999 → 1000 → 溢出 → 更新事件!
此时 ARR=500 才真正生效
→ 下一个周期完整地用新值,波形不会乱

第四部分:三种计数模式

递增计数(你当前用的)

复制代码
ARR = 6

CNT: 0 → 1 → 2 → 3 → 4 → 5 → 6 → (溢出) → 0 → 1 → ...
                                         ↑ 更新事件

递减计数

复制代码
ARR = 6

CNT: 6 → 5 → 4 → 3 → 2 → 1 → 0 → (下溢) → 6 → 5 → ...
                                         ↑ 更新事件

中心对齐(递增/递减交替)

复制代码
ARR = 6

CNT: 0→1→2→3→4→5→6→5→4→3→2→1→0→1→2→...
                      ↑                 ↑
                   上溢事件           下溢事件

生成的PWM波形是对称的,常用于电机控制

第五部分:四大核心功能

功能1:输入捕获 ⭐(你的动平衡项目用的就是这个)

作用: 外部信号边沿到来时,硬件自动把 CNT 的值"拍照"存下来。

复制代码
CNT在自由计数:  0  1  2  3  4  5  6  7  8  9  10 11 12 ...

外部信号:     _____|¯¯¯¯¯¯¯¯¯¯|____________|¯¯¯¯
                   ↑                        ↑
              CCR1 = 4                  CCR1 = 12
              (拍照!存下4)            (拍照!存下12)

两次捕获的差 = 12 - 4 = 8 个tick → 就知道了信号周期

这就是你测相位差的原理:

复制代码
光电头信号:    _____|¯|_________________________
                    ↑ CH1捕获,CCR1 = 1000

过零检测信号:  _______________|¯|_______________
                              ↑ CH2捕获,CCR2 = 4500

时间差 = 4500 - 1000 = 3500 ticks
周期 = 20000 ticks(50Hz)
相位差 = 3500/20000 × 360° = 63°

功能2:输出比较

作用: CNT 数到某个值时,自动改变引脚电平。

复制代码
CCR1 = 5,模式 = 翻转

CNT: 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
OC1: __________________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|____
                       ↑ CNT=CCR1,翻转!      ↑ 再次翻转

功能3:PWM 生成

本质就是输出比较的特殊应用。

复制代码
ARR = 999(决定频率)
CCR1 = 300(决定占空比 = 300/1000 = 30%)

PWM模式1:CNT < CCR1 时输出高,否则输出低

CNT:  0 ──→ 299 ──→ 300 ──→ 999 ──→ 0
OC1:  ¯¯¯¯¯¯¯¯¯¯¯¯|__________________|¯¯¯¯
      ← 高(30%) →  ←    低(70%)     →

改 CCR1 就改占空比,改 ARR 就改频率。

功能4:编码器接口

两个正交信号(A相、B相)接入,定时器自动判断旋转方向和位置:

复制代码
正转时:A相超前B相 → CNT递增
反转时:B相超前A相 → CNT递减

CNT的值就直接代表编码器位置,全硬件完成,CPU不用管

第六部分:高级定时器 vs 通用定时器------多了什么?

特性 通用定时器(TIM2~TIM5) 高级定时器(TIM1/TIM8)
基本功能 ✅ 全有 ✅ 全有
互补输出+死区 ✅ 驱动半桥/全桥
断路保护 ✅ 紧急关断PWM
重复计数器 ✅ 减少更新频率
位宽 TIM2/TIM5: 32位, TIM3/TIM4: 16位 16位

互补输出 + 死区

驱动半桥电路(上管+下管),两个管子绝不能同时导通,否则短路:

复制代码
OCxREF:    ¯¯¯¯¯|___________|¯¯¯¯¯
                 ↓           ↓
OC1 (上管): ¯¯¯|__|_________|__|¯¯   ← 提前关
OC1N(下管): ___|__|¯¯¯¯¯¯¯¯¯|__|__   ← 延迟开
                ↑               ↑
              死区时间         死区时间
              (两个都关)      (两个都关)

断路保护

复制代码
正常运行: PWM正常输出驱动电机

突然检测到过流! → BRK引脚触发
                     ↓ 硬件自动(不需要CPU介入)
                  MOE = 0
                  所有PWM输出立刻变为安全状态
                  电机停转,功率管保护

第七部分:输入滤波器(ICxF)详解

你的配置中 Input Filter 我建议设为 8,它的含义是:

复制代码
ICxF = 0000: 无滤波,任何边沿都算
ICxF = 0011: 连续采样8次都是新电平才算有效
ICxF = 1000: 以 fDTS/8 频率采样,连续6次才算有效  ← 你用的

作用就是抗毛刺:

复制代码
实际信号(有毛刺):  _____|¯|_|¯¯¯¯¯¯¯¯¯¯¯|___
                          ↑ 假的!

滤波后:              ________|¯¯¯¯¯¯¯¯¯¯¯¯|___
                             ↑ 这才是真的边沿

回到你的动平衡项目

你只用到了高级定时器很小一部分功能中的输入捕获。但你选的是 TIM2(通用定时器),不是高级定时器 TIM1/TIM8,所以那些互补输出、死区、断路等高级功能跟你没关系。

你实际用到的:

复制代码
PSC = 239        → 把240MHz分频到1MHz
ARR = 4294967295 → 32位最大值,让计数器自由跑
CH1 = 输入捕获   → 光电头信号,抓时间戳
CH2 = 输入捕获   → 过零检测信号,抓时间戳
ARPE = Disable   → ARR不会改,无所谓
滤波器 = 8       → 抗毛刺
中断 = 使能      → 捕获到边沿时通知CPU读数据

这就是全部。定时器的其他功能虽然强大,但你的场景不需要。

相关推荐
DLGXY2 小时前
STM32(十八)——IIC通信、MPU6050、IIC外设
stm32·单片机·嵌入式硬件
Struggle to dream3 小时前
STM32关于GPIO的模式配置详解
stm32·单片机·嵌入式硬件
上海合宙LuatOS3 小时前
LuatOS核心库API——【fatfs】支持FAT32文件系统
java·前端·网络·数据库·单片机·嵌入式硬件·物联网
xiaobobo33303 小时前
评判一下stm32的标准库函数写的怎样?
stm32·单片机·嵌入式硬件
码农三叔3 小时前
(11-4-01)完整人形机器人的设计与实现案例:机器人的站立与行走
人工智能·嵌入式硬件·机器人·人机交互·人形机器人
小武编程3 小时前
基于STM32G030系列MCU之ADC采集转电压值
stm32·单片机·嵌入式硬件
逐步前行4 小时前
STM32_烧录调试
stm32·嵌入式硬件·mongodb
小龙报5 小时前
【51单片机】51 单片机 IIC 协议深度解析:时序实现 + GXHT3L 连续转换模式 + 数据解析
c语言·数据结构·stm32·单片机·嵌入式硬件·物联网·51单片机
不做无法实现的梦~16 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶