LV16-32-定时器-02-通用定时器-01-基础知识

本文主要是STM32开发——定时器 通用定时器 的一些基础知识相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
  • 通用
分类 网址说明
官方网站https://www.arm.com/ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.st.com/content/st_com/zh.htmlST官方网站,在这里我们可以找到STM32的相关文档
https://www.stmcu.com.cn/意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档
http://elm-chan.org/fsw/ff/00index_e.htmlFatFs文件系统官网
教程书籍《ARM Cortex-M3权威指南》ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩
《ARM Cortex-M0权威指南》
《ARM Cortex-M3与Cortex-M4权威指南》
开发论坛http://47.111.11.73/forum.php开源电子网,正点原子的资料下载及问题讨论论坛
https://www.firebbs.cn/forum.php国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT
https://www.amobbs.com/index.php阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。
http://download.100ask.net/index.html韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。
博客参考http://www.openedv.com/开源网-原子哥个人博客
http://blog.chinaaet.com/jihceng0622博主是原Freescale现NXP的现场应用工程师
cortex-m-resources这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接)
点击查看相关文件下载
分类 网址 说明
STM32相关 STM32F103xx英文数据手册 STM32F103xC/D/E系列的英文数据手册
STM32F103xx中文数据手册 STM32F103xC/D/E系列的中文数据手册
STM32F10xxx英文参考手册(RM0008) STM32F10xxx系列的英文参考手册
STM32F10xxx中文参考手册(RM0008) STM32F10xxx系列的中文参考手册
Arm Cortex-M3 处理器技术参考手册-英文版 Cortex-M3技术参考手册-英文版
STM32F10xxx Cortex-M3编程手册-英文版(PM0056) STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版
STM32 HAL库开发实战 野火STM32开发教程在线文档——基于F103系列开发板
STM32库开发实战指南 野火STM32开发教程在线文档——基于野火霸道开发板
SD卡相关 SD卡相关资料——最新版本 有关SD卡的一些资料可以从这里下载
SD卡相关资料——历史版本 有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议
SD 2.0 协议标准完整版 这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看
ESP32 SD卡相关资料——最新版本 这个⼿册介绍了 ESP8266EX 的产品参数。
ESP8266 系列入门教程 一个入门手册(安信可官网)
ESP8266 AT 指令集 这是一篇关于ESSP8266的AT指令集的文档(安信可官网)
ESP8266 AT 指令使用实例 这是一篇关于ESSP8266的AT指令集使用实例的文档(安信可官网)
ESP-AT 用户指南 本指南详细介绍 ESP-AT 是什么、如何连接硬件、以及如何下载和烧录 AT 固件(乐鑫官网)
乐鑫官方技术文档 这里是乐鑫官方技术文档的入口,文档都可以来这里找(乐鑫官网)

一、STM32的通用定时器

STM32F103 的通用定时器有 4 个,如下所示:

image-20240114085044691

该表可以参考《STM32数据手册》的2.3.17 Timers and watchdogs小节。由上表知道: 该 STM32 芯片的计数器都是 16 位的。 通用定时器和高级定时器其实也就是在基本定时器的基础上,添加了一些其他功能,如: 输入捕获、 输出比较、输出 PWM 和单脉冲模式等。 而通用定时器数量较多,其特性也有一些的差异,但是基本原理都一样。

二、通用定时器框图

基本框图如下:

image-20240114085219342

图二-1 通用定时器框图

1. ① 时钟源

1.1 有哪些选择?

通用定时器时钟可以选择下面四类时钟源之一:

(1)内部时钟(CK_INT)。

(2)外部时钟模式 1:外部输入引脚(TIx), x=1, 2(即只能来自于通道 1 或者通道 2)。

(3)外部时钟模式 2:外部触发输入(ETR)。

(4)内部触发输入(ITRx):使用一个定时器作为另一定时器的预分频器。

通用定时器时钟源的设置方法如下表所示:

定时器时钟类型 设置方法
内部时钟(CK_INT) 设置 TIMx_SMCR 的 SMS=0000
外部时钟模式 1:外部输入引脚(TIx) 设置 TIMx_SMCR 的 SMS=1111
外部时钟模式 2:外部触发输入(ETR) 设置 TIMx_SMCR 的 ECE=1
内部触发输入(ITRx) 设置可参考《STM32中文参考手册》的14.3.15 小节

