本文重点在于记录和理解定时器中断的流程,关于定时器和中断的知识点不过多赘述,相关知识点可以查看我的另外两篇文章,讲的很详细,希望能有所帮助。
定时器:
STM32定时器和时钟树详细图文讲解,小白必会!-CSDN博客
外部中断:
STM32外部中断讲解-CSDN博客
下图为用内部时钟作时钟源的定时器中断流程,标了执行逻辑的顺序。
- RCC时钟使能,开启APB1总线上的TIM2时钟(TIM2,3,4,5为通用定时器)
// 1. RCC时钟使能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
- 选择时基单元(预分频器,计数器,自动重装器)的时钟源
// 2. 选择时基单元的时钟源 TIM_InternalClockConfig(TIM2);
选择内部时钟,连接到使用的TIM2通用定时器。
- 配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; // 定义结构体 TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 滤波器分频,设为不分频 TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数 TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1; // 自动重装器 TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1; // 预分频器 TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 高级定时器的重复计数器 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); // 初始化时基单元
TIM_TimeBaseInitStruct结构体包含了时基单元的配置,最后初始化别忘了取值符&。
- 中断输出控制
// 开启更新中断到NVIC的通路,更新中断就是计数溢出产生的,表明定时器定的时间到了 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
在3到4这个过程中间,中断信号会在状态寄存器里置一个中断标志位,这个标志位会通过中断输出控制到NVIC申请中断。
为什么要有中断输出控制呢?
因为定时器还有很多模块都需要申请中断,比如不仅计数器重新置零会触发中断,触发信号也会申请中断,输入捕获和输出比较也会申请中断,所有这些中断都需要经过输出中断控制。如果需要就允许,不需要就禁止,简单来说中断输出控制就是一个中断输出的允许位,如果需要某个中断就允许一下。 - 中断分组,配置和初始化NVIC
// 5. 中断分组 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置和初始化STM32中断控制器(NVIC) NVIC_InitTypeDef NVIC_InitStrucyure; NVIC_InitStrucyure.NVIC_IRQChannel = TIM2_IRQn; //指定中断请求通道。 NVIC_InitStrucyure.NVIC_IRQChannelCmd = ENABLE; //启动指定的通道 NVIC_InitStrucyure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级 NVIC_InitStrucyure.NVIC_IRQChannelSubPriority = 1; //响应优先级 NVIC_Init(&NVIC_InitStrucyure);
在配置NVIC结构体前先进行中断分组。
- 使能计数器
// 6.运行控制,使能计数器 TIM_Cmd(TIM2, ENABLE);
- 自动调用中断函数
完整代码如下,值得注意的是定时器初始化后会自动触发一个事件,不等计数器就立马触发中断,所以得加个清除标志位。
void Timer_Init(void)
{
// 1. RCC时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 2. 选择时基单元的时钟源
TIM_InternalClockConfig(TIM2);
// 3. 配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 滤波器分频,设为不分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1; // 自动重装器
TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1; // 预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 高级定时器的重复计数器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); // 初始化时基单元
// 实际单元初始化会产生中断事件,不等计数器就立马触发中断,所以清除标志位
TIM_ClearFlag(TIM2, TIM_IT_Update);
// 4. 中断输出控制
// 开启更新中断到NVIC的通路,更新中断就是计数溢出产生的,表明定时器定的时间到了
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 5. 中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置和初始化STM32中断控制器(NVIC)
NVIC_InitTypeDef NVIC_InitStrucyure;
NVIC_InitStrucyure.NVIC_IRQChannel = TIM2_IRQn; //指定中断请求通道。
NVIC_InitStrucyure.NVIC_IRQChannelCmd = ENABLE; //启动指定的通道
NVIC_InitStrucyure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
NVIC_InitStrucyure.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_Init(&NVIC_InitStrucyure);
// 6.运行控制,使能计数器
TIM_Cmd(TIM2, ENABLE);
// 7. 之后自动调用中断函数
}