ARM嵌入式学习笔记(五) TIMER(定时器)

1.前言

上一篇文章介绍了Systick嘀嗒定时器控制LED的闪烁,这篇文章我们来介绍一下STM32单片机中的通用定时器的部分,使用定时器来控制两个LED灯的交替闪烁。同样地,我们所使用的硬件设备仍然是STM32RCT6单片机等基础设备,关于单片机的原理图以及LED灯的引脚在前文均已详细介绍,这里我们就不再赘述。

2.定时器详解

什么是定时器

定时器顾名思义就是可以用来定时的,我们可以设置想要的定时时间,然后去做很多事情。STM32的定时器功能很强大,可以用来定时、计数、PWM产生、输入捕获以及定时器中断等,它是存在于STM32单片机中的一个外设。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6)。

定时器的时钟详解

先是8MHz的信号经过PLL倍频后送入系统时钟SYSCLK,SYSCLK经过AHB预分频后分别送至APB1和APB2定时器的时钟来自APB1和APB2的的倍频信号,最后经过APB1和APB2的预分频后送入通用定时器时钟。其框图如下所示:

通用定时器的工作原理

通用原理的工作框图如下所示,这个图包含了定时器的工作方式和工作原理。

通用定时器具有向上计数、向下计数、向上向下双向计数模式。

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

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

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

这里我们主要使用向上计数模式,定时器时间有以下计算公式

定时器频率 =((1+TIM_Prescaler )/72M)*(1+TIM_Period )
例:如果想要设置定时器频率为 1 秒,可以设置
TIM_Prescaler=35999,TIM_Period=1999

向上计数模式的具体流程如下图所示:

3.软件部分

定时器初始化

定时器初始化使用的函数为:

TIM2_Configuration(void);

让我们看看这个函数的具体内容:

void TIM2_Configuration(void)
 {
			TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

			RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
			TIM_DeInit(TIM2);
			TIM_TimeBaseStructure.TIM_Prescaler = 7199;
			TIM_TimeBaseStructure.TIM_Period = 9; 
			TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
			TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
			TIM_Cmd(TIM2, ENABLE);
 }

 这个函数首先使能了与TIM2相关的APB1时钟,再设置预分频系数和周期分别为7199和9,根据上述公式,那么定时器的时间为:

T=(7199+1)*(9+1)/72000000=0.001s=1ms

 再是一个TIM_TimeBaseInit()语句,让我们来看看这个函数的具体内容

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));

  tmpcr1 = TIMx->CR1;  

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5)) 
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
  }
 
  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
  }

  TIMx->CR1 = tmpcr1;

  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
 
  /* Set the Prescaler value */
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler and the Repetition counter
     values immediately */
  TIMx->EGR = TIM_PSCReloadMode_Immediate;           
}

这个函数主要是初始化定时器参数,设置自动重装值,分频系数,计数方式等,第一个参数是确定是哪个定时器,第二个参数是定时器初始化参数结构体指针。这个结构体一共有 5 个成员变量,对于通用定时器只有前面四个参数有用,下列为各个参数的作用

第一个参数 TIM_Prescaler 是用来设置分频系数的
第二个参数 TIM_CounterMode 是用来设置计数方式

第三个参数TIM_Period是设置自动重载计数周期值
第四个参数TIM_ClockDivision是用来设置时钟分频因子

定时器的中断发生

说到定时器中断,那么就一定与NVIC相关,因此这里用到一个函数为

NVIC_Configuration();

同样地,让我们看看这个函数的具体内容。

void NVIC_Configuration(void)
 {
		 NVIC_InitTypeDef NVIC_InitStructure; 

		 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
		 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
		 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
		 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
		 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
		 NVIC_Init(&NVIC_InitStructure);
 }

关于NVIC的内容在前面部分已经介绍,这里将不再赘述,唯一的不同就是将这里的NVIC中断通道改成了TIM2_IRQn,其余与之前的类似。

然后我们这里使用了一个函数来定义定时器中断服务函数。

void TIM2_IRQHandler(void);

 这个函数的具体内容如下:

 void TIM2_IRQHandler(void)
{ 
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{ 
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
		timer_count++;
}
}

这里主要是判断定时器中断是否发生,中断发生后进行相应的服务函数,并清除中断发生的标志位,这里我们是控制定时变量timer_count进行累加,来进行相应的定时判断。

4.完整代码

Main.c

#include "stm32f10x.h"
#include "bsp/led/bsp_led.h"
#include "bsp/GeneralTIM/bsp_GeneralTIM.h" 


__IO uint16_t timer_count=0;

int main(void)
{   
  LED_GPIO_Init();  
  
  TIM2_Configuration();  
  NVIC_Configuration();
  while (1)
  {
    if(timer_count==500)  
		{			
      LED1_ON;
			LED2_OFF;
		}
   else if(timer_count==1000)
		 {			
      LED1_OFF;
			LED2_ON;
			timer_count = 0;
		}
  }
}

Main.c中主要包括LED灯、定时器和NVIC的初始化,同时在while(1)中通过判断timer_count的值进行计时的判定,我们之前说过定时器中断1ms发生一次,对应的timer_count累加一次,这里分别在500和1000处进行判定并清除计时标志,这样就实现了500毫秒一次的LED电平翻转功能。

GeneralTIM.c

#include "bsp/GeneralTIM/bsp_GeneralTIM.h" 

	extern uint16_t timer_count;
void NVIC_Configuration(void)
 {
		 NVIC_InitTypeDef NVIC_InitStructure; 

		 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
		 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
		 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
		 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
		 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
		 NVIC_Init(&NVIC_InitStructure);
 }

void TIM2_Configuration(void)
 {
			TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

			RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
			TIM_DeInit(TIM2);
			TIM_TimeBaseStructure.TIM_Prescaler = 7199;
			TIM_TimeBaseStructure.TIM_Period = 9; 
			TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
			TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
			TIM_Cmd(TIM2, ENABLE);
 }
 
 void TIM2_IRQHandler(void)
{ 
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{ 
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
		timer_count++;
}
}

这个文件中主要就是上述所说的定时器初始化、NVIC初始化以及中断服务函数的编写,均已在前文介绍。

5.实验效果

定时器控制LED灯闪烁

6.结束语

本次实验讲解了使用Stm32的定时器控制LED灯的交替闪烁,这也是STM32单片机核心的一部分内容,希望以上内容对各位朋友有所帮助。

最后,欢迎大家在评论区留言批评指正。谢谢!

  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值