[蓝桥杯嵌入式有手就行]10_TIM(上)


前言

一、内部结构

1、分类

2、框图

二、定时器输出的原理

1、计数(基本定时器)

1、过程

2、举例

2、PWM波输出

1、名词解释

2、举例

3、输出比较

三、代码示例(基本定时器)

1、cubemx配置

2、上代码( 水灯)

四、代码示例(高级定时器)

1、cubemx配置

2、上代码

五、问题

1、注意点

1、PSC和ARR寄存器的值为什么最后一位常常是9

2、既然周期是由PSC和ARR寄存器共同决定的,我们能不能调节PSC寄存器来改变周期

总结

前言

注:本系列基于2023年蓝桥杯实战情况就行编写,所有软件均采用2023年赛点资源包

其实定时器本质上应该属于一种特殊的计数器,其本质是按照特定的频率和计数方式进行计数,当计数值达到预设值的时候就会产生一个事件触发中断或者DMA请求。

因为定时器部分内容较多,因此本章节只讨论输出部分。因方波也是一种特殊的pwm波,因此下文中主要以pwm波为主。


一、内部结构

1、分类

在这里插入图片描述

在这里插入图片描述

这边需要注意只有定时器2是32位的。

关于计数方式,可以分为中心计数,向上计数和向下计数三种。在手册里已经给出了示意图。

在这里插入图片描述

注意:图中的RCR寄存器(重复次数寄存器)是高级定时器才有的,对于其他类型的定时器,我们认为其就是这种情况


2、框图

在这里插入图片描述

看不清的话可以去参考手册28.3.1节查询。图中粉色荧光 笔部分为输入捕获,放入下一节中讲述。

在这里插入图片描述

这个是通用定时器

在这里插入图片描述

这个是基本定时器。其中CK_CNT=CK_PSC/(PSC[15:0]+1)。

注意:PSC和ARR寄存器的框下面有阴影,表示存在影子寄存器,只有当更新事件发生的时候,重装载寄存器的值才会传递到影子寄存器,影子寄存器才是真正起作用的寄存器


其实高级定时器-刹车部分=通用定时器,通用定时器-中间荧光笔标记的部分=基本定时器。因此本文直接用高级定时器做分析。


二、定时器输出的原理

1、计数(基本定时器)

1、过程

我们看上面基本定时器的结构图,可以发现来自APB总线的时钟信号进入了定时器的触发控制器,每来一个时钟信号,计数器加一,然后计数器的值来到了下方的预分频器,输出分频后的计数值进入 CNT counter即计数器。而计数器上方是自动重装载寄存器,当CNT内的值与ARR内的值相等的时候,就会触发更新事件,停止计数,并清空CNT。以此往复,便实现了定时的功能。


2、举例

这里以定时器6定时1s举例。

我一般使用100M主频,因此APB1总线上的频率为100Mhz。查阅手册得知(不会的去看第三节中的时钟树),定时器6挂载在APB1总线上,因此输入定时器的时钟信号也就为100M。

通过手册我们可以知道,定时器6是一个16位的向上计数的定时器,一秒将产生100M个事件,也就是ARR寄存器至少要27位才能装下,但是显然不可能做到。因此,我们需要预分频,预分频寄存器也是16位的。也就是说,我最多可以计2^32个数了,满足要求了。那么接下来对于PSC和ARR两个寄存器的值我们就需要好好考虑一下了(尤其是在资源受限的条件下,我们不可能一个定时器只用一个引脚)。


PSC*ARR      计数间隔

65534*1525    655us

39999*2499   400us

19999*4999    200us

9999*9999     100us

4999*1999     9 50us

2499*399     99 25us

1525*6553    4 15us

至于为什么PSC和ARR不是整数,请看第一个问题

通过计算,我们可以发现在当前主频下,我们计数间隔(产生事件的间隔)在15~655us间,我们最长只能计时42.9s。但是这个时候的间隔为655us,将导致之后调用这个定时器的时候很难实现精确的定时,甚至整个1s也是有偏差的。相对来说上图标注的两个值比较合理,也方便后期计算时间。


2、PWM波输出

在上面的基础上,我们需要引入两个概念,分别是占空比和周期。


1、名词解释

