当前位置:   article > 正文

STM32--定时器_stm32定时器相关的函数,主要用到以下几个:(1) ()函数,作用是初始化定时器自动

stm32定时器相关的函数,主要用到以下几个:(1) ()函数,作用是初始化定时器自动

定时器简介

        定时器就是计数器,简称TIM,可以对输入时钟进行计数,并在计数值达到设定值时触发中断或触发其他外设ccc5399ce9c2493a99a0e4a27e7d6241.png

        根据复杂度和应用场景,定时器分为三种,它们的功能从高级到低级向下兼容。高级定时器连接的是性能更高的APB2总线(最大72Mhz),而APB1最大36Mhz。

        尽管如此,三类定时器的内部时钟来源都能达到72Mhz,原因见时钟树。

RCC时钟树

1、时钟的分配

25eac03a22424669b6307610ef54a0e0.png

        

        RCC时钟树:在STM32中用来产生和配置时钟,并且把配置好的各个外设都发射到各个外设的系统。 时钟是所有外设运行的基础,所以时钟最先配置的东西。在程序执行时,在执行主程序之前还会执行一个SystemInit函数。

2、时钟的产生
  有4个振荡源,分别是内部的8MHz高速RC振荡器、外部的4-16MHz高速石英振荡器(一般都外接8MHz)、外部的32.768kHz低速晶振振荡器(一般给RTC提供时钟)、内部的40kHz低速RC振荡器(给看门狗WDG提供时钟)。

        外部的石英振荡器比内部的RC振荡器更加稳定。如果系统非常简单,且不需要过于精确的时钟,就可以使用内部的RC振荡器,这样可以省下外部的晶振电路。
  在SystemInit函数中是这样来配置时钟的:首先会启动内部的8MHz高速RC振荡器产生时钟,选择该时钟为系统时钟,暂时以8MHz的内部时钟运行;然后再启动外部的8MHz高速石英振荡器产生时钟,进入PLLMUL锁相环进行倍频,8MHz倍频9倍,得到72MHz,待锁相环输出稳定后,选择锁相环输出为系统时钟。这样就把系统时钟从8MHz切换为了72MHz。如下图所示的电路

e18e5b38f2df4cc596da8156399fb150.png


  图中的CSS称为时钟安全系统,它同样负责切换时钟。CSS可以检测时钟的运行状态,一旦外部时钟失效,它就会自动把外部时钟切换为内部时钟,从而保证程序可以正常运行,不会卡死造成事故。另外在高级定时器的刹车输入功能中,CSS同样负责检测当外部时钟失效时,立即切断输出控制引脚,切断电机输出,防止发生意外。

        据此可以推测:如果外部晶振出问题,可能会出现程序时钟慢大概10倍的现象。如果外部时钟的硬件电路有问题(晶振短路或连接错误等),系统的时钟就无法切换到72MHz,会保持内部的8MHz运行。


基本定时器

时基单元

5b762364f203413ba49752b6f2d9be23.png

        时基单元主要包含3个16位的PSC预分频器、CNT计数器、ARR自动重装载寄存器。

        工作过程为:

  1. 时钟来源于内部时钟APB1,先经过PSC预分频(实际分频系数PSC+1)
  2. 再传给CNT进行向上计数,达到设定值溢出(实际为ARR+1)
  3. 计数值回到0,然后产生计数器溢出事件,可以选择如下两种之一:
  • Update Interrupt 更新中断(中断通往NVIC,配置好通道就能让CPU响应)
  • Update 更新事件 (它不触发中断,而是触发其他外设,像基本定时器就是TRGO触发DAC)

        因此,在时基单元的控制下,最长可延时Tmax=65536*65536/72M≈59.65s

    影子寄存器

        这里特别的地方就是,PSC和ARR两个寄存器框带上了阴影,因为它们都是由“影子寄存器”真正操控生效。

  • 对于PSC,如果在计数过程想修改分频系数,不是立即生效,虽然控制寄存器中的值已经修改了,但是得等到这轮计数溢出更新事件后再生效,即PSC修改的值先进入到了影子寄存器中进行缓冲等待;
  • 对于ARR,影子寄存器的功能同理,不过stm32还专门设置了自动重装载预加载使能位APRE(详见手册),简单来说就是,可以通过设置该位来决定是否预加载,预加载就是缓冲的意思,如果设置不预加载,即在计数过程中修改ARR的值会立即生效。

45b35387cfa64b458fd3e12cfff13c67.png

f81d979da65145ceb92a2e4be2379a33.png

520eb745a2a343449fd0f624d7c4b77a.png

通用定时器

        c72a946149a04dc1848678a09cb820bf.png

时基单元

        通用定时器的时基单元和基本定时器的区别在于:计数方式上多了两种。

  • 向下计数模式:从重装值ARR向下自减到0,然后回到重装值产生计数器溢出事件
  • 中央对齐模式:实际上就是先向上计数到ARR-1,产生一个计数器溢出事件;然后向下计数到1,产生一个计数器溢出事件;最后从0开始重新计数

        实际上简单且用的最多的还是向上计数,掌握这个就好

