六、定时器中断

一、定时器基本定时功能

1.定时器就是一个计数器,当这个计数器的输入是一个准确可靠的基准时钟的时候,那它在对这个基准时钟进行计数的过程,实际上就是计时的过程。

比如在STM32中,定时器的基准时钟一般都是主频72MHZ,如果我对72MHZ计72个数,那就是1MHz也就是1us的时间。

T(时钟周期)=1/fosc(频率) 计时时间=n(计数次数)*T,1s/72M*72=1us

72MHZ的就是1秒计72M个数,可以理解为对72个数计数1M次,计72个数的频率就是1MHz,用时1us

2.时基单元里面的计数器、预分频器、自动重装寄存器都是16位的,2的16次方是65536.

最大计数代表的计数时间=(T=(分频数MAX/72M))*最大计数数MAX))

每秒计数次数(72M/65536) / 触发中断的计数值(65536) = 每秒产生的中断数,取倒数 -> 中断周期/间隔时间

因为同一个芯片一般都有很多个定时器,所以TM后面会跟一个数字。APB2总线性能更高。

高级定时器多出的功能,主要是为了三相无刷电机的驱动设计的。

不同的型号,定时器的数量是不同的。在操作这个外设之前,一定要看一下他是不是有这个外设。

1.基本定时器

内部时钟的来源是RCC_TIMXCLK,这里的频率值一般都是系统的主频72MHz,所以通向时基单元的计数基准频率就是72M。

计数时钟每来一个上升沿,计数器的值就加1。当计数值等于自动重装值时,也就是计时时间到了,那它就会产生一个中断信号,并且清零计数器,计数器自动开始下一次的计数计时,在这里图上画的一个向上的折线箭头,就代表这里会产生中断信号。像这种计数值等于自动重装值产生的中断,我们一般把它叫做“更新中断”。

这个更新中断之后就会通往NVIC,我们再配置好NMIC的定时器通道,那定时器的更新中断就能够得到CPU的响应了。

这里向下的箭头,代表的是会产生一个事件,这里对应的事件就叫做“更新事件”,更新事件不会触发中断,但可以触发内部其他电路的工作。

以上这些,就是定时器定时中断的全部流程。

总结:

从基准时钟,到预分频器,再到计数器,计数器计数自增,同时不断地与自动重装寄存器进行比较。它俩值相等时,即计时时间到,这时会产生一个更新中断和更新事件,CPU响应更新中断,就完成了我们定时中断的任务了。

数模转换器(Digital to Analog Converter):把更新事件通过主模式映射到TRGO,然后TRGO就会直接去触发DAC了。整个过程不需要软件的参与,实现了硬件的自动化,这就是主模式的作用。

2.通用定时器

基本定时器仅支持向上计数模式,通用定时器和高级定时器还支持向下计数模式和中央对齐模式

基本定时器时钟源只可以选择内部的72MHZ时钟,通用定时器还可以选择外部时钟:

1.TIMx_ETR(external)引脚,外部时钟模式2;

2.TRGI(trigger In),主要用作触发输入,可以触发定时器的从模式。当这个TRGI当做外部时钟来使用的时候,这一路就叫做外部时钟模式1。ITRO到ITR3分别来自其他4个定时器的TRGO输出。

通过这一路我们就可以实现定时器级联的功能,比如我可以先初始化TIM3,然后使用主模式把它的更新事件映射到TRGO上。接着再初始化TIM2,这里选择ITR2,对应的就是TIM3的TRGO。然后后面再选择时钟为外部时钟模式1,这样TM3的更新事件就可以驱动TM2的时基单元,也就实现了定时器的级联。

这里还可以选择TI1F_ED,连接的是这里输入捕获单元的CH1引脚。也就是从CH1引脚获得时钟,这里后缀加一个ED(Edge)就是边沿的意思,也就是通过这一路输入的时钟,上升沿和下降沿均有效。

最后,这个时钟还能通过TI1FP1和TI2FP2获得。其中TI1FP1连接到了CH1引脚的时钟,TI2FP2连接到了CH2引脚的时钟。