1.2 内部时钟(CK_INT)

STM32F1 系列的定时器 TIM2/TIM3/TIM4/TIM5/ TIM6/TIM7 都是挂载在 APB1 总线上, 这些定时器的内部时钟(CK_INT)实际上来自于 APB1 总线提供的时钟。但是这些定时器时钟不是由 APB1 总线直接提供,而是要先经过一个倍频器。 在 HAL 库版本例程源码的 sys.c 文件中,系统时钟初始化函数 sys_stm32_clock_init 已经设置 APB1 总线时钟频率为 36MHz, APB1 预分频器的预分频系数为 2,所以这些定时器时钟源频率为72MHz 。因为当 APB1 预分频器的预分频系数≥2 分频时, 挂载在 APB1 总线上的定时器时钟频率是该总线时钟频率的两倍。这个和基本定时器一样。

另外, 高级定时器 TIM1 和 TIM8 是挂载在 APB2 总线上的, 也随便给大家说一下它们的情况。 由STM32F1 时钟系统图(可以看数据手册)可以知道,如果 APB2 预分频系数为 1,挂载在该总线的定时器时钟频率不变,否则频率是该总线时钟频率的 2 倍。 我们在系统时钟初始化函数sys_stm32_clock_init 已经设置 APB2 总线时钟频率为 72MHz, APB2 预分频器的预分频系数为1,所以 TIM1 和 TIM8 时钟源频率为 72MHz。

1.3 外部时钟模式 1(TI1、 TI2)

外部时钟模式 1 这类时钟源,顾名思义时钟信号来自芯片外部。时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_CH1(或者TIMx_CH2),这里需要注意的是:外部时钟模式 1 下,时钟源信号只能从 CH1 或者 CH2 输入到定时器, CH3 和 CH4 都是不可以的。从 IO到 TIMx_CH1(或者 TIMx_CH2),就需要我们配置 IO 的复用功能,才能使 IO 和定时器通道相连通。

时钟源信号来到定时器 CH1 或 CH2 后,需要经过什么“关卡”才能到达计数器作为计数的时钟频率的?我们来看一下:

image-20240114090049775

图二-2 外部时钟模式 1 框图

图中是以 CH2(通道 2)为例的,时钟源信号到达 CH2 后,那么这里我们把这个时钟源信号用 TI2 表示,因为它只是个信号,来到定时器内部,那我们就按定时器内部的信号来命名。

TI2 首先经过一个滤波器,由 ICF[3:0]位来设置滤波方式,也可以设置不使用滤波器。

接着经过边沿检测器,由 CC2P 位来设置检测的边沿,可以上升沿或者下降沿检测。

然后经过触发输入选择器,由 TS[4:0]位来选择 TRGI(触发输入信号)的来源。可以看到图中框出了 TI1F_ED、 TI1FP1 和 TI2FP2 三个触发输入信号(TRGI)。 TI1F_ED 表示来自于 CH1,并且没有经过边沿检测器过滤的信号,所以它是 CH1 的双边沿信号,即上升沿或者下降沿都是有效的。 TI1FP1 表示来自 CH1 并经过边沿检测器后的信号,可以是上升沿或者下降沿。 TI2FP2 表示来自 CH2 并经过边沿检测器后的信号,可以是上升沿或者下降沿。这里以CH2 为例,那只能选择 TI2FP2。如果是 CH1 为例,那就可以选择 TI1F_ED 或者 TI1FP1。

最后经过从模式选择器,由 ECE 位和 SMS[2:0]位来选择定时器的时钟源。这里我们介绍的是外部时钟模式 1,所以 ECE 位置 0, SMS[2:0] = 111即可。 CK_PSC 需要经过定时器的预分频器分频后,最终就能到达计数器进行计数了。

1.3 外部时钟模式 2(ETR)

外部时钟模式 2,顾名思义时钟信号来自芯片外部。时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_ETR。从 IO 到 TIMx_ETR,就需要我们配置 IO 的复用功能,才能使IO 和定时器相连通。

