STM32单片机 定时器TIM

分三个部分学习

第一部分,学习定时器定时基本功能,也就是定一个时间,然后让定时器每隔一个时间产生一个中断,来实现每隔一个固定时间执行一段程序的目的。比如要做个时钟、秒表、或者一些程序算法的时候,都需要定时中断的这个功能。

第二部分,学习定时器输出比较功能。输出比较功能模块最常见的用途是产生PWM波形,用于驱动电机等设备。学习用STM32输出的PWM波形来驱动舵机直流电机的例子。

第三部分,主要学习定时器输入捕获功能,学习使用输入捕获这个模块来实现测量方波频率的例子。

第四部分,学习定时器的编码接口,使用编码接口能够方便的读取正交编码器的输出波形,在编码电机测速中应用广泛。

第一部分

STM32中功能最强大、结构最复杂的外设——TIM(Timer)定时器

  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
    • 可以看出来定时器就是计数器,当这个计数器的输入是一个准确可靠的基准时钟时,那它在对这个基准时钟进行计数的过程,实际上就是计时的过程。
    • 比如在STM32中,定时器的基准时钟一般都是主频72MHz,如果我对72MHz计72个数,那就是1MHz也就是1us的时间。如果计72000个数,那就是1KHz也就是1ms的时间。
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
    • 计数器就是用来执行计数定时的一个寄存器,每来一个时钟,计数器就加1。
    • 预分频器,可以对计数器的时钟进行分频,让计数更加灵活。
    • 自动重装寄存器就是计数的目标值,就是计多少个时钟时申请中断。
    • 计数器、预分频器、自动重装寄存器构成了定时器最核心的部分,我们把这一块电路称为时基单元这些都是16位的,2^16=65536。如果预分频器设置最大,自动重装也设置最大,那么定时器的最大定时时间就是59.65s。怎么算的:72M/65536/65536,得到的是中断频率,然后取倒数为59.65s。如果嫌这个时间不够长,STM32定时器还支持级联的模式,也就是一个定时器的输出当作另一个定时器的输入,这样加一起,最大定时时间就是59.65s乘2次65536,大概是8千多年。
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能。
  • 根据复杂度和应用场景分为了高级定时器(最复杂)、通用定时器(最常用)、基本定时器(最简单)三种类型。

定时器类型

重复计数器、死区生成、互补输出、刹车输入等功能主要的是为了三相无刷电机设计的。

从上图可以看出,这三种定时器是由高级到低级向下兼容的,高级定时器拥有通用定时器的全部功能,通用定时器又有基本定时器的全部功能。

对于STM32F103C8T6芯片,它内部拥有的定时器资源是TIM1、TIM2、TIM3、TIM4,也就是一个高级定时器和三个通用定时器,没有基本定时器。注意:不同型号,定时器的数量是不同的,在操作外设之前要查询它是否有这个外设。

基本定时器结构图

预分频器、计数器、自动重装寄存器,他们构成了最基本的计数计时电路,所以这一块叫时基单元

  • 预分频器之前,连接的就是基准计数时钟的输入,最终来到控制器。由于基本定时器只能选择内部时钟,所以可以直接认为这根线直连到了输入端这里,也就是内部时钟CK_INT。内部时钟的来源是RCC_TIMxCLK,这里的频率值一般是系统的主频72MHz。
  • 预分频器,就是对输入频率提前进行分频操作,它可以对这个72MHz的计数时钟进行预分频,比如:这个寄存器写0,那就不分频,或者说是1分频,这时候输出频率=输入频率=72MHz;如果预分频器写1,那就是2分频,输出频率=输入频率/2=36MHz;如果写2,那就是3分频,输出=输入/3=24MHz,以此类推。所以预分频器的值和实际的分频系数相差了1,即实际分频系数=预分频器的值+1。这个预分频器是16位的,所以最大值可以写65535,也就是65536分频。
  • 计数器,可以对预分频后的计数时钟进行计数,计数时钟每来一个上升沿,计数器的值就+1。这个计数器也是16位的,所以里面的值可以从0一直加到65535,如果再加的话,计时器就会回到0重新开始。所以计数器的值在计时过程中会不断自增运算,当自增运行到目标值时,产生中断,那就完成了定时任务,所以现在还需要一个存储目标值的寄存器,那就是自动重装寄存器了。
  • 自动重装寄存器,也是16位的,它存的就是我们写入的计数目标,当计数器等于目标值,计时时间到,自动重装寄存器就会产生中断、清零计数器,计数器自动开启下一次的计数计时。
  • 该箭头代表这里会产生中断信号,像这种计数器等于目标值产生的中断,称为“更新中断”,这个更新中断之后就会前往NVIC,我们再配置好NVIC的定时器通道,定时器的更新中断就能得到CPU的响应。
  • 该箭头代表产生一个事件,,对应的事件称为“更新事件”,更新事件不会触发中断,但可以触发内部其他电路工作。