总结一下就是,外部时钟模式1的输入可以是ETR引脚、其他定时器、CH1引脚的边沿、CH1引脚、CH2引脚。一般情况下外部时钟通过ETR引脚就可以了。

下面设置这么复杂的输入,不仅仅是为了扩大时钟输入的范围,更多的还是为了某些特殊应用场景而设计的,比如为了定时器的级联而设计的这一部分。

对于时钟输入而言,最常用的还是内部的72MHz的时钟。如果要使用外部时钟,首选ER引I脚外部时钟模式2的输入,这一路最简单最直接。

定时器的主模式输出,这部分电路可以把内部的一些事件映射到这个TRGO引脚上。比如我们刚才讲基本定时器分析的,将更新事件映射到TRGO,用于触发DAC。这里也是一样,它可以把定时器内部的一些事件映射到这里来,用于触发其它定时器、DAC或者ADC。

右边这一块是输出比较电路,总共有四个通道,分别对应CH1到CH4的引脚,可以用于输出PWM波形,驱动电机。

左边这一块是输入捕获电路,也是有四个通道,对应的也是CH1到CH4的引脚,可以用于测量输入方波的频率等。

中间这个寄存器是捕获/比较寄存器,是输入捕获和输出比较电路共用的。因为输入捕获和输出比较不能同时使用,所以这里的寄存器是共用的,引脚也是共用的

3.高级定时器

DTG(Dead Time Generate)是死区生成电路。右边一对输出引脚可以输出一对互补的PWM波,这些电路是为了驱动三相无刷电机的。

刹车输入:BKIN。

4.定时中断基本结构

PSC(prescaler)预分频器、CNT(counter)计数器、ARR(Auto Reload register)自动重装寄存器这三个寄存器构成了时基单元。

运行控制,就是控制寄存器的一些位,比如启动停止、向上或向下计数等等。我们操作这些寄存器就能控制时基单元的运行。

左边是为时基单元提供时钟的部分。

接下来右边这里,就是计时时间到,产生更新中断后的信号去向。(在这里,如果是高级定时器的话,还会多一个重复计数器。)那这里中断信号会先在状态寄存器里置一个中断标志位,这个标志位会通过中断输出控制,到NVIC申请中断。为什么会有一个中断输出控制呢,因为这个定时器模块有很多地方都要申请中断,所以这些中断都要经过中断输出控制。如果需要这个中断,那就允许,如果不需要,那就禁止。简单来说,这个中断输出控制就是一个中断输出的允许位

5.时序图

CK_PSC是预分频器的输入时钟,选内部时钟的话一般是72MHz;

CNT_EN,计数器使能,高电平计数器正常运行,低电平计数器停止;

CK_CNT计数器时钟,它既是预分频器的时钟输出,也是计数器的时钟输入;

当我在计数计到一半的时候改变了分频值,这个变化并不会立刻生效,而是会等到本次计数周期结束时,产生了更新事件,预分频寄存器的值才会被传递到缓冲寄存器里面去,才会生效。

预分频器内部实际上也是靠计数来分频的。

中断响应后,需要在中断程序中手动清零UIF。

如果想算溢出时间,那再取个倒数就行了。

如定时器最大定时事件:59.65s=1/(72MHz/65536/65536)

带一个黑色阴影的寄存器,都是有影子寄存器这样的缓冲机制的。

所以计数的这个ARR自动重装寄存器,也是有一个缓冲寄存器的,并且是否开启是可以自己设置的。

通过设置ARPE位,就可以选择是否使用预装功能。

引入这个影子寄存器的目的实际上是为了同步,就是让值的变化和更新事件同步发生,防止在运行途中更改造成错误。在下一个计数周期这个更改的36才有效。

6.RCC时钟树

这个时钟树,就是STM32中用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统。

时钟是所有外设运行的基础,所以时钟也是最先需要配置的东西。

我们之前说过,程序中主函数之前还会执行一个Systemlnit函数,这个函数就是用来配置这个时钟树的。这个配置比较麻烦,不过好在ST公司已经帮我们写好了配置这个时钟树的Svstemlnit函数。