时钟源信号来到定时器 TIMx_ETR 后,需要经过什么“关卡”才能到达计数器作为计数的时钟频率?我们来看一下:

image-20240114091029566

图二-3 外部时钟模式 2 框图

可以看到在外部时钟模式 2 下,定时器时钟信号首先从 ETR 引脚进来。

接着经过外部触发极性选择器,由 ETP 位来设置上升沿有效还是下降沿有效,选择下降沿有效的话,信号会经过反相器。

然后经过外部触发预分频器,由 ETPS[1:0]位来设置预分频系数,系数范围: 1、 2、 4、 8。

紧接着经过滤波器器,由 ETF[3:0]位来设置滤波方式,也可以设置不使用滤波器。 fDTS 由TIMx_CR1 寄存器的 CKD 位设置。

最后经过从模式选择器,由 ECE 位和 SMS[2:0]位来选择定时器的时钟源。这里我们介绍的是外部时钟模式 2,直接把 ECE 位置 1 即可。 CK_PSC 需要经过定时器的预分频器分频后,最终就能到达计数器进行计数了。

1.4 内部触发输入(ITRx)

内部触发输入是使用一个定时器作为另一个定时器的预分频器,即实现定时器的级联。下面以 TIM1 作为 TIM2 的预分频器为例,我们来看一看。

image-20240114091138052

图二-4 TIM1 作为 TIM2 的预分频器框图

上图中, TIM1 作为 TIM2 的预分频器,需要完成的配置步骤如下:

(1)TIM1_CR2 寄存器的 MMS[2:0]位设置为 010,即 TIM1 的主模式选择为更新(选择更新事件作为触发输出 (TRGO))。

(2)TIM2_SMCR 寄存器的 TS[2:0]位设置为 000,即使用 ITR1 作为内部触发。 TS[2:0]位用于配置触发选择,除了 ITR1,还有其他的选择,详细描述如下图所示:

image-20240114091211234

图二-5 触发选择

上图中的触发选择中,我们在学习外部时钟模式 1 的时候说过 TI1F_ED、TI1FP1 和 TI2FP2,以及外部时钟模式 2 的 ETRF, 它们都是属于外部的,其余的都是内部触发了。那么这内部触发都代表什么意思呢?我们可以找到《STM32中文参考手册》的 表78 TIMx内部触发连接:

image-20240114091357679

在步骤(2)中, TS[2:0]位设置为 000,使用 ITR1 作为内部触发,这个 ITR1 什么意思?由上表可以知道,当从模式定时器为 TIM2 时, ITR1 表示主模式定时器就是 TIM1。 这里只是TIM2~5 的内部触发连接情况,其他定时器可以查看参考手册的相应章节。

(3)TIM2_SMCR 寄存器的 SMS[2:0]位设置为 111,即从模式控制器选择外部时钟模式 1。

(4)TIM1 和 TIM2 的 CEN 位都要置 1,即启动计数器。

定时器的时钟源这部分内容是非常重要的,因为这计数器工作的基础。虽然定时器有四类时钟源之多,但是我们最常用的还是内部时钟。

2. ② 控制器

控制器包括:从模式控制器、编码器接口和触发控制器(TRGO)。从模式控制器可以控制计数器复位、启动、递增/递减、计数。编码器接口针对编码器计数。触发控制器用来提供触发信号给别的外设,比如为其它定时器提供时钟或者为 DAC/ADC 的触发转换提供信号。

3. ③ 时基单元

时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。这部分内容和基本定时器基本一样的。

不同点是:通用定时器的计数模式有三种: 递增计数模式、 递减计数模式和中心对齐模式;TIM2 和 TIM5 的计数器是 32 位的。递增计数模式在学习基本定时器的时候已经学习过了,那么对应到递减计数模式就很好理解了。就是来了一个计数脉冲,计数器就减 1,直到计数器寄存器的值减到 0,减到 0 时定时器溢出,由于是递减计数,故而称为定时器下溢,定时器溢出就会伴随着更新事件的发生。然后计数器又从自动重载寄存器影子寄存器的值开始继续递减计数,如此循环。最后是中心对齐模式, 字面上不太好理解。该模式下,计数器先从 0 开始递增计数,直到计数器的值等于自动重载寄存器影子寄存器的值减 1 时,定时器上溢,同时生成更新事件,然后从自动重载寄存器影子寄存器的值开始递减计算,直到计数值等于 1 时,定时器下溢,同时生成更新事件,然后又从 0 开始递增计数,依此循环。每次定时器上溢或下溢都会生成更新事件。计数器的计数模式的设置请参考 TIMx_CR1 寄存器的位 CMS 和位 DIR。