总结

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

主模式触发DAC的功能

能让内部的硬件在不受程序的控制下实现自动运行,实现硬件自动化,可以减轻CPU负担。

在我们使用DAC时,可能会用DAC输出一段波形,那就需要每隔一段时间来触发一次DAC,让它输出下一个电压点。

正常实现思路:先设置一个定时器产生中断,每隔一段时间在中断程序中调用代码手动触发一次DAC转换,然后DAC输出。但是这样会使主程序处于频繁被中断的状态,影响主程序的运行和其他中断的响应。

主模式

因此设计了主模式,使用主模式就可以把这个定时器的的更新事件映射到触发输出TRGO(Trigger Out)的位置,然后TRGO直接接到DAC的触发转换引脚上,这样定时器的更新就不需要通过中断来触发DAC转换,只需要把更新事件通过主模式映射到TRGO,然后TRGO就会直接去触发DAC了。

通用定时器结构图

中间部分和基本定时器结构一样,但是通用计数器的计数模式不止向上计数这一种,通用定时器和高级定时器还支持向下计数模式中央对齐模式

向下计数模式

就是从重装值开始,向下自减到 0 之后回到重装值,同时申请中断,然后继续下一轮依次循环,这就是向下计数。

中央对齐计数模式

就是从 0 开始,先向上自增计到重装值申请中断,然后再向下自减到0,再申请中断,然后继续下一轮依次循环。

总结

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

上图为内外时钟源选择和主从触发模式的结构。

内外时钟源选择,对于基本定时器而言,定时器只能选择内部时钟,也就是系统频率 72 MHz。到了通用定时器这里,时钟源不仅可以选择内部的 72 MHz时钟,还可以选择外部时钟。

具体都有哪些呢?第一个外部时钟就是来自 TIMx_ETR 引脚上的外部时钟,这个 ETR 引脚的位置可以参考一下引脚定义表

可以看到这里有TIM2_CH1_ETR,意思就是这个TIM2的CH1和ETR 都是复用在了这个位置,也就是 PA0引脚,下面还有CH2、CH3、CH4 和其他定时器的一些引脚也都可以在这里找到。

那这里我们可以在这个TIM2的 ETR 引脚,也就是 PA0 上接一个外部方波时钟,然后配置一下内部的极性选择、边沿检测和预分频器电路,再配置一下输入滤波电路,这些电路可以对外部时钟进行一定的整形,因为是外部引脚的时钟,所以难免会有些毛刺,那这些电路就可以对输入的波形进行滤波,同时也可以选择一下极性和预分频器。

滤波器:过滤掉信号抖动

参数:采样频率f、采样次数N

如何配置采样频率f:直接从内部时钟来或内部时钟加一个时钟分频来,分频多少由TIM_ClockDivision决定

工作原理:在一个固定的时钟频率f下对信号进行采样,如果连续N个采样点的电平相同,那就代表信号稳定,输出采样值,如果连续N个采样点的电平不全相同,说明信号抖动,那就保持上一次的输出或者直接输出低电平。

最后滤波后的信号兵分两路,上面一路 ETIF 进入触发控制器,紧跟着就可以选择作为时基单元的时钟了。如果你想在 ETR 外部引脚提供时钟,或者想对 ETR 时钟进行计数,把这个定时器当作计数器来用的话,那就可以配置这一路的电路啊。在 STM 32 中,这一路也叫做外部时钟模式2。

除了外部ETR引脚可以提供时钟外,下面TRGI(Trigger In)也可以提供时钟,从名字上看,是用来触发输入,它可以触发定时器的从模式

对于时钟输入而言,最常见用的还是内部的72MHz的时钟

下方电路

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

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

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

主要学习定时中断内外时钟源选择

高级定时器结构图

结构分析

申请中断的地方增加了一个重复次数计数器,有了这个计数器之后就可以实现每隔几个计数周期才发生一次更新事件和更新中断,原来的结构是每个计数周期完成后都会发生更新,现在有个计数器在这里,可以实现每隔几个周期再更新一次,这就相当于对输出的更新信号又做了一次分频,那对于高级定时器的话,我们之前计算的最大定时时间 59 秒多,在这里就还需要再乘一个65356,这就又提升了很多的定时时间了,这就是这个重复计数器的工作流程。

然后下面这里的这些就是高级定制器对输出比较模块的升级了,这些内容简单说一下,大家有个印象就行了,现在还不必深入了解。我们看一下这个 DTG 是死区生成电路,右边这里的输出引脚由原来的一个变为了两个互补的输出,可以输出一段互补的 PWM 波,这些电路是为了驱动三相无刷电机的。三相无刷电机还是比较常用的,比如四轴飞行器、电动车的后轮电钻等里面都可能是这个三相无刷电机,因为三相无刷电机的驱动电路一般需要三个桥臂,每个桥臂2个大功率开关管来控制,总共需要 6 个大功率开关管来控制,所以这里的输出 PWM 引角的前三路就变为了互补的输出,而第四路却没什么变化,因为三向电机只需要三路就行了。