左边的都是时钟的产生电路,右边的都是时钟的分配电路,中间的这个SYSCLK就是系统时钟72MHz。

在时钟产生电路有四个震荡源,分别是:

①内部的8MHZ高速RC振荡器;

②外部的4-16MHZ高速石英晶体振荡器,也就是晶振,一般都是接8MHz;

③外部的32.768KHz低速晶振,这个一般是给RTC提供时钟的;

④内部的40KHZ低速RC振荡器,这个可以给看门狗提供时钟。

上面这两个高速晶振,是用来提供系统时钟的。我们的AHB、APB2、APB1的时钟都是来源于这两个高速晶振。这里内部和外部都有一个8MHz的晶振,都是可以用的,只不过是外部的石英振荡器比内部的RC振荡器更加稳定,所以我们一般都用外部晶振。

CSS(Clock Security System)时钟安全系统。

P6-1  42:50 Systeminit函数配置时钟的过程、45:15

二、定时器定时中断代码

1.整体框架:

1.RCC开启时钟,在这里打开时钟后,定时器的基准时钟和整个外设的工作时钟就都会同时打开了;

2.选择时基单元的时钟源,对于定时中断,我们就选择内部时钟源;

3.配置时基单元,包括这里的预分频器、自动重装器、计数模式等等,这些参数用一个结构体就可以配置好了;

4.配置输出中断控制,允许更新中断输出到NVIC;

5.配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级;

6.运行控制,整个模块配置完成后,我们还需要使能一下计数器,要不然计数器是不会运行的。当定时器使能后,计数器就会开始计数了,当计数器更新时,触发中断。

7.最后我们再写一个定时器的中断函数,这样这个中断函数每隔一段时间就能自动执行一次了。

2.代码执行流程:

1.开启时钟

2.选择时基单元的时钟,内部时钟

定时器上电后默认就是使用内部时钟,所以写不写这行代码均可。

3.配置时基单元(初始化)

在这里我们预分频是对72M进行7200分频,得到的就是10K的计数频率,在10K的频率下,计10000个数,那不就是1s的时间嘛。

4.使能中断(更新中断)

5.NVIC优先级分组、NVIC配置(初始化)

6.启动定时器

7.写中断函数

当定时器产生更新中断时,这个函数就会自动被执行

对于定时中断而言,这个中断函数就是为别的文件服务的,所以中断函数可以放在使用它的地方(源文件)

弹幕:“中断函数可以放在任意的地方,因为函数名代表着函数的地址,在编译的时候,中断向量表里已经定义好了函数名,就是函数的入口地址,所以只要在这个工程里面,在哪都是可以跳转进去的。”

执行时会产生一次中断,所以在后面需要清除一下更新中断的标志位。

3.定时器外部中断

大体流程同前两点,需要将选择内部时钟改为选择外部时钟并加入GPIO初始化。

外部的输入信号功率很小,内部的这个上拉电阻可能会影响到这个输入信号时,就可以用一下浮空输入,防止影响外部输入的电平。

三、定时器的输出比较

1.原理

主要用来输出PWM波形,而PWM波形又是驱动电机的必要条件。

输出比较的电路:

IC:Input Capture输入捕获

CCR:捕获/比较寄存器。输入捕获和输出比较共用。

2.PWM简介

PWM的频率越快,那它等效模拟的信号就越平稳,不过同时性能开销就越大,一般来说PWM的频率都在几K到几十KHz,这个频率就已经足够快了。

占空比就是高电平时间相对于整个周期时间的比例,占空比为20%,那就是高电平占20%,低电平占80%。占空比决定了PWM等效出来的模拟电压的大小,这个等效关系一般是线性的。如:高电平5V,低电平0V,那50%占空比就等效于中间电压,就是2.5V。

分辨率:比如有的占空比只能是1%、2%、3%等等这样以1%的步距跳变,那它的分辨率就是1%。所以这个分辨率就是占空比变化的精细程度

使用PWM波形,就可以在数字系统等效输出模拟量,就能实现LED控制亮度、电机控速等功能了。

3.如何输出PWM