我们来看一下定时器工作在不同计数模式下,更新事件发生的情况 :

image-20240114091813132

图二-6 更新事件发生条件

上图中,纵轴表示计数器的计数值,横轴表示时间, ARR 表示自动重载寄存器的值,小红点就是更新事件发生的时间点。举个例子,递增计数模式下,当计数值等于 ARR 时,计数器的值被复位为 0,定时器溢出,并伴随着更新事件的发生,后面继续递增计数。递减计数模式和中心对齐模式可以参考前面的描述。

上面的描述属于硬件更新事件发生条件,我们还可以通过 UG 位产生软件更新事件。关于影子寄存器和定时器溢出时间计算公式等内容可以参考基本定时器的相关笔记。

4. ④ 输入捕获

第④部分是输入捕获,一般应用是要和第⑤部分一起完成测量功能。TIMx_CH1~ TIMx_CH4 表示定时器的 4 个通道,这 4 个通道都是可以独立工作的。 IO 端口通过复用功能与这些通道相连。配置好 IO 端口的复用功能后,将需要测量的信号输入到相应的IO 端口,输入捕获部分可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常见的测量有:测量输入信号的脉冲宽度、测量 PWM 输入信号的频率和占空比等。

下面简单了解一下测量高电平脉冲宽度的工作原理,方便理解:一般先要设置输入捕获的边沿检测极性,如:我们设置上升沿检测,那么当检测到上升沿时,定时器会把计数器 CNT的值锁存到相应的捕获/比较寄存器 TIMx_CCRy 里, y=1~4。然后我们再设置边沿检测为下降沿检测,当检测到下降沿时,定时器会把计数器 CNT 的值再次锁存到相应的捕获/比较寄存器TIMx_CCRy 里。最后,我们将前后两次锁存的 CNT 的值相减,就可以算出高电平脉冲期间内计数器的计数个数,再根据定时器的计数频率就可以计算出这个高电平脉冲的时间。如果要测量的高电平脉宽时间长度超过定时器的溢出时间周期,就会发生溢出,这时候我们还需要做定时器溢出的额外处理。低电平脉冲捕获同理。

上面的描述是第④部分输入捕获整体上的一个应用情况,下面我们来看第④部分的细节。当需要测量的信号进入通道后,需要经过哪些“关卡”?我们一起来看一下:

image-20240114092147664

图二-7 通道 1 输入阶段

上图是图二-1 通用定时器框图第④部分通道 1 的“放大版”,这里是以通道 1 输入捕获为例进行介绍,其他通道同理。

待测量信号到达 TIMx_CH1 后,那么这里我们把这个待测量信号用 TI1 表示。

TI1 首先经过一个滤波器,由 ICF[3:0]位来设置滤波方式,也可以设置不使用滤波器。 fDTS由 TIMx_CR1 寄存器的 CKD 位设置。

接着经过边沿检测器,由 CC1P 位来设置检测的边沿,可以上升沿或者下降沿检测。 CC1NP是配置互补通道的边沿检测的,在高级定时器才有,通用定时器没有。

然后经过输入捕获映射选择器,由 CC1S[1:0]位来选择把 IC1 映射到 TI1、 TI2 还是 TRC。这里我们的待测量信号从通道 1 进来,所以选择 IC1 映射到 TI1 上即可。

紧接着经过输入捕获 1 预分频器,由 ICPS[1:0]位来设置预分频系数,范围: 1、 2、 4、 8。

最后需要把 CC1E 位置 1,使能输入捕获, IC1PS 就是分频后的捕获信号。这个信号将会到达 图二-1 通用定时器框图 的第⑤部分。

下面我们接着看 图二-1 通用定时器框图 的第⑤部分的“放大版”,如下图所示:

image-20240114092634878

图二-8 捕获/比较通道 1 主电路(输入捕获功能部分)

