STM32-定时器详解_stm32定时器

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

即:高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。

2. 通用定时器功能和特点

STM32的众多定时器中我们使用最多的是高级定时器和通用定时器,而高级定时器一般也是用作通用定时器的功能,下面我们就以通用定时器为例进行讲解,其功能和特点包括:

  • 位于低速的APB1总线上(APB1)
  • 16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。
  • 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。
  • 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:

① 输入捕获

② 输出比较

③ PWM 生成(边缘或中间对齐模式)

④ 单脉冲模式输出

  • 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
  • 如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):

①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

③输入捕获

④输出比较

⑤支持针对定位的增量(正交)编码器和霍尔传感器电路

⑥触发输入作为外部时钟或者按周期的电流管理

  • STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
  • 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。

3. 计数器模式

通用定时器可以向上计数、向下计数、向上向下双向计数模式。

①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。

②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。

③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

4. 定时器工作原理

a.定时器框图

下面就是STM32定时器的工作款图了,是学习STM32定时器必须要掌握的。很多学习者学会了通过库函数来配置定时器,实现了简单的应用却忽略了基本原理,这就对导致在复杂应用的设计上出现低级的错误。所以建议读者认真掌握定时器的工作框图,明白内在的原理。

框图可以分为四个大部分(用红色笔表示出),分别是:①时钟产生器部分,②时基单元部分,③输入捕获部分、④输出比较部分。

b.时钟产生器部分

在第一部分时钟选择上,STM32定时器有四种时钟源选择(图中蓝色笔标识),分别是:

①内部时钟(CK_INT)

②外部时钟模式:外部触发输入(ETR)

③内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

④外部时钟模式:外部输入脚(TIx)

这四种情况可由右图表示:

其中,内部触发输入口1~4除了ITR1/ITR2/ITR3/ITR4之外还有一种情况:用一个定时器作为另一个定时器的分频器。

外部捕获比较引脚有两种,分别是:

引脚1:TI1FP1或TI1F_ED

引脚2:TI2FP2

c.时基单元

时基单元就是定时器框图的第二部分,它包括三个寄存器,分别是:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)和自动装载寄存器(TIMx_ARR)。对这三个寄存器的介绍如下:

  • 计数器寄存器(TIMx_CNT)

向上计数、向下计数或者中心对齐计数;

  • 计数器寄存器(TIMx_CNT)

可将时钟频率按1到65535之间的任意值进行分频,可在运行时改变其设置值;

  • 自动装载寄存器(TIMx_ARR)

如果TIMx_CR1寄存器中的ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的那日同将在每次的更新时间UEV发生时,传送到影子寄存器;

如果TIM1_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。

d.输入捕获通道
  • IC1、2和IC3、4可以分别通过软件设置将其映射到TI1、TI2和TI3、TI4;
  • 4个16位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值;
  • 当产生一次捕捉,相应的CCxIF标志位被置1;同时如果中断或DMA请求使能,则产生中断或DMA请求。
  • 如果当CCxIF标志位已经为1,当又产生一个捕捉,则捕捉溢出标志位CCxOF将被置1。

e.输出比较通道(PWM)
  • PWM模式运行产生:

定时器2、3和4可以产生4独立的信号

频率和占空比可以进行如下设定:

一个自动重载寄存器用于设定PWM的周期;

每个PWM通道有一个捕捉比较寄存器用于设定占空时间。

例如:产生一个40KHz的PWM信号:在定时器2的时钟为72MHz下,占空比为50% :

预分频寄存器设置为0 (计数器的时钟为TIM1CLK/(O+1)),自动重载寄存器设为                         1799,CCRx寄存器设为899。

  • 两种可设置PWM模式:

边沿对齐模式

中心对齐模式

二、定时器中断应用

1.内部时钟选择

除非APB1的分频系数是1,否则通用定时器的时钟等于APB1时钟的2倍。

默认调用SystemInit函数情况下:

SYSCLK=72M

AHB时钟=72M

APB1时钟=36M

所以APB1的分频系数=AHB/APB1时钟=2

所以,通用定时器时钟CK_INT=2*36M=72M

2.计数器模式

  • 向下计数模式:(时钟分频因子=1)

  • 向下计数模式:(时钟分频因子=1)

中央对齐计数模式:(时钟分频因子=1 ARR=6)

3.定时器中断实验相关寄存器

  • 计数器当前值寄存器CNT

  • 预分频寄存器TIMx_PSC

  • 自动重装载寄存器(TIMx_ARR)

  • 控制寄存器1(TIMx_CR1)

  • DMA中断使能寄存器(TIMx_DIER)

4. 常用库函数

定时器参数初始化:

void TIM_TimeBaseInit(TIM_TypeDef* TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);

结构体内部成员:

typedef struct
{
  uint16_t TIM_Prescaler;        
  uint16_t TIM_CounterMode;     
  uint16_t TIM_Period;        
  uint16_t TIM_ClockDivision;  
  uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef; 

声明方式(一般):

TIM_TimeBaseStructure.TIM_Period = 4999; 
TIM_TimeBaseStructure.TIM_Prescaler =7199; 
TIM_TimeBaseStructure.TIM_ClockDivision =   TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode =   TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 

定时器使能函数:

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

定时器中断使能函数

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

状态标志位获取和清除

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);

5. 定时器中断实现步骤

① 能定时器时钟。

RCC_APB1PeriphClockCmd();