左边是CNT和CCR比较的结果,右边是输出比较的电路,最后通过TIM_CH1输出到GPIO引脚上。

输出模式控制器的输入是CNT和CCR的大小关系,输出是REF的高低电平,里面可以选择多种模式来更加灵活地控制REF输出,这个模式可以通过寄存器来配置。

REF仅在CNT更新时可变,CNT=CCR时REF保持则一直不会变,可用于暂停输出

PWM模式1:蓝色线是CNT的值,黄色线是ARR的值,红色线就是CRR的值。蓝色线从0开始自增,一直增到ARR,也就是99,之后清0继续自增。

CCR设置的高一些,输出的占空比就变大。这就是PWM的工作流程

这里REF,就是一个频率可调,占空比也可调的PWM波形

PWM的频率就等于计数器的更新频率。PWM频率的公式就是计数器的更新频率公式。

4.电机工作原理

可以用PWM信号来控制舵机输出轴的角度

周期的倒数就是频率(HZ)  20ms = 1/0.02s=50HZ

20ms一个周期,一秒就是50个周期,就是50Hz

这里其实是把PWM当成通信协议来使用的。把PWM当成一个通信协议,也是一个比较常见的应用。

可以用PWM来控制电机的速度。

这个直流电机是个单独的电机,里面没有驱动电路,所以要外挂一个驱动电路来控制。

电机这类器件基本上都属于大功率设备了,必须要加驱动电路才能控制。

其中PWMA引脚要接PWM信号输出端,其它两个引脚可以任意接两个普通的GPIO口。

STBY(Stand By)引|脚,这个是待机控制脚,如果接GND,芯片就不工作,处于待机状态;如果接逻辑电源VCC,芯片就正常工作。

如果PWM频率足够快,那电机就可以连续稳定地反转了,并且速度取决于PWM信号的占空比。

在这里的PWM,就是我们之前讲的,使用PWM来等效一个模拟量的功能了。


 

四、输出比较示例代码

1.PWM驱动呼吸灯

(1)初始化整体框架:

第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开;

第二步,配置时基单元,包括这前面的时钟源选择和这里的时基单元,都配置好;

第三步,配置输出比较单元,里面包括这个CCR的值、输出比较模式、极性选择、输出使能这些参数,在库函数里也是用结构体统一来配置的;

第四步,配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置。PWM和GPIO的对应关系可以参考引脚定义表;

第五步,运行控制,启动计数器,这样就能输出PWM了。

(2)初始化代码执行流程:

用结构体统一初始化。一般来说,结构体里的参数都会有一个单独的函数可以进行更改

1.配置时基单元

打开时钟——选择内部时钟——启动定时器(放在最后一步了)

2.初始化输出比较单元

在时基单元初始化下面写。输出比较单元、输出比较通道都是一个意思。不同的通道对应的GPIO口也是不一样的。由引脚定义图知,这里的PA0口对应的就是第一个输出比较通道。

用TIM-OCStructInit函数给结构体所有成员赋初始值,在再修改用到的初始值,防止切换到高级定时器时出问题。

现在的结构体是一个局部变量,如果不给它的成员赋初始值,它成员的值就是不确定的。如果结构体原本用不到的成员,现在需要用了,而这些成员你有没有赋值,那就可能会导致一些奇怪的问题。

现在我们已经把通道初始化好了,在TIM2的OC1通道上就可以输出PWM波形了。但最终,这个波形肯定要借用一下GPIO口才能输出。

注:外设引脚和GPIO引脚的复用关系和重映射的介绍

那这个TIM2的OC1通道是借了哪个GPIO口呢?我们可以打开引脚定义表,这边这一列默认复用功能,就是片上外设的端口和GPIO的连接关系

由引脚定义表可知,TIM2_CH1_ETR是在PA0这一行的,这就说明TIM2的ETR引脚和通道1的引脚都是借用了PA0这个引脚的位置的,换句话说就是TIM2的引脚复用在了PA0引脚上

所以说如果我们要使用TIM2的OC1也就是CH1通道,输出PWM,那它就只能在PA0的引脚上输出,而不能意选择引脚输出。同样,如果使用TIM2的CH2,那就只能在PA1端口输出。

