定时器
-
TIM(Timer)定时器
-
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
-
16位计数器、预分频、自动重装寄存器的时基单元,在72M计数时钟下可以实现最大59.65s的定时
-
不仅具备基本的定时器中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
-
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
-
对72MHz计72个数就是1MHz,也就是1us的时间,计72000个数,那就是1KHz也就是1ms的时间
-
59.65s =65536 X 65536X 1/72M/(中断频率倒数),
-
STM32的定时器支持级联的模式:一个定时器的输出当做另一个定时器的输入最大定时时间就是59.65s X 65536 X 65536
- 预分频器(PSC):对输入的基准频率提前进行一个分频的操作
- 实际分频系数 = 预分频器的值 + 1,最大可以写65535即65536分频
- 计数器(CNT):也是16位,值可以从0~65535,当计数器的值自增(自减)到目标值时,产生中断,完成定时
- 自动重装寄存器():也是16位当计数值等于自动重装值时,就是计时的时间到了,就会产生一个中断信号,并且清零计数器,计数器自动开始下一次的计数计时,计数值等于自动重装值的中断一般叫做“更新中断”,此更新中断就会通往NVIC,再配置好NVIC的定时器通道,定时器上的更新中断就会得到CPU的响应了,对应的事件叫做“更新事件”,更新事件不会触发中断,但可以触发内部其他电路的工作
- 从基准时钟,到预分频器,再到计数器,计数器自增,同时不断地与自动重装寄存器进行比较,计数器和自动重装寄存器的值相等时,即计时时间到,这时会产生一个更新中断和更新事件,CPU响应更新中断,就完成了定时中断的任务了。
主从触发模式
使用定时器的主模式,可以把定时器的更新事件映射到触发输出TRGO(Trigger Out)的位置,TRGO直接接到DAC的触发转换引脚上,这样定时器的更新就不需要再通过中断来触发DAC转换了
缓冲寄存器:某个时刻把预分频器由0改成了1,当计数计到一半的时候改变了分频值,这个变化不会立即生效,而是会等到本次计数周期结束时,产生了了更新事件,预分频器的值才会被传递到缓冲寄存器里面去,才会生效。
举个例子来说,如果我们想改变ARR寄存器中的值,但是当前的定时还没有结束,在这时如果未设置影子寄存器,那么设定的值会立即生效。而如果设置了影子寄存器,那么新的值会在当前计数周期结束之后生效。
计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)
计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)
开启定时器步骤
- 第一步,RCC开启时钟
- 第二步,选择时基单元的时钟源
- 第三步,配置时基单元
- 第四步,配置输出中断控制,允许更新中断输出到NVIC
- 第五步,配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
- 第六步,运行控制
- 第七步,使能计数器
定时器常用的库函数
恢复缺省配置函数
void TIM_DeInit(TIM_TypeDef* TIMx);
时基单元初始化函数
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
把结构体变量赋一个默认值函数
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
使能计数器函数
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
使能中断输出信号函数
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
选择内部时钟函数
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
选择ITRx其他定时器的时钟函数
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
选择TIx捕获通道的时钟函数
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);
参数3:输入的极性 参数4:滤波器
选择ETR通过外部时钟模式1输入的时钟函数
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
参数2:预分频器 参数3:输入的极性 参数4:滤波器
选择ETR通过外部时钟模式2输入的时钟函数
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
单独配置ETR引脚的预分频器、极性、滤波器这些参数的函数
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);
参数3:写入的模式,在更新事件生效,或者在写入后,手动产生一个更新事件,让这个值立刻生效
改变计数器的计数模式函数
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);
自动重装器预装功能配置函数
TIM_ARRPreloadConfig设置为DISABLE 和ENABLE的问题,他的作用只是允许或禁止在定时器工作时向ARR的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值。
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
给计数器写入一个值函数
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
给自动重装器写入一个值函数
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
获取当前计数器的值函数
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
获取当前预分频器的值函数
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);
使用跨文件的变量: extern声明变量,告诉编译器,有Num这个变量在别的文件中定义了,在此文件中也可以使用
程序示例:
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2时钟
TIM_InternalClockConfig(TIM2);//使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义时基单元结构体
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置向上计数
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_FLAG_Update);//清除更新标志位
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//中断输出
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
NVIC_InitTypeDef NVIC_InitStructure;//NVIC结构体
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_Cmd(TIM2, ENABLE);//开启定时器
}
/*
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//判断是否中断溢出
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除中断标志位
}
}
*/
评论(0)
您还未登录,请登录后发表或查看评论