【手拉手 带你准备电赛】原来定时器还能这么用

在不了解定时器之前

蛋糕是这样的:不就是个定时器,不就只能记个数

了解了定时器之后

蛋糕是这样的:定时器!中断处理!!我可以!!!啊看看我!!!!!

那接下来就和我一起走进定时器!!!!!GOGOGO

        通用定时器是一个通过可编程预分频器(PSC)驱动的16位自动装载计数器(CNT)构成的。STM32的通用定时器可以被用来:测量输入信号脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。在这里我们主要说明定时后的中断处理功能。

        介绍到这里,大家可以就对定时器和我们已经学过的时钟心存疑惑。

        时钟是CPU的心脏,一块芯片可能具有多个时钟源,以STM32为例,它具有5个时钟源(51单片机由于功能较为简单只具有一个系统时钟)它们分别是:HSI(高速内部时钟)、HSE(高速外部时钟)、LSI(低速内部时钟)、LSE(低速外部时钟)PLL(锁相环倍频输出)。

        简单来说,时钟是定时器的基础部分,没有时钟定时器就没有办法工作,定时器是时钟功能的衍生。

        下面小蛋糕以实验为例,带大家走进定时器。

        在本实验的主要内容是:通过定时器定时产生中断,再由硬件执行中断服务函数。在本实验中,为了更好的表现出中断服务函数的作用,我们将LED的闪烁安排在中断服务函数中,使我们的实验现象更加直观。

        话不多说,上代码!!!

        首先我们需要设置中断的优先级分组,在STM32系列芯片中使用四位保存优先级,所以我们的优先级分组就有NVIC_PriorityGroup_0、NVIC_PriorityGroup_1、NVIC_PriorityGroup_2、NVIC_PriorityGroup_3、NVIC_PriorityGroup_4,共四种优先级分组可选。在这里根据我们的中断数量我们设置中断优先级分组为NVIC_PriorityGroup_2,代码如下:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组

        对中断优先级分组设置完成后,由于我们在中断服务函数中使用了LED,所以我们还要在主函数(main()函数)中完成LED的初始化。

void LED_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;        //声明初始化需要的结构体
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);	 //使能相关时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;		//设置使用引脚		 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //设置输出模式
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //设置输出频率
 GPIO_Init(GPIOA, &GPIO_InitStructure);					 //完成GPIOA8的初始化
 GPIO_SetBits(GPIOA,GPIO_Pin_8);						//设置引脚输出高电平

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	    		 
 GPIO_Init(GPIOD, &GPIO_InitStructure);	  				 
 GPIO_SetBits(GPIOD,GPIO_Pin_2); 						
}

        在上面这段代码中我们就完成了LED连接的GPIO的初始化。

        然后,重点来了。我们开始进入与定时器有关的操作——通用定时器的初始化(在这里小蛋糕使用的是TIM3定时器)

        首先我们来看看,定时器初始化参数结构体里面有哪些内容

typedef struct
{
    uuint16_t TIM_Prescaler;              //设置分频系数
    uint16_t TIM_CounterMode;             //设置计数方式(向上、向下、中央对齐)
    uint16_t TIM_Period;                  //设置自动重载计数周期值
    uint16_t TIM_ClockDivision;           //设置时钟分频因子
    uint8_t TIM_RepetitionCounter;        //仅在高级定时器中使用,这里不需要
}TIM_TimeBaseInitTypeDef;

        了解了定时器初始化参数结构体后,我们就可以根据自己的需求进行定时器初始化函数的书写了。

void TIM3_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;    //定义定时器初始化结构体
  NVIC_InitTypeDef NVIC_InitStructure;               //定义NVIC中断寄存器初始化结构体

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);     //使能时钟

	TIM_TimeBaseStructure.TIM_Period = arr;         //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc;       //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;    //设置时钟分割
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置技术模式为向上计数
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
 
	TIM_ITConfig(  
		TIM3, 
		TIM_IT_Update ,
		ENABLE  		);

	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;     //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;         //设置子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //使能对应外设的NVIC寄存器
	NVIC_Init(&NVIC_InitStructure);  

	TIM_Cmd(TIM3, ENABLE);  
							 
}

        完成定时器的初始化之后我们要开始编写我们的中断服务函数,但是需要注意的是,中断服务函数是不会被任何函数调用的,if你还不理解发生中断后的硬件工作原理,你只需要知道中断服务函数是硬件直接操作的,至于怎么操作,嗯嗯嗯嗯嗯,其实也可以暂且把它理解为调用函数的神秘力量。下面就是我们的中断服务函数。

void TIM3_IRQHandler(void)   //由于中断服务函数不能被任何函数调用,所以它没有参数、没有返回值
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)         //检查指定的定时器是否发生中断
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );           //清除中断待处理位,进行中断处理
		LED1=!LED1;        //通过LED显示中断发生,并执行中断服务函数
		LED0=!LED0;        //通过LED显示中断发生,并执行中断服务函数
		}
}

        程序的主函数如下,其中for循环的功能是实现延时,即增加函数运行一次的时长,所以for语句是没有实际作用的,因此循环体是空语句。

 int main(void)
 {	
	 int i;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置优先级分组
	LED_Init();		                                   //初始化LED 	
	TIM3_Int_Init(4999,7199);
  for(i=0;i<10000000000;i++)                            //实现延时
	 {
	 };
}

        通过上述代码的组合,我们就可以完成在一定的时间间隔内,通过定时器产生中断,由硬件调用中断服务函数的操作了。

        怎么样,没想到吧,定时器还能这么用,其实定时器不仅可以产生中断,在我们的操作系统的某些进行调度算法也用到了定时器。怎么样,你学废了没?下篇文章见!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值