STM32 定时器介绍--基本定时器

目录

基本定时器

1.功能框图

1-时钟源

2-控制器

3-时基单元

4-影子寄存器

2.定时时间的计算

3.时基初始化结构体

4.实验设计

1-配置时基初始化结构体

2-开启定时器更新中断(即定时时间到了)

3-编写main函数


在我之前文章中说过一个系统定时器SysTick,它存在于内核,嵌套在NVIC中,所有的Cortex-M内核的单片机都具有这个定时器。而今天介绍的STM32定时器是相当于一个外设,功能更加丰富全面。

SysTick定时器文章链接:

STM32 系统定时器--SysTick_systick中断_Haohao fighting!的博客-CSDN博客

定时器分类:基本定时器(TIM6和TIM7)、通用定时器(TIM2、TIM3、TIM4和TIM5)、高级定时器(TIM1和TIM8)

功能:基本定时器:只能实现定时的功能

          通用定时器:定时、输出比较、输入捕获、互补输出

          高级定时器:包含了基本定时器和通用定时器的所有功能。

STM32F103系列有2个高级定时器TIM1和TIM8,4个通用定时器TIM2/3/4/5,2个基本定时器TIM6和TIM7。

基本定时器

计数器16bit,只能从0开始向上计数。没有外部的GPIO,是内部资源,只能用来定时。时钟来自PCLK1,为72M,可实现1~65536分频。

1.功能框图

STM32 定时器介绍--基本定时器_第1张图片

1-时钟源

时钟源来自RCC的TIMx_CLK(属于内部的CK_INT)

STM32 定时器介绍--基本定时器_第2张图片

基本定时器和通用定时器是挂载到APB1总线上,由于APB1的预分频系数是2,所以频率要×2,也就是72M。

2-控制器

控制器用于控制定时器的:复位、使能、计数、触发DAC。涉及到的寄存器为:CR1/2、DIER(DMA/中断使能寄存器)、EGR(事件产生寄存器)、SR(状态寄存器)

3-时基单元

定时器最主要的就是时基部分:包括预分频器、计数器、自动重装载寄存器。这些所有定时器都有。

预分频器PSC (寄存器 TIMx_PSC控制):

结构框图中:CK_PSC就是从APB1得到的时钟(72M),预分频控制寄存器的值就是PSC里面的值,而CK_CNT就是分频最终得到的值。

16位的预分频器PSC对内部时钟CK_PSC进行分频之后,得到计数器时钟CK_CNT=CK_PSC(预分频器时钟)/(PSC(预分频因子)+1)

计数器CNT在计数器时钟的驱动下开始计数,计数一次的时间为1/CK_CNT。

计数器、自动重装载寄存器

定时器使能(CEN置1)后,计数器 CNT在CK_CNT 驱动下计数,当TCNT值(计数器的值)与ARR 的设定值(自动重装载寄存器的值,自动重装载寄存器是16位的,最大值是65535)相等时就自动生成事件(如果使能中断就产生中断)并 CNT 自动清零,然后自动重新开始计数,如此重复以上过程。

4-影子寄存器

功能框图上有个影子,PSC和ARR都有影子寄存器。

什么是影子寄存器?

这表示在物理上这个寄存器对应2个寄存器:一个是我们可以可以写入或读出的寄存器,称为预装载寄存器,另一个是我们看不见的、无法真正对其读写操作的,但在使用中真正起作用的寄存器,称为影子寄存器。

每次发生更新事件(UEV)时,所有真正起作用的影子寄存器(shadowregister)可以同时被更新为预装载寄存器 (preloadregister)里面的值,这样可以保证多个通道的操作能够准确同步;如果没有影子寄存器(shadowregister),或者预装载寄存器 (preloadregister) 和影子寄存器 (shadowregister)是直通的,当软件更新了预装载寄存器 (preloadregister),也就立即更新了影子寄存器 (shadowregister),由于软件不能同时更新多个影子寄存器,这就会导致多个通道的时序不能同步。

原文链接:

https://blog.csdn.net/weixin_51703421/article/details/126500556

影子寄存器的存在起到一个缓冲的作用,用户值->寄存器->影子寄存器->起作用。例如:自动重装载的影子寄存器(ARR寄存器):自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件 (UEV) 时传送到影子寄存器。也就是说,在CNT计数器计数的过程中,自动重装载寄存器的值可以随时更改,更改的数值可以立刻起作用,也可以在本轮计数完成之后再起作用。是否立刻起作用可以通过软件来进行控制。由控制寄存器 1(TIMx_CR1)的ARPE位来控制。0:TIMx_ARR寄存器没有缓冲 1:TIMx_ARR寄存器具有缓冲。

而PSC的影子寄存器,只能在这一轮计数完成之后的下一轮才开始起作用。这个是不能通过软件来控制的

如果不使用影子寄存器则用户值在写到寄存器之后则里面起作用。

2.定时时间的计算

PSC = 72-1,定时器频率=72M/(PSC+1)=1MHZ,近似时间为1微秒。