周期:PWM波可以认为是由一段又一段重复的波形组成的,而每段波持续的时间就是周期,上一节中我们实现的1s定时,周期为1s。也就是通过改变ARR寄存器的值调节周期(一般情况下我们程序运行过程中修改频率是一件很危险的事,当然也有例外,看下方问题区)。

务必注意:一个定时器共用一个PSC和ARR寄存器,也就是各个通道的计数的时间间隔是一样的,我们只能通过CCR寄存器来调整各个通道的输出周期

占空比:在一个周期内有效电平(一般我们认为高电平有效)持续时间占总周期的比值。


2、举例

在程序中,假设我们需要输出一个1hz高电平有效30%占空比的PWM波。我们通过预分频,将计数频率降低到10000hz,此时我们数10000个数就是1s。而当计数器数到3000的时候,就会翻转电平,这样我们就获得了想要的PWM波。


根据傅里叶变换,方波是由基波和无数个奇次谐波组成。而方波正是一种特殊的PWM波,也就是说,理论上我们产生PWM波后,就可以通过多个PWM波来合成我们所需要的任意的波形了。


3、输出比较

输出比较一共可以分为5种模式,区别如下


模式                     说明

冻结模式            作为普通定时器使用

比较输出模式1    匹配时输出有效/无效电平模式

比较输出模式2    也叫电平翻转模式,方波输出

强制输出模式      强制为无效/有效电平模式

PWM模式          PWM1和PWM2

关于PWM1和PWM2的区别

一般我们都使用PWM1模式,简单的说就是当cnt回到初始值后,在到达ccr设定的值之前为有效电平的就是PWM1,否则就是PWM2。


三、代码示例(基本定时器)

1、cubemx配置

在这里插入图片描述

在这里插入图片描述


2、上代码(流水灯)

记得在开始的时候开启定时器6的中断 。


void HAL_Tim_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  static uint16_t counter = 0;
  static uint16_t led = 0x0001, i = 0, dir = 0;
  if (++counter == 100)
  {
    counter = 0;
    GPIOD->BSRR |= 0x0004;          // PD2置1
    GPIOC->ODR = ~(led << (8 + i)); // pc8~15输出反相的led
    __nop();                        // delay一个cpu时钟周期
    GPIOD->BRR |= 0x0004;           // PD2置0
    
    if (dir == 0)
    {
      if (++i == 7)
        dir = 1;
    }
    else
    {
      if (--i == 0)
        dir = 0;
    }
  }
  HAL_TIM_Base_Start_IT(&htim6);
}



四、代码示例(高级定时器)

1、cubemx配置

在这里插入图片描述

在这里插入图片描述


2、上代码

按需组合使用下面几行代码就可以


 

 TIM3->PSC=99;//AHB clock prescaler/100
  TIM3->ARR=999;//auto reload register
  TIM3->CCR2=500;//compare capture register,duty=CCR2/ARR=50%
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);//start pwm
  HAL_Delay(1000)
  HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2);//stop pwm

五、问题

1、注意点

1、PSC和ARR寄存器的值为什么最后一位常常是9

务必注意这个寄存器值为0时,实际是1。也就是如果我们需要100分频,PSC的值应该设置成100-1即99。ARR同理。


2、既然周期是由PSC和ARR寄存器共同决定的,我们能不能调节PSC寄存器来改变周期

一般情况下,我们习惯调整ARR寄存器的值来改变周期,因为相对计算简单,就像上面100M主频,PSC=10000的情况下,每次CNT+1需要经过0.1ms,我想要1hz,只需要ARR=10000,想要10hz,只需要ARR=1000。

但是,就是14届比赛的时候,碰到一个很神奇的东西。题目要求pwm波以不超过200hz的变化幅度在规定时间内变换至指定周期,占空比还不能变。这个时候你会发现占空比是CCR和ARR的比值,ARR变了,CCR的值就要重算,虽然就是多一行程序,但是实际上示波器测量发现占空比还是有波动的。这个时候,我们调整PSC相对来说就容易的多了。

那么怎么选择呢,很简单,记住一句话改周期就改ARR,改频率就改PSC


总结

定时器部分我个人偏向于寄存器编程,因为只需要记住9个字母(PSC、ARR、CCR)就可以完成大部分功能的编写,比又臭又长的hal库函数好记多了,重点是keil调试的时候是可以直接查看这三个寄存器的值的,这极大的方便了找bug 。



请使用浏览器的分享功能分享到微信等