STM32定时器实现计时功能

前言

        本文章使用STM32F103C8T6标准库实现TIM1的定时功能,代码如下:

#include "stm32f10x.h"                  // Device header
#include "led_drv.h"

static void timInit(uint32_t periodUs)
{
	/*使能定时器时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	/*定时器复位*/
	TIM_DeInit(TIM1);
	/*定时器配置*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
	TIM_TimeBaseInitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1;//输入给计数器的时钟频率为1Mhz,周期1us
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = periodUs - 1;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
	TIM_ClearFlag(TIM1, TIM_FLAG_Update);
	/*使能定时器更新中断*/
	TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
	/*NVIC配置*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//一个工程只分组一次
	
	NVIC_InitTypeDef  NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStruct);
	/*定时器使能*/
	TIM_Cmd(TIM1, ENABLE);
	TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
}

/**
***********************************************************
* @brief	定时器驱动初始化
* @param
* @return 
***********************************************************
*/
void TimDrvInit(void)
{
	timInit(1000);
}

/**
***********************************************************
* @brief	定时器1更新中断服务函数
* @param
* @return 
***********************************************************
*/
void TIM1_UP_IRQHandler(void)
{
	if ( TIM_GetITStatus(TIM1, TIM_IT_Update) )
	{
//		static uint32_t s_counter;
//		static uint8_t flipFlag = 1;
//		s_counter ++;
//		if (s_counter >= 1000 && flipFlag)
//		{
//			s_counter = 0;
//			flipFlag = 0;
//			TurnOnLed(LED_BLUE);
//			TurnOnLed(LED_YELLOW);
//			TurnOnLed(LED_WHITE);
//		}
//		else if (s_counter >= 1000 && flipFlag == 0)
//		{
//			s_counter = 0;
//			flipFlag = 1;
//			TurnOffLed(LED_BLUE);
//			TurnOffLed(LED_YELLOW);
//			TurnOffLed(LED_WHITE);
//		}
		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
	}
}

一 基本定时框图

        来自RCC的TIM1CLK的频率是72MHz,PSC预分频器是一个16位的寄存器,所以分频系数可以选择的范围是0~65535,假如设置预分频系数为0,那就是不分频(1分频),CK_CNT == TIM1CLK / 1;假如预分频系数PSC为71, 那就是72分频,CK_CNT == TIM1CLK / 72 == 1MHz。

        CNT计数器是一个周期计数器,CK_CNT每来一个时钟周期就±1,假如CK_CNT == 1MHz,那么周期t = 1/f = 1us,也就是说CNT计数器每计数一次就是1us。

        这时,如果自动重装载寄存器设置为999,那么每1000us即1ms产生一次更新中断,如此实现定时的功能。为什么是999重装值而不是1000呢, 假如我需要4us产生一次中断,那我设置重装寄存器的值为4, 计数器从0-1计数1次, 从1-2计数2次, 从2-3计数3次,从3-4计数4次, 从4-0计数5次,为0产生更新中断,所以需要减1。

 

二 代码实现

2.1 驱动初始化

        只讲一些要点,不逐一进行分析。

        ①TIM_TimeBaseStructInit这个函数是为了对结构体初始化,因为TIM_TimeBaseInitStruct是一个局部变量,我们实现定时器1的定时功能并不会用到它的所有成员,而局部变量不赋初值其值是不确定的,所以需要进行初始化。

        ②SystemCoreClock / 1000000 - 1;使用这个作为预分频系数,假如系统时钟是36MHz,同样得到CK_CNT为1MHz。

        ③TIM_CounterMode_Up为向上计数模式,关于计数模式网上资料很多,可自行查阅。

static void timInit(uint32_t periodUs)
{
	/*使能定时器时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	/*定时器复位*/
	TIM_DeInit(TIM1);
	/*定时器配置*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
	TIM_TimeBaseInitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1;//输入给计数器的时钟频率为1Mhz,周期1us
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = periodUs - 1;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
	TIM_ClearFlag(TIM1, TIM_FLAG_Update);
	/*使能定时器更新中断*/
	TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
	/*NVIC配置*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//一个工程只分组一次
	
	NVIC_InitTypeDef  NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStruct);
	/*定时器使能*/
	TIM_Cmd(TIM1, ENABLE);
	TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
}

 2.2 中断服务函数

        唯一要注意的就是更换定时器后记得更换中断服务函数,进入中断后,不要忘记清除中断标志位。

/**
***********************************************************
* @brief	定时器1更新中断服务函数
* @param
* @return 
***********************************************************
*/
void TIM1_UP_IRQHandler(void)
{
	if ( TIM_GetITStatus(TIM1, TIM_IT_Update) )
	{
		/*实现功能*/
		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值