3. MCU定时器深入:通用定时器与高级定时器的区别。自动重装载寄存器(ARR)与捕获/比较寄存器(CCR)的配置。

好,咱们今天聊点硬核的。定时器这东西,说白了就是MCU的“心脏节拍器”。很多刚入行的朋友觉得定时器就是用来计个时、产生个PWM,其实远不止这么简单。我个人习惯把定时器分成两类来看:通用定时器和高级定时器。它们俩,就像普通轿车和越野车,都能跑,但能干的事儿差远了。

3.1 通用定时器 vs 高级定时器:到底差在哪?

先说说通用定时器。这是最常用的,比如STM32里的TIM2、TIM3、TIM4、TIM5这些。它能干嘛?基本的定时、计数、输入捕获、输出比较、产生PWM,这些活儿它都能干。我在项目中做过一个简单的直流电机调速,用的就是通用定时器的PWM模式,完全够用。

但高级定时器就不一样了。像TIM1和TIM8,它们除了具备通用定时器的所有功能外,还多了很多“高级”玩意儿。你想想看,什么场合需要更复杂的控制?三相电机驱动、开关电源、数字电源变换器,这些场合就需要高级定时器。

具体多了什么呢?我列个表,大家一目了然:

功能特性 通用定时器 高级定时器
基本定时/计数
PWM输出
输入捕获
输出比较
互补PWM输出
死区时间插入
刹车功能(Break)
重复计数
编码器接口 部分支持

看到没?高级定时器多了互补输出、死区插入、刹车功能。这些在电机驱动里是刚需。我曾经在一个伺服驱动器项目里,就是因为没选对定时器,结果不得不用软件模拟死区,那叫一个痛苦。后来换了高级定时器,硬件自动搞定,省心多了。

3.2 自动重装载寄存器(ARR)的配置

ARR,全称Auto-Reload Register。它的作用很简单:决定定时器的计数周期。说白了,就是定时器从0数到ARR,然后归零重新开始。

举个例子,你想让定时器每1ms产生一次更新事件。假设定时器的时钟频率是72MHz,预分频器设置成72-1,那么计数器的时钟就是1MHz,也就是每1us计一次数。那么ARR应该设成多少?

// 定时器时钟 72MHz
// 预分频器 PSC = 72 - 1 = 71
// 计数器时钟 = 72MHz / 72 = 1MHz = 1us
// 想要 1ms 中断一次
// ARR = 1000 - 1 = 999

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 71;        // 预分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseStructure.TIM_Period = 999;          // ARR值
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 高级定时器才有的
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

嗯,这里要注意一点:ARR的值是实际周期减1。因为计数器是从0开始计数的,计到ARR时,其实已经计了ARR+1个脉冲。这个坑我刚开始学的时候踩过,算出来的时间总差那么一点。

小技巧: 配置ARR时,建议先算好需要的频率或周期,再反推ARR值。公式很简单:更新频率 = 定时器时钟 / (PSC+1) / (ARR+1)。反过来,ARR = 定时器时钟 / (PSC+1) / 目标频率 - 1。

3.3 捕获/比较寄存器(CCR)的配置

CCR,全称Capture/Compare Register。这玩意儿比ARR灵活多了。它有两种工作模式:捕获模式和比较模式。

比较模式:这是最常用的,用来产生PWM。计数器CNT的值不断增长,当CNT等于CCR时,输出电平翻转。所以CCR的值直接决定了PWM的占空比。

// 配置PWM模式1,输出高电平有效
// 假设ARR = 999,想要50%占空比
// CCR = 999 * 50% = 499.5,取整为500

TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 500;             // CCR值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);

捕获模式:用来测量外部信号的频率或脉宽。当外部信号发生跳变时,硬件自动把当前CNT的值锁存到CCR里。这样你就能知道信号变化的时间点。

核心区别: ARR决定周期,CCR决定占空比。ARR是全局的,所有通道共用;CCR是每个通道独立的,可以分别设置不同的占空比。

3.4 实际配置中的避坑指南

讲几个我实际项目中遇到的坑,大家引以为戒。

坑1:高级定时器的PWM输出需要额外使能
通用定时器配置完OC就完事了。但高级定时器不行,你还得使能主输出:TIM_CtrlPWMOutputs(TIM1, ENABLE);。我当初第一次用TIM1,折腾了半天没波形,最后发现是这步忘了。
坑2:死区时间的设置
驱动H桥或三相逆变桥时,上下管不能同时导通,否则就是短路。高级定时器可以自动插入死区时间。死区时间由TIM_BDTR寄存器的DTG位决定。我曾经因为死区设得太短,导致MOS管发热严重。后来查手册才知道,死区时间要根据MOS管的关断延迟来算,不能拍脑袋设。
坑3:刹车功能的使用
高级定时器的刹车功能,可以在紧急情况下强制关闭PWM输出。比如电机过流、过温,硬件信号一来,输出立刻变成安全状态。这个功能在工业产品里是强制要求的。我建议大家在设计电机驱动板时,一定要把刹车引脚引出来,接到保护电路上。

3.5 总结一下

通用定时器和高级定时器的选择,取决于你的应用场景。做简单的LED调光、蜂鸣器控制,通用定时器足够了。但如果你要做电机驱动、数字电源,那就老老实实用高级定时器,别想着省成本。

ARR和CCR的配置,记住一句话:ARR定周期,CCR定占空比。配置时注意减1的问题,还有高级定时器的额外使能步骤。把这些搞明白了,定时器这块就算入门了。

下一章,咱们聊聊PWM的极性配置和互补输出,那才是电机驱动的精髓所在。