TIM定时中断
TIM定时中断
TIM(Timer)定时器
功能
对输入的时钟进行计数,并在计数值达到设定值时触发中断
时基单元
在72MHz计数时钟下可以实现最大59.65s的定时
功能
定时中断
内外时钟源选择
输入捕获
输出比较
编码器接口
主从触发模式
类型
高级定时器、通用定时器、基本定时器
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
基本定时器
UI:更新中断
通用定时器
若使用外部时钟,首选ETR引脚外部时钟模式2的输入
定时中断基本结构
GPIO->RCC/ETR->内部/外部时钟->时基单元计时->中断输出控制->NVIC
各类参数
预分频系数PSC:调整输入时钟信号的频率,为定时器提供一个适合的计数速率
重装载值ARR:定时器的计数值,达到这个ARR时,定时器就会重新装载其他值
定时器时钟CK_CNT
定时器时钟源CK_PSC:一般为72MHz
CK_CNT_OV:最终定时频率
预分频器PSC
计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)
计数器CNT
计数器溢出频率/最终输出的频率:
CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)
无预装时序:改变ARR->直接改变记到的数
有预装时序:改变ARR后,等到原先的周期读完后再开始新的ARR计数
RCC时钟树
代码部分
TIM库常用函数
省流版
时基单元 TimeBaseInit
中断输出控制 ITConfig
运行控制 TIM_Cmd
void TIM_DeInit(TIM_TypeDef* TIMx);
//重设TIMx寄存器
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//时钟分频,选择不分频:TIM_CKD_DIV1
//此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
/*计数器模式:
向上计数 TIM_CounterMode_Up
向下计数 TIM_CounterMode_Down
中央对齐计数 TIM_CounterMode_CenterAligned1/2/3
*/
//计时1秒
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
//使能或者失能 TIMx 外设
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
//使能外设的 TIM 中断输出【Config常用】
/*uint16_t TIM_IT参数:
TIM_IT_Update TIM 中断源
TIM_IT_Trigger TIM 触发中断源
TIM_IT_CC1 TIM 捕获/比较 1-4 中断源
*/
/*时钟源选择*/
//内部时钟源
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
//外部时钟源
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//写预分频值
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//改变计数器的计数模式
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
//(自动重装器)ARR 上的预装载寄存器配置
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
//设置 TIMx 计数器寄存器值 CNT
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
//设置 TIMx 自动重装载寄存器值 ARR
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
//获得 TIMx 计数器的值->返回int
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);
//获得 TIMx 预分频值->返回int
【主函数内查看】
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
//检查指定的 TIM 标志位设置与否->SET 或 RESET
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
//清除 TIMx 的待处理标志位
/*TIM_FLAG参数:
TIM_FLAG_Update TIM 更新标志位
TIM_FLAG_Trigger TIM 触发标志位
TIM_FLAG_CC1-4 TIM 捕获/比较 1-4 标志位
TIM_FLAG_CC1OF TIM 捕获/比较 1-4 溢出标志位
*/
【中断函数内查看】
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
Timer.c库
内部时钟
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2的时钟
/*配置时钟源*/
TIM_InternalClockConfig(TIM2);
//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
/*中断输出配置*/
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//清除定时器更新标志位
/*【原因】
TIM_TimeBaseInit函数末尾,手动产生了更新事件
若不清除此标志位,则开启中断后,会立刻进入一次中断
*/
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE);//使能TIM2,定时器开始运行
外部时钟
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA的时钟
/*GPIO初始化*/->外部时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//将PA0引脚初始化为上拉输入
/*外部时钟配置*/
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted, 0x0F);
/*TIM_ExtTRGPrescaler[预分频器]
TIM_ExtTRGPSC_OFF:不需要预分频
TIM_ExtTRGPSC_DIV2-8:TIM ETRP除以2-8
*/
/*TIM_ExtTRGPolarity[极性]
TIM_ExtTRGPolarity_Inverted:低电平/下降沿
TIM_ExtTRGPolarity_NonInverted:高电平/上升沿
*/
//选择外部时钟模式2,时钟从TIM_ETR引脚输入
//注意TIM2的ETR引脚固定为PA0,无法随意更改
//最后一个滤波器参数加到最大0x0F,可滤除时钟信号抖动
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//ARR到10 CNT记1
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//外部计时器 不需要配置预分频器
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
/*中断输出配置*/
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//开启TIM2的更新中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE);
中断函数
复制到使用它的地方
否则需要extern
声明跨文件变量
eg extern int g_val;
void TIM2_IRQHandler(void)//固定的NVIC函数
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}