一、什么是定时器?
1.定时器本质上是一个硬件计数器,它依靠时钟脉冲进行计数,当计数值达到预设值时可以触发中断或事件。通过控制计数频率和计数范围,我们可以实现各种与时间相关的功能。
2.STM32定时器家族
STM32中的定时器根据复杂程度分为三类:
| 基本定时器 | 只有最基本的计数功能,无外部引脚 | 基础定时、产生中断、触发DAC | TIM6、TIM7 |
| 通用定时器 | 拥有输入捕获、输出比较、PWM生成等 | 波形测量、PWM输出、电机控制等 | TIM2、TIM3、TIM4、TIM5 |
| 高级定时器 | 在通用基础上增加互补输出、死区控制等 | 三相电机驱动(带刹车功能) | TIM1、TIM8 |
二、定时器的核心组件:
-
时钟源
-
内部时钟(CK_INT):来自APB总线,通常为72MHz或经过预分频后的频率。
-
外部时钟(TIx、ETR):通过引脚输入脉冲计数。
-
其他:ITRx(其他定时器级联)、内部触发等。
-
-
预分频器(PSC)
对时钟源进行分频,得到计数器实际使用的时钟频率。
计数器时钟 = 定时器时钟 / (PSC + 1) -
计数器(CNT)
16位或32位寄存器,存储当前计数值。 -
自动重装载寄存器(ARR)
存放计数上限值。当CNT达到ARR时,会清零并重新开始计数(或向下计数到0),同时可产生更新事件/中断。
4. 三种基本计数模式
-
向上计数:CNT从0递增到ARR,然后重置为0,产生溢出事件。
-
向下计数:CNT从ARR递减到0,重置为ARR,产生下溢事件。
-
中央对齐模式:先向上计数到ARR,再向下计数到0,如此循环,每个周期产生两次溢出(上溢和下溢)。
5. 定时器的常见应用场景
-
定时中断:产生固定时间间隔的中断(如1ms触发一次)。
-
PWM输出:通过输出比较通道生成占空比可调的方波。
-
输入捕获:测量外部信号的频率、脉宽。
-
编码器接口:直接连接正交编码器读取电机转速和方向。
-
单脉冲模式:输出一个特定宽度的脉冲。
6. 如何配置一个定时器(以通用定时器TIM3为例)
1.使能TIM3时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
2.配置时基单元(预分频器PSC,自动重装载ARR)
配置时基单元的本质:时基单元是硬件定时器的核心组成部分。配置时基单元,本质上就是设置定时器的时间基准,也就是决定定时器“滴答”一次需要多长时间。
-
PSC(预分频器,Prescaler): 定时器通常连接到一个高速时钟(例如72MHz或168MHz)。预分频器的作用是将这个高速时钟的频率分频,降低到一个合适的值。例如,将72MHz时钟除以7200,得到10kHz的计数时钟。
-
ARR(自动重装载寄存器,Auto-Reload Register): 这指定了计数的上限。定时器从0开始计数,一直数到ARR设置的值。
-
CNT(计数器,Counter): 这是当前计数值。
配置时基单元的目的:
通过组合上述参数,您可以精确控制定时器的溢出频率(即定时中断的频率)或PWM(脉宽调制)的周期。
计算公式示例:
定时器中断频率 = (定时器输入时钟) / [(PSC + 1) * (ARR + 1) ]
举例:
如果您想让定时器每1毫秒中断一次,您就需要配置时基单元:
1.选择时钟源。
2.设置PSC和ARR的值,使得 (时钟频率) / (分频系数 * 计数值) = 1000 Hz(即1ms)。
程序演示:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 9999; // ARR重装载
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // PSC预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割(一般用不到)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
3.使能更新中断
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
4.配置NVIC:(作用是使能 TIM3 的中断,并设置该中断的优先级。)
1. NVIC 是什么?
NVIC 是 Cortex-M 内核中负责管理中断的模块。它可以:
-
使能/禁用某个外设的中断请求。
-
设置中断的抢占优先级和子优先级(用于中断嵌套)。
-
处理中断的硬件响应。程序演示:
NVIC_InitTypeDef NVIC_InitStructure;
//指定要配置的中断通道,对应 TIM3 的中断向量号
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设置该中断的抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//设置该中断响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能 TIM3 的中断请求
NVIC_Init(&NVIC_InitStructure);
3. 关于优先级分组的补充说明
在配置上述优先级之前,通常需要先调用 NVIC_PriorityGroupConfig() 函数来设置优先级分组。优先级分组决定了抢占优先级和子优先级各占多少位(例如,分组为 NVIC_PriorityGroup_2 表示 2 位抢占优先级,2 位子优先级)。这段代码中没有显示分组设置,但在实际项目中,一般在系统初始化阶段会设置一次。
-
如果未设置分组,默认可能是所有位都用于抢占优先级(取决于复位值),建议明确配置分组以避免混乱。
-
抢占优先级和子优先级的数值范围取决于分组配置(例如,分组2下,抢占优先级可取 0~3,子优先级可取 0~3)。
5.使能TIM3计数器:
TIM_Cmd(TIM3, ENABLE);
6.编写中断服务函数:
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
// 用户代码:翻转LED等
GPIO_ToggleBits(GPIOC, GPIO_Pin_13); // 假设LED在PC13
}
}
三、常见问题:
1.定时器不工作:
检查时钟是否开始,是否使能中断,NVIC,时基单元配置是否正确
2.定时器如何计算时间:
定时时间=(PSC+1)*(ARR+1)/定时器时钟频率
3.如何选择定时器:
简单定时:基本定时器
PWM或输入捕获:通用定时器
电机控制:高级定时器