图中,灰色阴影部分是输出比较功能部分,学习到第⑥部分输出比较的时候再说。左边没有阴影部分就是输入捕获功能部分了。

首先看到捕获/比较预装载寄存器,我们以通道 1 为例,那么它就是 CCR1 寄存器,通道 2、通道 3、通道 4 就分别对应 CCR2、 CCR3、 CCR4。在 图二-1 通用定时器框图 中就可以看到 CCR1~4 是有影子寄存器的,所以这里就可以看到图二-8中有捕获/比较影子寄存器,该寄存器不可直接访问。

图二-8 左下角的 CC1G 位可以产生软件捕获事件,那么硬件捕获事件如何产生的?这里我们还是以通道 1 输入为例, CC1S[1:0] = 01,即 IC1 映射到 TI1 上; CC1E 位置 1,使能输入捕获;比如不滤波、不分频, ICF[3:0] = 00, ICPS[1:0] = 00;比如检测上升沿, CC1P 位置 0;接着就是等待测量信号的上升沿到来。当上升沿到来时, IC1PS 信号就会触发输入捕获事件发生,计数器的值就会被锁存到捕获/比较影子寄存器里。当 CCR1 寄存器没有被进行读操作的时候,捕获/比较影子寄存器里的值就会锁存到 CCR1 寄存器中,那么程序员就可以读取 CCR1 寄存器,得到计数器的计数值。检测下降沿同理。

5. ⑤ 输入捕获和输出比较公用部分

该部分需要结合第④部分或者第⑥部分共同完成相应功能。

6. ⑥ 输出比较

第⑥部分是输出比较,一般应用是要和第⑤部分一起完成定时器输出功能。TIMx_CH1~ TIMx_CH4 表示定时器的 4 个通道,这 4 个通道都是可以独立工作的。 IO 端口通过复用功能与这些通道相连。

下面我们按照输出信号产生过程顺序来看看定时器如何实现输出功能的,首先看第⑤部分的“放大版”图,如下图所示

image-20240114093204210

图二-9 捕获/比较通道 1 主电路(输出比较功能部分)

图二-9 中,灰色阴影部分是输入捕获功能部分。这里我们看到右边没有阴影部分就是输出比较功能部分了。下面以通道 1 输出比较功能为例来学习定时器如何实现输出功能的。

首先程序员写 CCR1 寄存器,即写入比较值。这个比较值需要转移到对应的捕获/比较影子寄存器后才会真正生效。什么条件下才能转移?图二-9 中可以看到 compare_transfer 旁边的与门,需要满足三个条件: CCR1 不在写入操作期间、 CC1S[1:0] = 0 配置为输出、 OC1PE 位置0(或者 OC1PE 位置 1,并且需要发生更新事件,这个更新事件可以软件产生或者硬件产生)。

当 CCR1 寄存器的值转移到其影子寄存器后,新的值就会和计数器的值进行比较,它们的比较结果将会通过第⑥部分影响定时器的输出。

下面来看看第⑥部分通道 1 ,如下图所示

image-20240114093400335

图二-10 通道 1 输出阶段

上图中,可以看到输出模式控制器,由 OC1M[2:0]位配置输出比较模式,该位的描述可以参考《STM32F10xxx 参考手册_V10(中文版) .pdf》 相关定时器章节的 TIMx_CCMR1 寄存器。F1 系列有 8 种输出比较模式之多,后面用到再学习。

oc1ref 是输出参考信号,高电平有效,为高电平时称之为有效电平,为低电平时称之为无效电平。它的高低电平受到三个方面的影响:OC1M[3:0]位配置的输出比较模式、第⑤部分比较器的比较结果、还有就是 OC1CE 位配置的 ETRF 信号。 ETRF 信号可以将 Oc1ref 电平强制清零,该信号来自 IO 外部。

一般来说,当计数器的值和捕获/比较寄存器的值相等时,输出参考信号 oc1ref 的极性就会根据我们选择的输出比较模式而改变。如果开启了比较中断,还会发生比较中断。

CC1P 位用于选择通道输出极性。

CC1E 位置 1 使能通道输出。

OC1 信号就会从 TIMx_CH1 输出到 IO 端口,再到 IO 外部。