1. 简介
定时器是一个非常重要的组件。它可以在一定的时间间隔内执行某些操作,比如产生周期信号、计时等。STM32F103系列内置了多个定时器模块,包括基础定时器(TIM6/TIM7)、通用定时器(TIM1/TIM8)、高级定时器(TIM2~TIM5)等。这些定时器模块可以用来产生各种不同类型的定时器信号,并且支持多种不同的定时器操作。
2. 基础定时器的初始化
首先,需要进行定时器的初始化配置,在bsp_timBase.c
文件中编写初始化函数:
#include "stm32f10x.h"
void TIM6_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
// 定时器配置
TIM_TimeBaseStructure.TIM_Period = 1000; // 累计1000计数值后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频器 时钟预分频数为 (该值+1)
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
// 使能定时器
TIM_Cmd(TIM6, ENABLE);
}
在以上代码中,首先使能了定时器的时钟,然后配置了定时器的周期和预分频器。将定时器的周期设置为1000,预分频器设置为71,这意味着定时器的计数器将以1ms的周期自动重载。最后,使能了定时器。
3. 定时器中断处理
在定时器开始计数后,当定时器计数器达到自动重载值时,定时器将产生一个中断请求。
当中断请求被触发时,我们需要编写一个中断处理函数来处理这个中断:
void TIM6_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
// 处理中断请求
// ...
// 清除中断标志位
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}
}
首先判断中断请求是否被触发,如果中断请求被触发,就处理中断请求。最后,我们清除了中断标志位,以便定时器下次产生中断请求。注意,在清除中断标志位之前,我们必须先判断中断标志位是否被设置,否则会导致中断标志位无法清除。
PS:在这里,我们可以编写一些需要定时执行的操作。
4. 定时器应用举例
举例:产生周期性的定时器信号。以下是一个基本的定时器应用代码,整合到main.c
中:
注意周期要减一
定时时长 T = (自动装载周期的值+1)*(预分频系数+1) / 72MHz
#include "stm32f10x.h"
void TIM6_Init(void);
void TIM6_IRQHandler(void);
int main(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 配置NVIC中断优先级分组为2抢占优先级和2响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置定时器中断优先级为0
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 初始化定时器
TIM6_Init();
while (1)
{
// 主循环
}
}
void TIM6_Init(void)
{
// 使能定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
// 定时器配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = (1000-1); // ! 注意这里要减一,是一个坑。计数器自动重载值
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频器
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
// 使能定时器中断
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
// 使能定时器
TIM_Cmd(TIM6, ENABLE);
}
编写中断函数:
void TIM6_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
// 中断任务
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}
}