STM32定时器中断实现定时功能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、定时器介绍
  • 定时器类型
  • 基本定时器
  • 通用定时器
  • 高级定时器
  • 时序图介绍
  • 二,配置定时器
  • 定时器库函数(本节)
  • 配置过程

  • 前言

    本节先只讲解定时器的定时中断,内外中断源选择。

    一、定时器介绍

    TIM(Timer)定时器
    定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
    16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时。
    不仅具备基本的定时中断功能,而且还包含内外时钟源选择输入捕获、输出比较、编码器接口、主从触发模式等多种功能。
    根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型。

    定时器类型


    注:开启时钟时注意,高级定时器连接APB2总线通用与基本定时器连接APB1总线

    基本定时器


    16位计数器、预分频器、自动重装寄存器构成了最基本的计时计数电路,叫做时基单元

    基本定时器只能选择内部时钟。
    预分频器写0,输入频率=输出频率=72MHZ;写1,二分频 ,输出频率=输出频率/2=32MHZ;
    写n,输出频率=输入频率/(n+1)。(预分频器是16位的,故写入值不得大于65535)

    计数器:16位寄存器;每来一个上升沿,计数器的值加1,自增到目标值时产生中断。

    自动重装寄存器:16位寄存器;写入值为固定值,是我们的目标值,当计数值等于自动重装值时,产生中断信号,清零计数器。

    上箭头代表会产生中断信号。
    下箭头代表会产生“更新事件”。(不会触发中断,但会触发其他内部电路的工作)。

    工作流程:时钟信号从基准时钟,到预分频器,再到计数器。计数器计数自增,并不断的与自动重装值进行比较,相等时,产生一个更新中断,更新事件,CPU响应定时中断,完成定时中断的任务。

    主模式触发DAC:将定时器的更新事件,映射到TRGO的位置,TRGO接到DAC的触发引脚上,TRGO会直接去触发DAC,实现了硬件自动化。

    通用定时器


    拥有基本定时器的功能

    通用定时器拥向上自增,向下自减,中央对齐。(基本定时器,只有向上模式)
    内外时钟源选择:基本定时器只能选择内部时钟源(系统频率72MHz),通用定时器还可以选择外部时钟,外部时钟模式2(ETR外部时钟),外部时钟模式1(ERT外部时钟、ITRx其他定时器-可定时器级联、TIx捕获通道)。
    外部时钟使用时注意外部时钟的引脚,STM32最小系统板的TIM的外部时钟接在PA0引脚上。(查看引脚定义表)

    高级定时器


    拥有通用定时器的功能
    重复次数计数器:可以实现每隔几个周期才发生一次更新事件和更新中断,相当于对更新的输出信号作了一次分频。

    定时中断的基本结构

    在定时中断中,ETR的外部中断1与外部中断2无区别。
    中断输出控制:定时器中含有多种中断(如定时中断,输入捕获,输出比较),需要中断输出控制进行判断是否需要。

    时序图介绍

    我们通过时序图,来更深入了解一下定时器定时中断时的工作原理。

    CK_PSC:预分频器的输入时钟。
    CNT_EN:计数器使能。
    CK_CNT定时器时钟:CK_PSC/(PSC+1)。

    CNT_EN置1后,计数器使能,计数器开始工作,预分频器的系数为1(写0,系数为1;写,系数为2),CK_CNT前半段频率=CK_PSC(若内部时钟作为时钟源的话,CK_CNT=72MHZ)。
    之后,预分频器系数为2,此时预分频缓冲器保留之前的系数,定时器时钟CK_CNT频率暂未改变,当计数器值自增到目标值时,产生一个更新事件,并且在下一个时钟来临时清零计数器;当产生更新事件后,预分频缓冲器的值为1,预分频计数器按照二分频的工作模式工作,CK_PSC不变,CK_CNT周期,计数周期为原来的两倍

    缓存器的作用:值的变化与计数周期同步发生,在控制寄存器的值突然改变时,定时仍按原来的方式工作一个计数周期后,再改变,避免更改数值造成错误。


    可知 更新中断后,需要再中断函数内手动清零中断标志位。

    二,配置定时器

    第一步:配置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);//使能计数器CNT;对应操作上图运行控制位。
    void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);//使能中断输出信号,ITConfing即使能外设的中断输出;对应操作上图中断输出控制。
    
    //时钟源选择
    void TIM_InternalClockConfig(TIM_TypeDef* TIMx);//内部时钟
    void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择ITRx其他定时器的时钟
    void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
                                    uint16_t TIM_ICPolarity, uint16_t ICFilter);//选择TIX捕获通道的时钟。
    void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                                 uint16_t ExtTRGFilter);//选择ETR通过外部时钟模式1,输入的时钟。
    void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                                 uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);//选择ETR通过外部时钟模式2,输入的时钟
    void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                       uint16_t ExtTRGFilter);//单独用来配置ETR引脚的极性,滤波器,预分频器等参数。
    
    
    void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//单独修改预分频值;参数1:定时器x;参数2:写入的预分频器的值;参数三:预分频器的模式(对应上文,预分频器的缓存器)
    void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//修改计数器的模式
    void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//修改预装值
    
    uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//获得计数器的值
    uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);//获得预分频器的值
    
    //获取或清除标志位(上节介绍过EXTI,类似)
    FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
    void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
    ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
    void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
    

    配置过程

    第一步:配置RCC

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2的时钟,TIM2连接APB1总线
    

    第二步:选择定时器时钟源

    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_TimeBaseInit,配置TIM2的时基单元	
    

    定时器中滤波器工作原理:在固定的频率f下,进行采样,如果n个采样点都输出相同的电平,即信号稳定;相反,则不稳定,这时保持上次输出,或低电平。时钟的滤波频率由结构体参数TIM_ClockDivisio配置的。

    第四步:配置中断输出控制

    	TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除定时器更新标志位
    									//TIM_TimeBaseInit函数末尾,手动产生了更新事件
    									//若不清除此标志位,则开启中断后,会立刻进入一次中断
    									//如果不介意此问题,则不清除此标志位也可
    	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断									
    

    配置中断输出控制为更新中断

    第五步:配置NVIC

    	/*NVIC中断分组*/
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
    																//即抢占优先级范围:0~3,响应优先级范围:0~3
    																//此分组配置在整个工程中仅需调用一次
    																//若有多个中断,可以把此代码放在main函数内,while循环之前
    																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
    	
    	/*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,定时器开始运行
    

    中断函数
    在启动文件中查找中断函数

    void TIM2_IRQHandler(void)
    {
    	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//检验标志位
    	{
    		//中断函数执行内容
    		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除标志位
    	}
    }
    

    作者:啊?啊?啊?

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32定时器中断实现定时功能

    发表回复