为了防止互补输出的 PWM 驱动桥壁时,在开关切换的瞬间,由于器件的不理想造成短暂的直通现象,所以前面这里就加上了死区生成电路,在开关切换的瞬间产生一定时长的死区,让桥臂的上下管全都关断,防止直通现象

最后一部分就是刹车输入的功能,这个是为了给电机驱动提供安全保障的。如果外部引角 BKIN (Break In)产生了刹车信号,或者内部时钟失效产生了故障,那么控制电路就会自动切断电机的输出,防止意外的发生。这就是刹车输入的功能。

定时中断基本结构图

定时中断

内外时钟源选择

首先中间最重要的还是 PSC 预分频器、 CNT 计数器、 ARR自动重装寄送器这三个寄存器构成的时基单元。

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

左边是为时基单元提供时钟的部分,这里可以选择 RCC 提供的内部时钟,也可以选择 ETR 引角提供的外部时钟模式2。在本小节示例程序里,第一个定时器定时中断就是用的内部时钟这一路,第二个定时器外部时钟就是用的外部时钟模式 2 这一路,当然还可以选择这里的触发输入当作外部时钟,即外部时钟模式1,对应的有 ETR 外部时钟、ITRX其他定时器、TIX输入捕获通道,这些就是定时器的所有可选的时钟源了。

最后这里还有个编码器模式,这一般是编码器独用的模式,普通的时钟用不到这个。

接下来右边这里就是计时间到产生更新中断后的信号去向,在这里如果是高级定时器的话,还会多一个重复计数器。这个注意一下,不过我们暂时就不考虑了,那这里中断信号会先在状态寄存器里置一个中断标志位,这个标志位会通过中断输出控制到 NVIC 申请中断。

为什么会有一个中断输出控制呢?因为这个定时器模块有很多地方都要申请中断,比如前面这个图里不仅更新要申请中断,这里触发信号也会申请中断,还有下面的输入捕获和输出比较匹配时也会申请,所以这些中断都要经过中断输出控制。如果需要这个中断那就允许,如果不需要,那就禁止。简单来说,这个中断输出控制就是一个中断输出的允许位,如果需要某个中断,就记得允许一下。

接下来我们再来看几个时序图,研究一下时机单元运行的一些细节问题。

第一个是预分频器时序,这个图是当预分频器的参数从1变到 2 时,计数器的时序图第一行是 CK_PSC 预分频器的输入时钟,

就是这个图里的这个位置,选内部时钟的话一般是 72 MHz。然后这个时钟在不断的运行,下面这个 CNTEN 计数器使能,高电平计数器正常运行,低电平计数器停止。

再下面是 CK_CNT 计数器时钟就是这个位置,它既是域分频器的时钟输出,也是计数器的时钟输入啊。这里可以看到开始时计数器未死人,计数器始终不运行,然后死人后前半段遇分明器系数为一。计数系的时钟等于域分频器前的时钟,后半段遇分频器系数变为 2 的计数器的时钟就也变为预分明器前时钟的一半。在寄抽器时钟的驱动下面,寄抽器寄存器也跟随时钟的上层沿不断自增,在中间的这个位置 FC 之后计数值变为 0 呢。这里虽然没写,但是可以推断出 AR r 自动重装值就是FC。当技术值记得和重装值相等,并且下一个时钟来临时,计数值才清零。同时下面这里产生一个更新事件,这就是一个计数周期的工作流程啊。然后下面还有 3 行时序,这 3 行时序是什么意思呢?这里描述的其实是这个玉分屏寄存器的一种缓冲机制,也就是这个玉分屏寄存器实际上是有两格,一个是这个供我们读写用的,它并不直接决定分频系数,另外还有个缓冲计算器,或者说是隐子计算器、缓冲计容器和隐资计容器这两个说法其实是一个意思,这个缓冲计算器才是真正起作容的计算器啊。


比如我们在某个时刻把预分频计算器由 0 改成了一,如果在此时立刻改变时钟的分频系数,那么就会导致这里在一个计数周期内,前半部分和后半部分的频率不一样,这里计数计到一半儿,计数频率突然就会改变了,这虽然一般并不会有什么问题,但是 STM 三儿的定时器比较严谨,设计的这个缓冲寄存器这样当我在计数计到一半的时候改变了分频值,这个变化并不会立刻生效,而是会等到本次计数周期结束时产生的更新事件。


