一、什么是定时器?
- 👻 定时器 顾名思义就是一个定时的器件。给定定时器一个初值,当定时器达到给定的初值时,会通知CPU或者其他处理器去做他们该做的事。可以理解为我们日常的闹钟,设置一个时间,该事件到达后,闹钟会提醒我们去做该做的事。
- 👻 定时器 可以认为是一个计数器;给定计数器一个初值,每当计数一次,就会走过一个固定的时间(等同于我们的钟表,固定的进行扫描),当达到我们给定的初值时,该定时器就完成了自己的使命,产生定时器中断,执行中断函数中的程序命令(等同于闹钟响了,提醒我们该做更重要的事是一个意思)。
二、STM32定时器简介
STM32F4 板载了高级控制定时器(TIM1和TIM8)、通用定时器(TIM2到TIM5)、通用定时器(TIM9到TIM14)以及基本定时器(TIM6和TIM7)等,总共达14个定时器之多。
♈三种定时器的区别:
😸ST32F40x 高级定时器包括 TIM1 和 TIM8。高级定时器包含通用定时器的功能,同时还具有 PW 互补输出、死区功能以及刹车功能。
♉三种定时器的时钟频率
在【STM32F4资料\1.手册\STM32F407ZGT6.pdf】的P17时钟树中可知:
三、基本定时器概述
🐮STM32F40基本定时器有两个,分别是TIM6和TIM7。基本定时器的特性:
①16 位自动重载递增计数器;
②16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数介于 1 和 65536 之间;
③发生计数器上溢时会生成中断(前提是使能更新中断)。
基本定时器框图讲解
- 定时器的最大计数频率(时钟频率)是84MHZ,即图中的CK_INT。
- 基本定时器有一个预分频器,分频值1 和 65536,作用是:降低计数频率(时钟频率),分频后的计数频率(时钟频率)是上图中的CK_CNT
- 基本定时器的工作原理:编程时,先确定计数频率CK_CNT,然后给“自动重装载寄存器 ”赋值,然后“定时器计数器寄存器”在CK_CNT的频率下进行自增,如果增加到与“自动重装载寄存器 ”中的值相等时,则定时时间到达,同时会产生更新事件(如果使能中断,则会产生更新中断),简答得说:定时的过程就是“定时器计数器寄存器”的值和自动重装载寄存器 ”实时比较的一个过程。
- 时基单元:①计数器寄存器 (TIMx_CNT);②预分频器寄存器 (TIMx_PSC);③自动重载寄存器 (TIMx_ARR)
- 时基单元的每个寄存器都是16位。
寄存器讲解--介绍两个
🍎3.1 TIM6 和 TIM7 控制寄存器 1 (TIMx_CR1)
位 0 CEN 计数器使能 (Counter enable)
0:禁止计数器
1:使能计数器位 1 UDIS 更新禁止 (Update disable)
0:使能更新 (UEV),更新事件可通过以下事件之一生成:①计数器上溢②将 UG 位置 1
1:禁止 更新UEV。定时到达后不会生成更新事件。
位 2 URS 选择更新请求源 (Update request source)
0:所有以下事件都会生成更新中断。此类事件包括:①计数器上溢;②将 UG 位置 1
1:只有计数器上溢才会生成更新中断。位 3 OPM 单脉冲模式 (One-pulse mode)
0:计数器在发生更新事件时不会停止计数
1:计数器在发生下一更新事件时停止计数(将 CEN 位清零)。位 7 ARPE 自动重载预装载使能 (Auto-reload preload enable)
0: TIMx_ARR 寄存器不进行缓冲(影子寄存器无效)。
1: TIMx_ARR 寄存器进行缓冲(影子寄存器有效)。举例:定时器6使能ARR自动重装载寄存器的影子寄存器,重复定时,允许计数器上溢产生更新请求且允许UG位置1产生更新请求,使能定时器6:
TIM6->CR1 |= 1<<7; TIM6->CR1&=~(1<<3); TIM6->CR1&=~(1<<1); TIM6->CR1&=~(1<<2); TIM6->CR1|=1<<0;
🍊3.2 TIM6 和 TIM7 状态寄存器 (TIMx_SR)
位 0 UIF 更新中断标志 (Update interrupt flag)
该位有硬件置1,软件清零。
0:未发生更新(即:定时时间还没到)。
1:更新中断挂起,由以下两种因素导致该位硬件置1:
①定时器计数器上溢会导致该位置1(即该位置1表示定时时间到达)②UG位置1也会导致该位置1(前提:TIMx_CR1 寄存器中 URS = 0 且 UDIS = 0)
总结:导致产生更新中断标志位置1并且产生更新中断的因素有两个
举例:定时器7的中断函数
void TIM7_IRQHandler(void) { if(TIM7->SR&(1<<0)) //判断中断标志是否置1 { TIM7->SR &=~(1<<0);//中断标志清零 //中断代码 } }
剩下的寄存器可以去看参考手册,编程通过手册来进行查找--下面介绍的定时器也会讲解
四、 高级控制定时器 TIM1和TIM8
4.1 TIM1和TIM8简介
- 高级控制定时器TIM1和TIM8包含一个16位的自动重载计数器(重载的意思是该计数器板载了重载寄存器,当对重载寄存器写入相关命令后,可将重载寄存器的值写入到计数器中),该计数器由可编程预分频器驱动。
- 此类定时器可以用于测量输入信号的脉冲宽度(输入信号的脉冲宽度:通过对51的学习,脉冲宽度会影响PWM,在对某些外设的调速中起重要作用),或者生成输出波形。
4.2 时基单元
- 🍌可编程高级控制定时器的主要模块是一个16位计数器及其相关的自动重载寄存器。计数器可递增计数、递减计数、交替进行递增递减计数。计数器的时钟可通过预分频器进行分频。
- 🍌时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)、重复计数器寄存器(TIMx_RCR)
- 🍌自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。计数器由预分频器输出CK_CNT提供时钟,仅当TIMx_CR1寄存器中的计数器启动位(CEN)置1时,才会启动计数器。
注意:计数器将在TIMx_CR1寄存器的CEN位置1时刻的一个时钟周期后开始计数。
预分频器:预分频器可对计数器时钟频率进行分频,分频系数介于1和65536之间。该预分频器基于预分频寄存器TIMx_PSC的16位寄存器所控制的16位计数器。
4.3 计数器模式
🍉递增计数模式:
- 在递增计数模式下,计数器从0计数到自动重载值(TIMx_ARR寄存器的内容),然后重新从0开始计数并生成计数器上溢事件。
- 如果使用重复计数器,则当递增计数的重复次数达到重复计数器寄存器中编程的次数加一次(TIMx_RCR+1)后,将升成更新时间UEV。否则将在每次计数器上溢时产生更新事件。
- 将TIMx_EGR寄存器的UG位置1时,也会产生更新事件;通过软件将TIMx_CR1寄存器中的UDIS位置1可禁止UEV事件。
- 发生更新事件时,将更新所有寄存器且将更新标志(TIMx_SR状态寄存器中的UIF位)置1。
🍋递减计数模式:
- 在递减计数模式下,计数器从自动重载值(TIMx_ARR重载寄存器的内容)开始递减计数到0,然后重新开始从自动重载值开始计数并生成计数器下溢事件。
- 如果使用重复计数器,则当递减计数的重复次数达到重复计数器寄存器中编程的次数加一次(TIMx_RCR+1) 后,将生成更新事件 (UEV)。否则,将在每次计数器下溢时产生更新事件。
- 将 TIMx_EGR 寄存器的 UG 位置 1(通过软件或使用从模式控制器)时,也将产生更新事件。通过软件将 TIMx_CR1 寄存器中的 UDIS 位置 1 可禁止 UEV 更新事件。
- 发生更新事件时,将更新所有寄存器且将更新标志(TIMx_SR 寄存器中的 UIF 位)置 1。
🍈中心对齐模式(递增/递减计数):
- 在中心对齐模式下,计数器从0开始计数到自动重载值(TIMx_ARR寄存器的内容) - 1,生成计数器上溢事件;然后从自动重载值开始向下计数到1生成计数器下溢事件。之后从0开始重新计数。
- 每次发生计数器上溢和下溢时都会生成更新事件,或将 TIMx_EGR 寄存器中的 UG 位置 1 (通过软件或使用从模式控制器)也可以生成更新事件。这种情况下,计数器以及预分频器计数器将重新从 0 开始计数。通过软件将 TIMx_CR1 寄存器中的 UDIS 位置 1 可禁止 UEV 更新事件。
🍑重复计数器
当重复寄存器TIMx_RCR达到0时,才会生成更新事件。这在生成PWM信号时很有用。
每当发生N+1个计数器上溢或下溢(其中,N是TIMx_RCR重复计数器寄存器中的值),数据就从预装载寄存器转移到影子寄存器(TIMx_ARR 自动重载寄存器、 TIMx_PSC 预分频器寄存器以及比较模式下的 TIMx_CCRx 捕获/比较寄存器);
重复计数器在下列情况下递减:
- 递增计数模式下的每个计数器上溢;
- 递减计数模式下的每个计数器下溢;
- 中心对齐模式下的每个计数器上溢或者计数器下溢;
🥭时钟选择
计数器时钟可由下列时钟源提供:
内部时钟 CK_INT
外部时钟模式1:外部输入引脚
外部时钟模式2:外部触发输入ETR
外部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频值。
- ①如果禁止从模式控制器(SMS=000),则CEN位、DIR位(TIMx_CR1寄存器中)和UG位(TIMx_EGR寄存器)为实际控制位,并且只能通过软件进行更改(UG除外,仍保持自动清0)。当对CEN位写入1时,预分频器的时钟就由内部时钟CK_INT提供。
- ②当 TIMx_SMCR 寄存器中的 SMS=111 时,可选择外部时钟模式1。计数器可在选定的输入信号上出现上升沿或下降沿时计数。
- ③通过在 TIMx_SMCR 寄存器中写入 ECE=1 可选择外部时钟模式2。计数器可在外部触发输入 ETR 出现上升沿或下降沿时计数。
🍇捕获/比较通道
每个捕获/比较通道均围绕一个捕获/比较寄存器(包括一个影子寄存器)、一个捕获输入阶段(数字滤波、多路复用和预分频器)和一个输出阶段(比较器和输出控制)构建而成。
- 捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。始终可通过读写操作访问预装载寄存器。
- 在捕获模式下,捕获实际发生在影子寄存器中,然后将影子寄存器的内容复制到预装载寄存器中。
- 在比较模式下,预装载寄存器的内容将被复制到影子寄存器中,然后将影子寄存器的内容与计数器进行比较。
🌽 输入捕获模式
在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器 (TIMx_CCRx) 来锁存计数器的值。
- 发生捕获事件时,会将相应的 CCXIF 标志(TIMx_SR 寄存器)置 1, 并可发送中断或 DMA 请求(如果已使能)。
- 如果发生捕获事件时 CCxIF 标志已处于高位, 则会将重复捕获标志 CCxOF(TIMx_SR 寄存器)置 1 。可通过软件向 CCxIF 写入 0 来给 CCxIF 清零,或读取存储在 TIMx_CCRx 寄存器中的已捕获数据。向 CCxOF 写入 “0” 后 会将其清零。
🧅其他功能
PWM输入模式、强制输出模式、输出比较模式、PWM模式、互补输出和死区插入、使用断路功能、发生外部事件时清除、生成6步PWM、单脉冲模式、编码器接口模式、定时器输入异或功能、连接霍尔传感器、TIMx与外部触发同步、定时器同步、调试模式。
五、 通用定时器 TIM2到TIM5、TIM9到TIM14
通用定时器包含一个16位或32位自动重载计数器CNT,该计数器由可编程预分频器PSC驱动。
通用定时器可用于测量输入信号的脉冲宽度(输入捕获)或生成输出波形(输出比较和PWM)。使用定时器预分频器和RCC时钟控制器预分频器,可将脉冲宽度和波形周期从几微秒调制到几毫秒。STM32F4的每个通用定时器都是完全独立的,没有互相共享任何资源。
🍖STM32的通用TIMx(TIM2~TIM5和TIM9~TIM14)定时器功能包括:
- 1. 16位/32位(仅TIM2和TIM5)递增、递减、递增/递减自动装载计数器(TIMx_CNT),注意:TIM9~TIM14只支持递增计数模式。
- 2. 16位可编程(可以实时进行修改)预分频器TIMx_PSC,计数器时钟频率的分频系数为1~65535之间的任意数值。
- 3. 4个独立通道(TIMx_CH1~4,TIM9~TIM14最多两个通道),这些通道可以用来作为:
- 输入捕获 输出比较 PWM生成(边缘或中间对齐模式),注意:TIM9~TIM14不支持中间对齐模式 单脉冲模式输出
- 4. 可使用外部信号TIMx_ETR控制定时器和定时器互连(可以用一个定时器控制另外一个定时器)的同步电路。
5. 如下事件发生时,产生中断或者DMA(TIM9~TIM14不支持DMA)
- A 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
- B 触发事件(计时器启动、停止、初始化或者由内部/外部触发计数)
- C 输入捕获
- D 输出比较
- E 支持针对定位的增量(正交)编码器和霍尔传感器电路(TIM9~TIM14不支持)
- F 触发输入作为外部时钟或者按周期的电流管理(TIM9~TIM14不支持)
相关重要寄存器
🔏 控制寄存器1:TIMx_CR1
🔏DMA/中断使能寄存器:TIMx_DIER
🔑预分频寄存器:TIMx_PSC
📦计数器:TIMx_CNT寄存器
该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。
自动重装载寄存器:TIMx_ARR
该寄存器在物理上实际对应着2个寄存器
一个是程序员可以直接操作的,另外一个是程序员看不到的。这个看不到的寄存器称为影子寄存器。真正上起作用的也是影子寄存器。
🔫 控制1寄存器TIMx_CR1中的ARPE位
ARPE=0时,预装载寄存器的内容可以随时传送到影子寄存器,此时二者是连同的。
ARPE=1时,在每一次更新事件(UEV)时,才把预装载寄存器(ARR)的内容传送到影子寄存器。
状态寄存器 :TIMx_SR
该寄存器用来标记当前与定时器相关的各种事件/中断是否发生。
六、配置流程
本次操作以通用定时器TIM3为例:
💎1. TIM3时钟使能:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //使能TIM3时钟
🏈2. 初始化定时器参数,设置自动重装值,分频系数,计数方式等
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); //定时器初始化参数
第一个参数是:确定哪个定时器 第二个参数是:定时器初始化参数结构体指针
结构体定义: 注意:通用定时器只有前四个参数有用,最后一个参数是针对高级定时器的;
typedef struct { uint16_t TIM_Prescaler; //设置分频系数 uint16_t TIM_CounterMode; //设置计数方式/向上计数/向下计数/中央对齐计数 //也就是递增/递减/递增和递减 TIM_CounterMode_Up/TIM_CounterMode_Down uint16_t TIM_Period; //设置自动重载计数周期值 uint16_t TIM_ClockDivision; //设置时钟的分频因子 uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef;
例如:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 5000; //自动重载计数器周期值 TIM_TimeBaseStructure.TIM_Prescaler =7199; //设置分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频因子 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式为向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
🏉3. 设置TIM3_DIER允许更新中断
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); //定时器中断使能
⚡ 第一个参数:选择定时器号; ag. TIM1~TIM17;
⚡ 第二个参数:指明使能定时器中断的类型,ag. 更新中断TIM_IT_Update 触发中断TIM_IT_Trigger 以及输入捕获中断
⚡第三个参数:使能 ;ENABLE;
例如: TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );
⛽4. TIM3中断优先级设置;
NVIC_Init();//初始化中断优先级
🚧5. 允许TIM3工作,也就是使能TIM3
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) //使能中断
ag. TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
⚓6. 编写中断服务函数
编写中断服务函数,通过该函数处理定时器产生的相关中断。中断产生后,通过状态寄存器的值来判断产生的中断属于什么类型。处理完中断以后,向TIM3_SR的最低位写0,来清除该中断标志。 void TIM3_IRQHandler(void) ;
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t) //判断定时器TIMx的中断类型TIM_IT是否发生中断。例如:
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){} void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT) //清除定时器TIMx的中断TIM_IT标志位 TIM_ClearITPendingBit(TIM3, TIM_IT_Update );