②  初始化定时器,配置ARR,PSC。

TIM_TimeBaseInit();

③开启定时器中断,配置NVIC。

void TIM_ITConfig();

NVIC_Init();

④  使能定时器。

TIM_Cmd();

⑥  编写中断服务函数。

TIMx_IRQHandler();

6. 应用实例

下面是使用定时器中断的代码,我们设置为每500ms中断一次,中断服务函数控制LED实现LED状态取反。时间计算方法为:

Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk

//timer.c源文件
#include "timer.h"
#include "led.h"

//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
	
	//定时器TIM3初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器


	TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
}
//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
		LED1=!LED1;
		}
}

//timer.h头文件
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"

void TIM3_Int_Init(u16 arr,u16 psc);
 
#endif

//main.c源文件
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
 

 int main(void)
 {		
 
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
	TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms  
   	while(1)
	{
		LED0=!LED0;
		delay_ms(200);		   
	}	 
}	 

三、定时器PWM输出实验

1. 通用定时器PWM概述

PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。PWM的功能有很多种,比如控制呼吸灯、控制直流电机或者舵机等驱动原件等等,是单片机的一个十分重要的功能。

在STM32单片机中,可以使用定时器的输出比较功能来产生PWM波:
       即PWM模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。其框图如下图所示:

可见,横坐标是时间变量,纵坐标是CNT计数值,CNT计数值随着时间的推进会不断经历从0到ARR,清零复位再到ARR的这一过程。这之中还有一个数值是CCRx即比较值,通过比较值和输出配置可以使之输出高低电平逻辑,这样就产生了PWM波形。通过调节ARR的值可以调节PWM的周期,调节CCRx的值大小可以调节PWM占空比。

我们以通道1为例,详细讲解PWM的工作过程,如下图所示:

从最左边进入的是时钟源,由内部时钟(CNT)或者外部触发时钟(ETRF)输入,进入输入模式控制器,通过OCMR1寄存器的OC1M[2:0]位来配置PWM模式,之后进入一个选择器,由CCER寄存器的CC1P位来设置输出极性,最后由CCER寄存器的CC1E位来使能输出,然后通过OC1来输出PWM波。

CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。

CCMR1: OC1M[2:0]位: 对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】

CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。

CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。

2. PWM模式

PWM有PWM模式1和模式2两种模式,它们之间的区别用寄存器TIMx_CCMR1的OC1M[2:0]位来分析:

表中红色框标识的地方就是PWM模式1和模式2的定义和区别,可以简单理解为:PWM模式1的情况下,当前值小于比较值为有效电平;PWM模式2的情况下,当前值大于比较值为有效电平。

理解这一点对之后的PWM配置十分重要。

下面是对PWM模式1以及向上计数配置情况的说明:

3.相关寄存器介绍

  • 捕获/比较寄存器1(TIMx_CCR1)

这里以寄存器1举例,其它的三个寄存器(CCR2、CCR3、CCR4)都是一样的

  • 捕获比较模式寄存器1(TIMx_CCMR1)

可以看到,每个捕获/比较模式寄存器可以控制两个通道,这样的话每个定时器就对应两个捕获/比较模式寄存器。其最常用的位就是0C1M(OC2M)位了,这两个位是用来设置PWM模式的,有模式1和模式2两种,这就和前面所讲的对应上了。

  • 捕获/比较使能寄存器(TIMx_CCER)

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

mage/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAS2V2aW5GbHlu,size_20,color_FFFFFF,t_70,g_se,x_16)

可以看到,每个捕获/比较模式寄存器可以控制两个通道,这样的话每个定时器就对应两个捕获/比较模式寄存器。其最常用的位就是0C1M(OC2M)位了,这两个位是用来设置PWM模式的,有模式1和模式2两种,这就和前面所讲的对应上了。

  • 捕获/比较使能寄存器(TIMx_CCER)

[外链图片转存中…(img-glI9hY8R-1715907822301)]
[外链图片转存中…(img-cL6uJYzH-1715907822301)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32定时器可以用于各种应用,比如延时、PWM、输入捕获、输出比较等。下面是STM32定时器的一些常用函数的详解: 1. 定时器时钟使能函数:`void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)` 该函数用于初始化指定的定时器时钟,并配置相应的GPIO口,以使能定时器。 2. 定时器初始化函数:`HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)` 该函数用于初始化定时器,并配置定时器的基本参数,比如时钟源、预分频系数、计数模式等。 3. 定时器启动函数:`HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)` 该函数用于启动定时器,开始计数。 4. 定时器停止函数:`HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)` 该函数用于停止定时器计数。 5. 定时器计数值设置函数:`HAL_TIM_Base_SetCounter(TIM_HandleTypeDef *htim, uint32_t Counter)` 该函数用于设置定时器的计数值。 6. 定时器计数值读取函数:`uint32_t HAL_TIM_Base_GetCounter(TIM_HandleTypeDef *htim)` 该函数用于读取定时器的当前计数值。 7. 定时器中断使能函数:`HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)` 该函数用于使能定时器的中断功能,当定时器计数完成时,会自动触发中断。 8. 定时器中断回调函数:`void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)` 该函数为定时器中断回调函数,当定时器计数完成时,会自动调用该函数。在该函数中可以编写相应的中断处理程序。 以上是一些常用的STM32定时器函数的详解,可以根据需求选择相应的函数进行使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值