预分明计算器的值才会被传递到缓冲计算器里面去才会生效啊。所以在这里看到即使我在计数中途改变了预分频值,计数频率仍然会保持为原来的频率,直到本轮计数完成,在下一轮计数时,改变后的分频值才会起作用。最后,这里也是域分明器内部,实际上也是靠计数来分频的,当域分频值为 0 时,计数器就一直为0,直接输出原频率。当预分频值为一时,计数器就01010101,这样计数在回到 0 的时候输出一个脉冲。这样输出频率就是输入频率的二分频遇分频积的值和时间的分频系数之间有一个数的偏移哈。
那最下面就有这样一个公式,就是计数器计数频率 CKCNT 等于 c k PS c 除以 PSC 加一。这个好理解吧。然后继续下一页,看一下计数器时序,这个图是计数器时序图,内部始终分频因子为2,就是分频系数为 2 哈。第一行是内部始终汽车兆赫兹,第二行是时钟矢能高电频启动。第三行是计数器时钟,因为分频系数为2,所以这个频率是上面这个除2,然后计数器在这个时钟每个上升沿自增,当增到 0036 的时候发生溢出。
那记到 36 之后再来一个上层言,计数据清零,计数器溢出产生一个更新事件脉冲,另外还会置一个更新中断标志位, UIF 这个标志位只要自一了就会去申请中断,然后中断响应后需要在中断程序中手动清零,这就是计数器的工作流程。下面有个式子,计数器溢出频率 CK CNT, OV 等于 CK CNT,除以 AR r 加一,这个 AR 的值也是要加一的,把上面这个式子代进去,就是等于 CK PSC 除以 PSC 加一,再除 AR r 加一。这就是我们在计算定时间的一个式子,用七十二兆赫兹除以 PSC 加一,再除 AIR 加一,就能得到溢出频率。如果想算溢出时间,那就只需要再取个倒数就行了。
那刚才说了,域分明器为了防止计数中途更改数值造成错误,设计了缓冲计算器,这个计数器那肯定也少不了这样的设计了,我们可以看一下这个结构图,这里面像这样带一个黑色阴影的计算器都是有影子计算器这样的缓冲机制的,包括预分命器、自动重装计算器和下面的捕获比较计算器。所以计数器的这个 AR 自动重装计算器也是有一个缓冲计算器的,并且这个缓冲计算器是用还是不用,是可以自己设置的哈。
下面这两个图,第一个计数器无预装时序就是没有缓存计算器的情况。第二个有预装时序就是有缓存计算器的情况,通过设置这个 AR p e v 就可以选择是否使用预装功能。我们先看一下无预装的情况,在这里计数器正在进行自增计数,我突然更改了自动加载寄存器,就是自动重装继承加,由 FF 改成了36,那计数值的目标值就由 FF 变成了36,所以这里记到 36 之后就直接更新,开始下一轮计数。再看一下下面这个图有预装的情况,在技术的中途,我突然把技术目标由 F5 改成了36。可以看到下面有个影子计算器,这个影子计算器才是真正起作用的,它还是F5,所以现在技术的目标还是记到 F5 产生更新事件,同时要更改的 36 才被传递到影子计算器,在下一个计数周期这个更改的 36 才有效。
所以可以看出,引入这个影子计算器的目的实际上是为了同步,就是让值的变化和更新事件同步发生,防止在运行途中更改造成错误,在这个例子也可以看出,如果这里不使用硬质计容器的话, F5 改到 36 立刻生效,但此时计数值已经到了F1,已经超过 36 了, F1 只能增加,但它的目标却是36,比它还小。这样 F1 就只能一直加到 f f f f 再回到0,再加到 36 才能产生更新,这就会造成一些小问题哈。
当然如果你不介意这样的问题的话,那就不用管这些细节了,毕竟 STM 32 设计出来要考虑到各种各样的情况,所以做的比较严谨,接下来我们再看一下最后一个PPT,在这里给出来一个 RCC 时钟数的结构图,这个时钟数就是 STM 32 中用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统。
2、时钟是所有外设运行的基础,所以时钟也是最先需要配置的东西。我们之前说过,程序中主函数之前还会执行一个 system elite 函数,这个函数就是用来配置这个时钟数的,这个结构看上去挺复杂的,配置起来还是比较麻烦的。不过好在 s t 公司已经帮我们写好了配置这个时钟数的 sySTem elite 函数,那这里我们就来看一下这个时钟数。
在这个时钟树里从这里画一个界限,左边的都是时钟的产生电路,右边的都是时钟的分配电路,中间的这个 system clock 就是系统时钟 72 兆赫值。在时钟产生链路有四个震荡源,分别是内部的八兆赫兹高速 RC 震荡器。外部的四到十六赫兹高速拾音晶体增长器,也就是晶震,一般都是接八兆赫兹。外部的 32.768 千赫兹低速晶震,这个一般是给 RTC 提供时钟的啊。最后是内部的 40 千赫兹低速 RC 正常器,这个可以给 Commungo 提供时钟。
上面这两个高速竞争是用来提供系统时钟的,我们 a H B a P B 2、 A P B 1 的时钟都是来源于这两个高速竞争哈。这里内部和外部都有一个八兆赫值的竞争,都是可以用的,只不过是外部的拾音震荡器比内部的 RC 震荡器更加稳定,所以一般我们都用外部竞争。但是如果你系统很简单,而且不需要那么精确的时钟,那也是可以使用内部 RC 震荡器的,这样就可以省下外部金震的电路了。
那在 system elite 函数里, s t 是这样来配置时钟的,首先它会启动内部时钟,选择内部 8 兆赫之为系统时钟,暂时以内部 8 兆赫值的时钟运行,然后再启动外部时钟配置。外部时钟走这一路进入 PLL 所向环进行倍平八兆赫之倍平 9 倍,得到七十二兆赫兹。等到索向环输出稳定后,选择索向环输出为系统适中。
这样就把系统时钟由八兆赫兹切换为了七十二兆赫兹,这是 ST 配置的流程,大家可以自己分析一下 system ED 的函数时间关系,我就不带着大家一步步分析了,这样分析之后可以解决实际应用的一个问题,那就是如果你的外部金正出问题了,可能会导致一个现象,就是你会发现你程序的时钟慢了大概 10 倍,比如你用定时器定一个 1 秒的时间,结果过了大概 10 秒才进中断。
这个问题就出在这里,如果外部金正出问题了,系统始终就无法切换到 72 兆赫兹,那它就会以内部的 8 兆赫兹运行。 8 兆相比于 72 兆大概就慢了 10 倍。我之前画了个板子就遇到了这个问题,我发现时钟好像慢了 10 倍,检查一下发现我芯片焊接的时候把外部经证的两个引角焊短路了,最后把这两个引角分开,始终就变为正常的 72 兆了。
另外这里还有一个CSS,这个是时钟安全系统r,它也是负责切换时钟的,它可以监测外部时钟的运行状态,一旦外部时钟失效,它就会自动把外部时钟切换回内部时钟,保证系统始终的运行,防止程序卡死造成事故。另外在这个高级定制器这里也有这个 CSS 的声音,在这个刹车输入这里,一旦 CSS 检测到外部时钟失效,这里通过后门就会立刻反应到输出比较这里让这个输出控制的电机立刻停止,防止意外,这就是这个 STM 32 里面的一些安全保障措施。那回到这里,接下来我们再看一下这右边的时钟分配电路。首先系统时钟 7 十二兆赫兹进入 AHB 中线, AHB 纵线有个域分频器。在 system elite 里配置的分频系数为一,那 AHB 的时钟就是 72 兆赫兹,然后进入 APB 1 中线,这里配置的分频系数是2,所以 APB 1 总线的时钟为 72 兆赫兹,除以 2 = 36 兆赫兹。
现在大家可能会有个问题,就是我们刚才说通用定时器和基本定时器是接在 APPE 上的,而 APBE 的时钟是 36 兆赫兹,按理说他们的时钟应该是 36 兆赫兹,但是我在讲定时器的时候一直都说的是所有的定时器的时钟都是 72 凿合值,这是为啥呢?原因就在这里,这下面还有一条之路,上面写的是如果 AP B1 预分明系数等于一,则频率不变,否则频率乘2。然后再看右边,发现这一路是单独为定时器 2- 7 开通的,那因为这里预分频系数我们给的是2,所以这里频率要再乘2,所以通下定时器 2- 7 的时钟就又回到了 72 兆赫兹。所以这里就可以有个结论,无论是高级定时器还是通用定时器,还是基本定时器,它们的内部基准时钟都是 72 兆赫兹,这个就给我们的使用带来了方便,不用再考虑不同定时器的时钟不一样的问题了。当然前提是你不乱改它 system elite 里面的默认配置,要是改了,这里的时钟还得再另行分析哈。
然后我们再看一下下面 a P B 2 的时钟,这里给的分明系数为一,所以 APB 2 的时钟和 AHB 一样都是 72 兆赫兹,这里接待 APB 2 上的高级定时器也单开了一路啊。上面写的也是,如果 A P B 2 预分频系数等于一,则频率不变,否则频率乘2。但是这里 APB 2 的运分频系数就是一,所以频率不变,定时期一和 8 的始终就是 72 兆赫兹啊。那在这些时钟输出这里都有一个语门进行输出控制,控制位写的是外部时钟死能,这就是我们在程序中写RCC、 APB 二或者 APB 1 外设始终控制作用的地方,打开时钟就是在这个位置写一,让左边的时钟能够通过语门输出给外设。好,那就有关时钟数的内容我就讲到这里哈。剩下的还有一些给ADC、 HDLO 等等这些提供时钟的电路,大家就自己看看了。最后我们还是再简单的看一下手册,看看手册上关于定时器的介绍。在手册里关于定时器的介绍有三张,高级定时器、通用定时器和基本定时器各占一张,内容还是非常多的,我们打开通用定义日期看一下哈。首先是简介,这里有它的一些基本描述哈。然后下面是结构图,这个还是很重要的哈。再下面就是功能描述有实际单元。这里面有一些时序图演示的域分明器的工作流程,下面这里计数器的时序图,这又比较多了,不仅有这个向上计数的模式啊。还有向下计数模式的。
中央对齐模式的。
一般向上技术用的最多,其他的想了解的话可以再看看这个手册。接着下一节就是始终选择了这里,想深入研究的话也可以再看看手册,再下面就是捕获比较通道的介绍,这个我们后续课程再讲哈。好,那到这里本小节的内容就全部完成了,我们下一小节来开始写

