定时器基本介绍
定时器分为基本定时器,通用定时器和高级定时器。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6),高级定时器有通用定时器的所有功能,通用定时器有基本定时器的所有功能。
由上图可知,要定时器产生1s中断需要开启时钟->预分频->计数->中断
时钟源
时钟来源:
- 内部时钟(CK_INT)
- 外部时钟模式1:外部输入脚(TIx)计数器可以在选定输入端的每个上升沿 或下降沿计数。
- 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
- 外部时钟模式2:外部触发输入(ETR)计数器能够在外部触发ETR的每一个上升沿或下降沿计数。
外部晶振8Mhz倍频9倍=72Mhz系统时钟,假如外部晶振损坏则以内部时钟(RC震荡器)8Mhz运行。
默认SystemInit函数下除非APB1的分频系数是1,否则通用定时器的时钟等于APB1时钟的2倍。APB1时钟=36M,所以APB1的分频系数=AHB/APB1时钟=2,所以,通用定时器时钟CK_INT=2*36M=72M
时基单元
可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可 以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。
PSC预分频器CK_PSC
预分频器可以将计数器的时钟频率按1到65536之间的任意值分频。这个控制寄存器带有缓冲器,它能够在工作时被改 变。新的预分频器参数在下一次更新事件到来时被采用。也就是说可以控制立刻更新预分频器值还是下个更新事件再更新预分频器值。
自动重装载寄存器
自动装载寄存器 (TIMx_ARR),自动重装载寄存器 ARR 是一个 16位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
CNT计数器CK_CNT
这个计数器可 以向上计数、向下计数或者向上向下双向计数。
向上计数:计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始 计数并且产生一个计数器溢出事件。
向下计数:计 数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动 装入的值重新开始并且产生一个计数器向下溢出事件。
向上向下双向计数(中央对齐模式):计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)−1,产生一个计数器 溢出事件,然后向下计数到1并且产生一个计数器下溢事件;然后再从0开始重新计数。
定时时间
定时时间是由时钟、PSC预分频器和自动重装载寄存器 ARR决定的。
计数器溢出频率:CK_CNT_OV = CK_PSC / (PSC + 1) / (ARR + 1)
如果要定时1s则应设置1=72M/7200/10000
PSC=7200-1
ARR=10000-1
可以理解为,72Mhz时钟经7200分频变为10000hz时钟,再计数10000次刚好就是1s。
定时器定时中断
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
//开启时钟,TM2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//选择时基单元的时钟源(默认内部时钟)
TIM_InternalClockConfig(TIM2);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//滤波分频,不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数器模式,向上计数
//定时频率=72M/(PSC+1)/(ARR+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_ClearFlag(TIM2,TIM_IT_Update);
//开启TIM2更新中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//NVIC中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_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;//抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级为1
NVIC_Init(&NVIC_InitStructure);//配置NVIC
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//判断是否是TIM2的更新事件触发的中断
{
TIM_ClearFlag(TIM2,TIM_IT_Update);//清除更新中断标志位
}
}
定时器外部时钟
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
//开启时钟,TM2和GPIOA
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//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);
//外部时钟配置,TIM2,不分频,不反向(高低电平有效不反向),不滤波
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x00);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//滤波分频,不分频
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//计数器模式,向上计数
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
//定时频率=72M/(PSC+1)/(ARR+1)
//自动重装值ARR
TIM_TimeBaseInitStructure.TIM_Period = 10-1;
//预分频PSC
TIM_TimeBaseInitStructure.TIM_Prescaler = 1-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//由于复位后自动更新中断,这里清除一下更新中断标志位
TIM_ClearFlag(TIM2,TIM_IT_Update);
//使能更新中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//NVIC中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_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;//抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级为1
NVIC_Init(&NVIC_InitStructure);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2);//返回定时器TIM2的CNT(计数值)
}