若我们设定ARR(自动重装载寄存器)= 1000-1,从0计数到999,则计了1000次。

中断周期   T = 1000 *1/1000000 = 1ms

3.时基初始化结构体

时基初始化结构体 TIM_TimeBaseInitTypeDef 里面有5个成员,TIM6和TIM7的寄存器里面只有TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,另外三个成员是通用定时器和高级定时器才有。TIM_Prescaler对应预分频器(TIMx_PSC),TIM_Period对应自动重装载寄存器(TIMx_ARR)。

typedef struct
{ 
   TIM_Prescaler             都有
   TIM_CounterMode			 TIMx,x[6,7]没有,其他都有
   TIM_Period                都有
   TIM_ClockDivision         TIMx,x[6,7]没有,其他都有
   TIM_RepetitionCounter     TIMx,x[1,8,15,16,17]才有
}TIM_TimeBaseInitTypeDef; 

4.实验设计

基本定时器产生500MS定时,在主函数里面让LED反转

设计思路:让基本定时器产生1ms的中断,到了1ms之后进入中断服务函数,中断服务函数里的变量自加,加到500之后代表到了500ms。我们可以在主函数内部判断变量值是否等于500,到了500让LED翻转一次。

这个就与51或者蓝桥杯的定时器0、1、2的定时功能差不多,我们通过定时的功能,完成一个固定周期的重复事件。

1-配置时基初始化结构体

首先宏定义硬件,基本定时器的时钟,自动重装载的值,时钟分频因子,定时器的中断通道(在使用高级定时器的时候只更改这些即可)。

/********************基本定时器TIM参数定义,只限TIM6、7************/

#define BASIC_TIM6 // 如果使用TIM7,注释掉这个宏即可

#ifdef  BASIC_TIM6 // 使用基本定时器TIM6
#define            BASIC_TIM                   TIM6
#define            BASIC_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            BASIC_TIM_CLK               RCC_APB1Periph_TIM6
#define            BASIC_TIM_Period            1000-1 //自动重装载的值 1000次计数进一次中断,也就是1毫秒进一次中断
#define            BASIC_TIM_Prescaler         71     //时钟分频因子 控制计数一次的时间 72/(71+1) = 1M 也就是1微秒
#define            BASIC_TIM_IRQ               TIM6_IRQn //中断源 所有的中断源在 stm32f10x.h文件中
#define            BASIC_TIM_IRQHandler        TIM6_IRQHandler

#else  // 使用基本定时器TIM7
#define            BASIC_TIM                   TIM7
#define            BASIC_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            BASIC_TIM_CLK               RCC_APB1Periph_TIM7
#define            BASIC_TIM_Period            1000-1
#define            BASIC_TIM_Prescaler         71
#define            BASIC_TIM_IRQ               TIM7_IRQn
#define            BASIC_TIM_IRQHandler        TIM7_IRQHandler

#endif

配置、初始化时基结构体,配置、初始化NVIC结构体。

// 中断优先级配置
static void BASIC_TIM_NVIC_Config(void)//涉及到中断就要配置、初始化 NVIC
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);		
		// 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ;	
		// 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
	  // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}


static void BASIC_TIM_Mode_Config(void)//初始化时基结构体
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;	
	
	// 开启定时器时钟,即内部时钟CK_INT=72M
    BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
	
		// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;	

	  // 时钟预分频数为
    TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;
	
		// 时钟分频因子 ,基本定时器没有,不用管
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
		
		// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 
		
		// 重复计数器的值,基本定时器没有,不用管
		TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
	
	  // 初始化定时器
    TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
		
		// 清除计数器中断标志位
    TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
	  
		// 开启计数器中断
    TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
		
		// 使能计数器
    TIM_Cmd(BASIC_TIM, ENABLE);	
}

void BASIC_TIM_Init(void)
{
	BASIC_TIM_NVIC_Config();
	BASIC_TIM_Mode_Config();
}

2-开启定时器更新中断(即定时时间到了)

具体哪个定时器,具体哪种中断。这里用到的是更新中断,计数器从n计数到m为一轮产生的中断就叫做更新中断。

extern volatile uint32_t time;

void  BASIC_TIM_IRQHandler (void)
{
	if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET )//判断是否产生中断 
	{	
		time++;
		TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);  		 
	}		 	
}

3-编写main函数

int main(void)
{
	/*在程序来到main函数这里的时候,系统时钟已经配置成72M*/
	LED_GPIO_Config();//初始化函数
	BASIC_TIM_Init();
	
	while(1)
	{
		if(time == 500)
		{
			time = 0;		    
			LED1_TOGGLE;/* LED1 取反 实现LED1的亮灭反转*/  
		}
	}
}

 完整程序下载链接:

链接:https://pan.baidu.com/s/13eb3qHm4YVtHELPXYBJXdQ 
提取码:hjaw 

你可能感兴趣的:(STM32,stm32,嵌入式硬件,单片机)