定时器库函数tim.h

//恢复缺省(默认)配置
void TIM_DeInit(TIM_TypeDef* TIMx);

//时基单元初始化,比较重要。参数1:选择定时器;参数二:结构体,包含了配置时基单元的一些参数
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

//可以把结构体变量赋一个默认值
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

//用来使能寄存器,对应图中的运行控制。参数1:选择定时器;参数2:新的状态,选择使能还是失能,使能计数器可以运行,失能计数器不能运行
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

//用来使能中断输出信号,对应图中中断输出控制,参数1:选择定时器;参数2:选择要配置哪个中断输出;参数3:新的状态,使能还是失能;
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);


************************************************************************
以下6个对应时基单元的时钟选择部分

//选择内部时钟
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

//选择ITRx其他定时器的时钟,参数1:选择要配置的定时器;参数2:选择要接入哪个其他的定时器
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

//选择TIx捕获通道的时钟,参数1:选择要配置的定时器;参数二:选择TIx具体的某个引脚;后面两个参数;输入的极性和滤波器
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource, uint16_t TIM_ICPolarity, uint16_t ICFilter);

//选择ETR通过外部时钟模式1输入的时钟,参数2:外部触发预分频器,可以对ETR的外部时钟再提前做一个分频
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

//选择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);
*************************************************************************