这些其他的外设也是同理,比如我们要使用SPI1的MISO引脚,那就是PA6。如果要使用I2C2的SCL脚,那就是PB10。这个关系是定死的,不能任意更改。

不过,但是虽然它是定死的,STM32还是给了我们一次更改的机会的,这就是重定义,或者叫重映射。

比如如果你既要用USART2的TX引脚,又要用TIM2的CH3通道。它俩冲突了,没办法同时用,那我们就可以在这个重映射的列表里找一下。比如这里我们找到了TM2的CH3,那TM2的CH3就可以从原来的引脚换到这里的引脚,这样就避免了两个外设引脚的冲突。

如果这个重映射的列表里找不到,那外设复用的GPIO就不能挪位置。这就是重映射的功能,配置重映射是用AFIO来完成的。

这些就是外设引脚和GPIO引脚的复用关系和重映射的介绍。我们在使用外设的引脚时,需要多参考一下这个引脚定义表。

这样的话,我们就知道该配置哪个GPIO口了。

这个表不在参考手册里面,而在数据手册里面,这两个手册内容不同。我们在使用外设的引脚时,需要多参考一下这个引脚定义表。

3.初始化GPIO

只有把GPIO设置成复用推挽输出,引脚的控制权才能交给片上外设,PWM波形才能通过引脚输出。

我们习惯把GPIO的初始化代码放上面。

4.启动定时器

(3)参数设置计算

如果我现在要产生一个频率为1KHz,占空比为50%,分辨率为1%的PWM波形:

(72MHz)/(PSC+1)/(ARR+1) = 1000;

CCR/(ARR+1) = 50%;

1/(ARR+1) = 1%

解一下很容易得到(ARR+1) = 100;CCR = 50;PSC+1 = 720;

在程序里即可ARR给100-1;PSC给720-1;CRR给50。现在就是频率为1KHZ,占空比为50%的PWM波形了。

(4)呼吸灯的实现

不断更改CCR的值(即调整占空比,占空比是CCR和ARR+1共同决定的,现在ARR+1固定为100)即可实现呼吸灯。

TlM_SetCompare1,这个函数是用来单独更改通道1的CCR值的。

(5)引脚重映射

TIM2_CH1可以从PA0移到PA15上,可用AFIO实现。

那首先,要使用AFIO,就要开启AFIO的时钟。

四种重映射的方式

PA15没给加粗,因为它上电后已经默认复用为了调试端口JTDI。所以如果想让他作为普通的GPIO或者复用定时器的通道,那还需要先关闭调试端口的复用。也是用这个GPlO_PinRemapconfig函数关闭。

SWJ就是SWD和JTAG这两种调试方式。

重映射的引脚正好是调试端口,这三句都得加上:打开AFIO时钟,重映射引脚,解除调试端口。

现在有了这三句,我们定时器的通道1,就从PA0挪到PA15了。听以下面GPIO初始化这里,GPIO_Pin_0也得改成GPIO_Pin_15。为已经挪到PA15了,所以就要初始化PA15的GPIO,而不是PA0了。现在重映射的代码就写好了。

2.PWM驱动舵机

驱动舵机的关键就是输出一个这样的PWM波形。

我们现在用的是PA1口,对应TIM通道2。在代码中修改即可。

修改三个参数。

同一个定时器不同通道输出PWM的特点:对于同一个定时器的不同通道输出的PWM,因为不同通道是共用一个计数器的,所以它们的频率必须是一样的。它们的占空比,由各自的CCR决定,所以占空比可以各自设定。还有就是它们的相位,由于计数器更新,所有PWM同时跳变,所以它们的相位是同步的。

如果驱动多个舵机或者直流电机,那使用同一个定时器不同通道的PWM,就完全可以了。

3.PWM驱动直流电机

五、定时器的输入捕获

输入捕获与输出比较的区别:

输出比较,是根据CNT和CCR的大小关系来执行输出动作;输入捕获,是接收到输入信号,执行CNT锁存到CCR的动作。

频率的定义就是,1s内出现了多少个重复的周期

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值