使用stm32内部时钟进行定时中断
学习江科大stm32第5天 ---- 6-1 TIM定时中断 、 6-2定时器定时中断&定时器外部中断
1、TIM(Timer) 定时器
(1)定时器对输入的时钟进行计数,当计数值达到设定值时触发中断;
(2)16位计数器、预分频器、自动重装寄存器的时基单元,并在72MHz计数时钟下可以实现最大59.65s的计时;
(3)具备基本的定时中断功能,包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能;
(4)分为高级定时器、通用定时器、基本定时器 。其中STM32C8T6中TIM1为高级定时器、TIM2 TIM3 TIM4为通用定时器;
(5)适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM);使用定时器预分频器和RCC时钟预分频器,脉冲长度和波形周期可以在几个微秒到几个微秒间调整;
(6)每个定时器都是完全独立的,没有互相共享任何资源,但可以一起可以同步操作。
图1 通用定时器框图
2、时序图
(1) 预分频器时序
从上面两张图来看,CK_PSC一直输出一个方波,CEN高电平使能,当预分频器为0,定时器根据CK_PSC的一个波形来进行累积计数,到达更新事件(UEV)后,从之前的预分频系数变为3(即根据CK_PSC的四个波形来进行累计计数),期间控制寄存器在上一个计数周期发生变化,通过预分频缓冲器在这个周期结束后再将计数周期改变,预分频计数器通过对CK_PSC方波信号进行计数从而得到以CK_CNT的四个周期为信号的方波波形。
且计数器计数频率:CK_CNT = CK_PSC / ( PSC + 1 )
(2) 计数器时序
CK_INT为内部时钟72MHz ,CNT_EN为计数器时钟使能(高电平使能),CK_CNT(内部时钟分频系数因子为2)。每两个时钟频率,计数器寄存器在CK_CNT的上升沿自增,到达36后计数器溢出,再来一个上升沿(计数器归零),同时产生一个更新事件脉冲,还会置一个更新中断标志位UIF(该标志位只要置1,就会申请中断,中断响应后,需要在中断程序中手动清零)
计数器溢出频率: CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC/(PSC + 1)/(ARR + 1)
其中计数器也存在有缓存的情况
3、定时中断基本结构
第一步,RCC开启时钟;
第二步,选择时基单元的时钟源(选择内部时钟);
第三步,配置时基单元(预分频器、计数器、自动重装器);
第四步,配置输出中断控制,允许更新中断输出到NVIC;
第五步,配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级。
4、代码部分
(1)Timer.c
#include "stm32f10x.h"
void Timer_Init(void)
{
//开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启TIM2的时钟
//配置时钟源
TIM_InternalClockConfig(TIM2); // 选择TIM2为内部时钟
//时基单元初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure ; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; //时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up ; //计数器模式选择向上计数
TIM_TimeBaseInitStructure.Period = 10000 - 1 ; //计数周期 ,即ARR的值
TIM_TimeBaseInitStructure.Prescaler = 7200 - 1 ;//预分频器, 即PSC的值
TIM_TimeBaseInitStructure.RepetitionCounter = 0 ; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure ) //将设置的结构体用来配置TIM2的时基单元
//中断输出配置
TIM_ClearFlag(TIM2,TIM_FLAG_Update) ; //清除定时器更新标志位
//TIM_TimeBaseInit函数末尾,手动产生了更新事件
//若不清除此标志位,则开启中断后,会立刻进入一次中断
//对上面一句话具体的描述:就是说如果开始程序后又复位,计时就会直接从1开始,而不是从0
//如果不介意此问题,则不清除此标志位
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的TIM2线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE ; //指定NVIC使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2 ; //指定NVIC线路的抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1 ; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure) ;//将结构体变量交给NVIC_Init,配置NVIC
//TIM使能
TIM_Cmd(TIM2,ENABLE); // 使能TIM2,定时器开始运行
}
(2)main.c
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //判断是否是TIM2的更新事件触发的中断
{
Num ++; //Num变量自增,用于测试定时中断
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中断标志位
//中断标志位必须清除
//否则中断将连续不断地触发,导致主程序卡死
}
}