//由于TIM_TimeBaseInitStruct里的值在后期可能还会做修改,而再修改某个参数再调用初始化函数就太麻烦了,因此提出以下函数,方便用来修改关键参数

//用来单独写预分频值,参数1:要写入的预分频值;参数二:写入模式
//预分频器有个缓冲器写入的值是在更新事件发生后才有效的。所以这里有个写入的模式可以选择是听从安排在更新事件生效,或者是在写入后手动产生一个更新事件,让这个值立刻生效。
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);

//用来改变计数器的计数模式。参数 count mood,选择新的计数型模式
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);


//自动重装器预装功能配置
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);



//用来获取标志位和清除标志位的
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);

TIM_ClockDivision 指定时钟分频,与滤波器频率f有关

滤波器工作原理:在一个固定的时钟频率f下进行采样,如果连续N个采样点都为相同的电平,那就代表输入信号稳定,然后输出信号,这N个采样值不全相同,那说明信号抖动,那就保持上一次的输出或直接输出低电平。其中采样频率f 可以由内部时钟直接而来,或者由内部时钟加时钟分频而来,分频多少就由TIM_ClockDivision决定。

  • TIM_CKD_DIV1        //1分频
  • TIM_CKD_DIV2        //2分频
  • TIM_CKD_DIV4        //4分频

TIM_CounterMode 计数器模式

  • TIM_CounterMode_Up        //向上计数模式
  • TIM_CounterMode_Down        //向下计数模式
  • TIM_CounterMode_CenterAligned1        //三种中央对齐模式
  • TIM_CounterMode_CenterAligned2
  • TIM_CounterMode_CenterAligned3

时基单元配置

控制定时时间

时基单元(如定时器)的计数器溢出频率是指计数器达到其最大值(即溢出)所需的时间。这一频率决定了定时器产生中断或更新事件的频率。

假如要定时1s,即定时频率1Hz,那么给PSC 7200-1,ARR给10000-1

因为预分频器和计数器都有1个数的偏差,所以要-1

PSC和ARR值在0~65535之间

预分频PSC对72M进行分频,得到10k计数频率,在10k的频率下,计10000个数就是1s。

  • TIM_Period周期,ARR自动重装寄存器的值

  • TIM_Prescaler,PSC预分频器的值

  • TIM_RepetitionCounter,重复计数器的值

    • 高级计时器才有,不用时给0

使能更新中断

TIM_ITConfig

开启更新中断到NVIC的通路

NVIC配置

NVIC优先级分组