时钟来源

9507eb067e1f4df19be8d62b395a0fee.png

输入捕获、输出比较

        40752c4f5c4744779b7b2aea43c4867c.png

        输入捕获和输出比较都有4个通道(占据4个GPIO口的复用功能)。输入捕获可用于测量输入的方波频率,输出比较可用于PWM波的产生和占空比调节,但是!!同一个定时器的通道不能同时使用这两个功能,因为它们的寄存器是共用的。

高级定时器

74aa8d8d284e4929b9a105434d6475b5.png         高级定时器大部分结构与通用定时器相同,拓展的地方在图上都框了出来。

  • 重复次数计数器:在计数溢出的输出地方,增加了一个重复次数计数器,它的作用是:可以实现每隔几个计数周期,才发生一次更新事件和中断。相当于对输出又作了一次分频。(除了前面时钟来源提到的定时器之间可以级联以外,这里其实又是一种“级联”,意味着可定时的时间还可以延长)。
  • 死区生成和互补输出:这主要是为了驱动三相无刷电机设计的。三相无刷电机的驱动电路需要三个桥臂,每个桥臂需要2个大功率开关管来控制,总共需要6个。所以输出的PWM引脚的前三路变为了互补的输出引脚。同时,为了防止上下桥臂互补输出时,在开关切换的瞬间,由于器件的不理想,该关断的未关断,造成短暂的直通现象,故添加了死区生成电路。在开关切换的瞬间,产生一定时长的死区,让桥臂的上下管全部关断,防止出现直通现象。
  • 刹车输入:刹车输入的主要作用是给电机驱动提供安全保障。如果外部引脚BKIN(Break In)产生了刹车信号,或者内部时钟失效,产生了故障,控制电路就会自动切断电机的输出,防止意外的发生。
      

    定时中断基本结构

90a3fe9fe079414f86e64167b21fa321.png

        定时器中最核心的部分是时基单元,图中“运行控制”就是控制寄存器中的一些位,比如用来启动或停止定时器,配置计数方式等,操作这些寄存器就能控制时基单元的运行了。再一个就是计时溢出产生的溢出事件可以选择中断,这里多了“中断输出控制”,是因为在定时器的结构中,不仅计数溢出可以申请中断,还有像时钟来源选择其他时钟触发输入时,输入捕获和输出比较匹配时都可以,所以配置中断需要明确需要的是哪个去触发中断。

定时器配置

  1. 配置时钟 外设时钟使能、时钟来源(内部APB1时钟默认开启可不设置,其他来源须设置)
  2. 配置时基单元(最后清除一下中断标志位)
  3. 配置中断来源、NVIC
  4. 使能定时器   一次完整计时时间 Tout = (ARR+1)*(PSC+1)/72M 
  5. 写中断函数
  1. #include "stm32f10x.h"
  2. #include "tim.h"
  3. uint32_t num = 0;
  4. void Tim_Config(void)
  5. {
  6. TIM_TimeBaseInitTypeDef tim_configstruct;
  7. NVIC_InitTypeDef nvic_structinit;
  8. //配置时钟
  9. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //外设时钟使能
  10. TIM_InternalClockConfig(TIM2); //选择内部时钟源
  11. //配置时基单元
  12. tim_configstruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
  13. tim_configstruct.TIM_ClockDivision = TIM_CKD_DIV1; //外部引脚输入时钟分频系数 用于采样滤波
  14. tim_configstruct.TIM_Period = 10000-1; //1s
  15. tim_configstruct.TIM_Prescaler = 7200-1;
  16. tim_configstruct.TIM_RepetitionCounter = 0; //重复次数计数器是高级定时器才有的 这里不用就给0
  17. TIM_TimeBaseInit(TIM2,&tim_configstruct); //初始化定时器
  18. //初始化后相当于给PSC、ARR写入新的值,原本是有寄存器缓冲的
  19. //但为了能立刻生效开始计数,初始化后默认置位了标志位进入了中断,所以需要手动清除
  20. TIM_ClearFlag(TIM2, TIM_IT_Update);
  21. //配置NVIC
  22. TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //设置中断来源 是由计数溢出产生
  23. nvic_structinit.NVIC_IRQChannel = TIM2_IRQn; //设置中断通道
  24. nvic_structinit.NVIC_IRQChannelCmd = ENABLE; //中断通道使能
  25. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  26. nvic_structinit.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
  27. nvic_structinit.NVIC_IRQChannelSubPriority = 1; //响应优先级
  28. NVIC_Init(&nvic_structinit);
  29. TIM_Cmd(TIM2,ENABLE); //使能定时器 开始计数
  30. }
  31. void TIM2_IRQHandler(void) //配置中断函数
  32. {
  33. if( TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
  34. {
  35. num++;
  36. TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志位
  37. }
  38. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/942218
推荐阅读
相关标签
  

闽ICP备14008679号