初始化NVIC

  • 中断通道
  • 使能
  • 抢占优先级
  • 响应优先级

启动定时器

TIM_Cmd();

中断函数

在startup启动文件里,查找中断函数名字

定时器的输出比较功能

OC(Output Compare)输出比较

IC(Input Capture)输入捕获

CC(Capture/Compare)输入捕获和输出比较单元

功能:用来输出PWM波形,PWM波形又是用来驱动电机的必要条件,用来做智能车、机器人等

输出比较可以通过比较CNT计数器与CCR捕获/比较寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形

每个高级定时器和通用定时器都拥有4个输出比较通道

高级定时器的前3个通道额外拥有死区生成和互补输出的功能

PWM波形(Pulse Width Modulation)脉冲宽度调制

是数字输出信号,由高低电平组成

在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域。

        使用这个 PWM 波形是用来等效的实现一个模拟信号的输出。也就是我们最开始提的问题,数字输出端口控制LED,按理说 LED 只能有完全亮和完全灭两种状态,怎么能实现控制亮度大小呢?那通过这个 PWM 波形就可以实现我们让 LED 不断点亮熄灭,当这个点亮熄灭的频率足够大时, LED 就不会闪烁了,而是呈现出一个中等亮度。当我们调控这个点亮和熄灭的时间比例时,就能让 LED 呈现出不同的亮度级别。

        对于电机调速也是一样,我们以一个很快的频率给电机通电、断电,那么电机的速度就能维持在一个中等速度,这就是 PWM 的基本思想。看起来也是一个挺简单的方法,是吧? PWM 的秘诀就是天下武功唯快不破。要我闪的足够快,你就发现不了我到底是闪着亮的,还是一个正常的平稳的亮度。当然,PWM的应用场景必须要是一个惯性系统。就是说 LED 在熄灭的时候,由于余晖和人眼视觉暂留现象, LED 不会立马熄灭,而是有一定的惯性,过一小段时间才会熄灭。电机也是当电机断电时,电机的转动不会立马停止,而是有一定的惯性,过一会才停,这样具有惯性的系统才能使用PWM。

PWM参数

频率=1/Ts  ;占空比:Ton/Ts  ;分辨率=占空比变化步距

占空比:占空比越大,则模拟电压越趋近于高电平,反之则趋近于低电平

假设高电平5V,低电平0V,占空比为50%,则模拟电压为2.5V,若占空比为25%,则模拟电压为1.25V。

分辨率

  • 占空比是1%,2%,3%等等这样就是以1%的步距跳变
  • 占空比是1.1%,1.2%,1.3%这样是以0.1%的步距跳变
  • 分辨率就是占空比变化的细腻程度

通用定时器的输出比较通道框图

  1. 左边就是 CNT 计数器和 CCR1 第一路的捕获/比较寄存器,它俩进行比较。
  2. 当 CNT 大于 CCR1 或者 CNT 等于 CCR1 时,就会给这个输出模式控制器传一个信号,然后输出模式控制器就会改变它输出 OC1 ref 的高低电瓶。ref  信号实际上就是指这里信号的高低电平,这个 ref 是 reference 的缩写,意思是参考信号
  3. ETRF 输入,这是定时器的一个小功能,一般不用,不需要了解。
  4. 输出模式控制器工作原理
    1. 什么时候给 ref 高电瓶,什么时候给 ref 低电瓶?我们看一下下面的这个表,这就是输出比较的 8 种模式,也就是这个输出模式控制器里面的执行逻辑,这个模式控制器的输入是 CNT 和 CCR 的大小关系。输出是REF的高低电平,里面可以选择多种模式来更加灵活的控制 ref 输出,模式可以通过寄存器(TIMx_CCMR1)来进行配置,你需要哪个模式就可以选那个模式。那具体都是怎么操作的呢?我们来看一下这个表。冻结,描述是 CNT 等于 CCR 时, REF保持为原状态,CNT等于 CCR 时维持原状态。那其实这个 CNT 和 CCR 就根本没有用,是吧?所以你也可以把它理解成 CNT 和 CCR 无效 REF 保持为原状态,这都是一样的效果。那这个模式也比较简单,它根本就不管 CNT 谁大谁小,直接 REF 保持不变,维持上一个状态就行了。这有什么用呢?比如你正在输出 PWM 波,突然想暂停一会输出,就可以设置成这个模式,一旦切换为冻结模式后,输出就暂停了,并且高低电平也维持为暂停时刻的状态保持不变,这就是冻结模式的作用。 
    2. 匹配时置有效电平匹配时置无效电平匹配时电平翻转,这个有效电平和无效电平一般是高级定时器里面的一个说法,是和关断刹车这些功能配合表述的。他说的比较严谨,所以叫有效电平和无效电平。在这里为了理解方面,你可以直接认为置有效电平就是置高电平,置无效电平就是置低电平。那这三个模式都是当 CNT 与 CCR 值相等时执行操作:

      1. 第一个是 CNT 等于 CCR 时 REF 置有效电平,也就是高电平。
      2. 第二个是相等时置无效电平,也就是低电平。
      3. 第三个是相等时电平翻转。
    3. 这些模式就可以用作波形输出了,比如相等时电瓶翻转这个模式,这个可以方便的输出一个频率可调占空比始终为 50% 的 PWM 波形。比如你设置CCR为0,那 CNT 每次更新清零时,就会产生一次 CNT = CCR 的事件,这就会导致输出电平翻转一次,每更新两次,输出为一个周期,并且高电平和低电平的时间是始终相等的,也就是占空比始终为50%。当你改变定时器更新频率时,输出波形的频率也会随之改变,它俩的关系是,输出波形的频率=更新频率/2,因为更新两次输出才为一个周期,这就是这个匹配时电平翻转模式的用途。

      上面这两个相等时置高电瓶和低电瓶感觉用途并不是很大,因为他们都只是一次性的,置完高或低电平后就不管事了,所以这两模式不适合输出连续变化的波形,如果你想定时输出一个一次性的信号,那可以考虑一下这两个模式。

    4. 强制为无效电平强制为有效电平,这两个模式是 CNT 与CCR无效,REF强制为无效电平或者强制为有效电平。这里这两个模式和冻结模式也差不多,如果你想暂停波形输出,并且在暂停期间保持低电平或者高电平,那你就可以设置这两个强制输出模式。

    5. PWM 模式1PWM 模式2非常重要,他们可以用于输出频率和占空比都可调的 PWM 波形,也是我们主要使用的模式。

      1. PWM 模式1,计数器为向上计数的情况下,它是 CNT 小于 CCR 时, REF 置有效点平, CNT 大于等于 CCR 时 REF 至无效点平。在向下技术的情况下,是 CNT大于 CCR时,REF置无效电瓶CNT小于等于 CCR 时, REF 制有效电平。这个情况比较多,一般我们都只使用向上计数,所以这里向下计数的描述我们就暂时不看了。他们之间也只有大小关系,极性这些东西不同,基本思想都是一样的,我们着重分析一个向上计数的就可以了,然后再对比看一下

        PWM 模式2,在向上计数的情况下, CNT小于CCS, REF 置无效电瓶。CNT大于等于 CCS 时, REF 至有效电瓶。经过观察可以发现它的大小比较关系,和上面这是一样的,区别就是输出的高低电平反过来了,所以 PWM 模式 2 实际上就是 PWM 模式1输出的取反,改变PWM 模式1和 PWM 模式 2 就只是改变了 REF 电瓶的极性而已。

  5. ref 信号可以前往主模式控制器。你可以把这个 ref 映射到主模式的 TRGO 输出上去,不过 ref 的主要去向还是下面这一路,
  6. 通过下面这一路到达一个极性选择,给这个寄存器写 0 信号就会往上走,就是信号电平不翻转,进来啥样出去还是啥样,写一的话信号就会往下走,就是信号通过一个非门取反,那输出的信号就是输入信号高低电平反转的信号,这就是极性选择,就是选择是不是要把高低电平反转一下
  7. 接着就是输出使能电路了,选择要不要输出。
  8. 最后是 OC1 引脚,这个引脚就是 CH1 通道的引脚,在引脚定义表里就可以知道具体是哪个 GPIO 了。

PWM基本结构

 蓝线:CNT;黄线:ARR;红线:CCR,CCR的值可以控制占空比

绿线:输出

REF是一个频率可调,占空比可调的PWM波形。

参数计算

 CK_PSC:预分频器时钟,CK表示CLOCK时钟的意思

分辨率ARR越大越好,CCR越大越好

高级定时器输出比较通道

红圈电路理解

需要结合外部电路来理解在其外面通常接一个正极接着一个大功率开关管(一般是MOS管),再来一个MOS管,最后GND,MOS管左边是控制极,比如说给高电平右边两根线就导通,低电平就断开,下面的MOS管也是一样,这就是一个基本的推挽电路,中间是输出,上管导通、下管断开,那就是输出高电平,反之低电平,都导通就是电源短路,不允许,都断开就是高阻态。

如果又两个这样的推挽电路就形成了H桥电路,可以控制直流电机正反转。

如果有三个这样的推挽电路,就可以用于驱动三相无刷电机。

如果要用单片机来控制,那就需要用两个控制极(如上图推挽电路),并且这两个电极电平相反互补,这样我们就好理解内部电路了

OC1和OC1N就是两个互补的输出端口,分别控制上下管的导通和关闭

为避免上管还没完全关闭,下管就打开的短暂同时导通现象,有了死区生成电路

死区生成电路:会在上管关闭的时候延迟一会再导通下管

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值