STM32F4/F7 32位定时器实现的 计时器 StopWatch

STM32F4或者STM32F7有2个32位定时器,非常适合用来做高精度的时间测量,既可以保证精度,又可以保证量程,测试使用定时器5(32位定时器),实现1us精度的时间测量,函数格式类似于StopWatch类。

/*************************************************************************************************************
 * 文件名		:	StopWatch.c
 * 功能			:	计时器
 * 作者			:	[email protected]
 * 创建时间		:	2020-02-09
 * 最后修改时间	:	2020-02-09
 * 详细:			通过32位的定时器5实现计时器功能,计时分辨率为1us;TIM5的时钟为APB1的时钟的两倍。
*************************************************************************************************************/	
#include "StopWatch.h"
#include "system.h" 

/******************************************************************************/
//定时器硬件设置
#define STOP_WATCH_TIMx				TIM5				//定时器设置,只能使用定时器2或定时器5,这2个定时器是32位的
#define STOP_WATCH_TIM_DEV			DEV_TIM5			//定时器的时钟使能设备选择
#define STOP_WATCH_TIM_IRQHandler	TIM5_IRQHandler		//定时器中断服务选择
#define STOP_WATCH_NVIC_IRQn		IRQ_TIM5			//NVIC中断位置
/******************************************************************************/

static u32 g_StopWatchCycleCount = 0;					//定时器周期计数器,在定时器的溢出中断中进行计数,一个周期为4000秒
#define STOP_WATCH_CYCLE	4000000000					//单位us,4000秒

//内部函数接口
static u32 StopWatch_GetTimeClockSpeed(void);					//获取TIM2或TIM5的时钟速度
static void StopWatch_Init(void);								//计时器初始化(会初始化定时器,并将定时器启动)
static void StopWatch_Start(STOP_WATCH_HANDLE *pHandle);		//开始计数,记录开始值
static void StopWatch_Stop(STOP_WATCH_HANDLE *pHandle);			//停止计数,记录结束值
static void StopWatch_Restart(STOP_WATCH_HANDLE *pHandle);		//复位开始于结束值为0
static u32 StopWatch_GetElapsedMs(STOP_WATCH_HANDLE *pHandle);	//获取过去的时间值,单位ms
static u64 StopWatch_GetElapsedUs(STOP_WATCH_HANDLE *pHandle);	//获取过去的时间值,单位us
static void StopWatch_Close(void);								//关闭全局计时器工具,会停止定时器,降低功耗




//定义一个全局的计时器工具
STOP_WATCH_TYPE g_mStopWatchClass = 							
{
	StopWatch_Init,										//计时器初始化(会初始化定时器,并将定时器启动)
	StopWatch_Start,									//开始计数,记录开始值
	StopWatch_Stop,										//停止计数,记录结束值
	StopWatch_Restart,									//复位开始于结束值为0
	StopWatch_GetElapsedMs,								//获取过去的时间值,单位ms
	StopWatch_GetElapsedUs,								//获取过去的时间值,单位us
	StopWatch_Close,									//关闭全局计时器工具,会停止定时器,降低功耗
};



/*************************************************************************************************************************
* 函数			:	static u32 StopWatch_GetTimeClockSpeed(void)
* 功能			:	获取TIM2或TIM5的时钟速度
* 参数			:	无
* 返回			:	定时器时钟频率,单位Hz
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	当APB1和APB2分频数为1的时候,TIM1、TIM8~TIM11的时钟为APB2的时钟,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟;
					而如果APB1和APB2分频数不为1,那么TIM1、TIM8~TIM11的时钟为APB2的时钟的两倍,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍
*************************************************************************************************************************/
static u32 StopWatch_GetTimeClockSpeed(void)
{
	u32 clock = 0;
	u8 PPRE;
	
	PPRE = (RCC->CFGR>>10)&0X7;	//获取PPRE1 分频值
	if(PPRE == 0)				//分频数位0,直接等于APB1时钟
	{
		clock = SYS_GetAPB1ClockSpeed();
	}
	else 						//分频数不为1,时钟为APB1的2倍
	{
		clock = SYS_GetAPB1ClockSpeed()*2;
	}
	
	return clock;
}


/*************************************************************************************************************************
* 函数			:	static void StopWatch_Init(void)
* 功能			:	计时器初始化(会初始化定时器,并将定时器启动)
* 参数			:	无
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static void StopWatch_Init(void)
{
	u32 psc;
	
	if (((u32)STOP_WATCH_TIMx)!=((u32)TIM2) && ((u32)STOP_WATCH_TIMx) != ((u32)TIM5))
	{
		DEBUG("StopWatch初始化失败,无效的定时器!\r\n");
		return;
	}
	psc = StopWatch_GetTimeClockSpeed();					//获取定时器时钟频率,设置定时器分频,时钟为1MHz
	psc /= 1000000;
	SYS_DeviceClockEnable(STOP_WATCH_TIM_DEV, TRUE);		//使能定时器时钟
	SYS_DeviceReset(STOP_WATCH_TIM_DEV);					//定时器复位
	//初始化配置
	STOP_WATCH_TIMx->CR1 = 0;								//关闭定时器,并复位相关设置,递增计数
	STOP_WATCH_TIMx->CR1 |= BIT2;							//只有溢出才会产生中断
	STOP_WATCH_TIMx->CR2 = 0;								//复位相关设置
	STOP_WATCH_TIMx->PSC = psc-1;							//预分频器设置,输入时钟为1MHz
	STOP_WATCH_TIMx->CNT = 0;								//初值为0
	STOP_WATCH_TIMx->ARR = STOP_WATCH_CYCLE;				//自动重装值 	
	STOP_WATCH_TIMx->CR1 |= BIT7;							//定时器自动重装使能
	//UG重新初始化计数器,并产生一个更新事件。注意预分频器的计数器也被清0(但是预分频系数不变)。
	//若在中心对称模式下或DIR=0(向上计数)则计数器被清0,若DIR=1(向下计数)则计数器取TIMx_ARR的值。
	STOP_WATCH_TIMx->EGR |= BIT0;							//更新UG=1
	STOP_WATCH_TIMx->SR = ~STOP_WATCH_TIMx->SR;				//清除中断标志位
	
	STOP_WATCH_TIMx->DIER |= BIT0;							//更新中断使能
	STOP_WATCH_TIMx->DIER |= BIT6;							//触发中断使能,2个一起设置才能使用中断
	STOP_WATCH_TIMx->SR = 0;								//清除中断
	STOP_WATCH_TIMx->CR1 |= BIT0;    						//使能定时器
	SYS_NVIC_IntEnable(STOP_WATCH_NVIC_IRQn, TRUE);			//开启中断
}

/*************************************************************************************************************************
* 函数			:	static void StopWatch_Start(STOP_WATCH_HANDLE *pHandle)
* 功能			:	开始计数,记录开始值
* 参数			:	pHandle:计数句柄
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static void StopWatch_Start(STOP_WATCH_HANDLE *pHandle)
{
	SYS_DisableIrq();								//临时关闭中断
	pHandle->StartTime = STOP_WATCH_TIMx->CNT;		//获取当前的计数器值
	pHandle->StartTime += g_StopWatchCycleCount;	//加上溢出后的值
	SYS_EnableIrq();								//开启中断
}

/*************************************************************************************************************************
* 函数			:	static void StopWatch_Stop(STOP_WATCH_HANDLE *pHandle)
* 功能			:	停止计数,记录结束值
* 参数			:	pHandle:计数句柄
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static void StopWatch_Stop(STOP_WATCH_HANDLE *pHandle)
{
	SYS_DisableIrq();								//临时关闭中断
	pHandle->StopTime = STOP_WATCH_TIMx->CNT;		//获取当前的计数器值
	pHandle->StopTime += g_StopWatchCycleCount;		//加上溢出后的值
	SYS_EnableIrq();								//开启中断
	
	pHandle->ElapsedUs = pHandle->StopTime - pHandle->StartTime;	//计算时间
}

/*************************************************************************************************************************
* 函数			:	static void StopWatch_Restart(STOP_WATCH_HANDLE *pHandle)
* 功能			:	复位开始于结束值为0
* 参数			:	pHandle:计数句柄
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static void StopWatch_Restart(STOP_WATCH_HANDLE *pHandle)
{
	pHandle->ElapsedUs = 0;		//清除
}

/*************************************************************************************************************************
* 函数			:	static u32 StopWatch_GetElapsedMs(STOP_WATCH_HANDLE *pHandle)
* 功能			:	获取过去的时间值,单位ms
* 参数			:	pHandle:计数句柄
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static u32 StopWatch_GetElapsedMs(STOP_WATCH_HANDLE *pHandle)
{
	return pHandle->ElapsedUs/1000;		
}

/*************************************************************************************************************************
* 函数			:	static u64 StopWatch_GetElapsedUs(STOP_WATCH_HANDLE *pHandle)
* 功能			:	获取过去的时间值,单位us
* 参数			:	pHandle:计数句柄
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static u64 StopWatch_GetElapsedUs(STOP_WATCH_HANDLE *pHandle)
{
	return pHandle->ElapsedUs;		
}


/*************************************************************************************************************************
* 函数			:	static void StopWatch_Init(void)
* 功能			:	关闭全局计时器工具,会停止定时器,降低功耗
* 参数			:	无
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-02-09
* 最后修改时间 	: 	2020-02-09
* 说明			: 	
*************************************************************************************************************************/
static void StopWatch_Close(void)
{
	u32 psc;
	
	if (((u32)STOP_WATCH_TIMx)!=((u32)TIM2) && ((u32)STOP_WATCH_TIMx) != ((u32)TIM5))
	{
		DEBUG("StopWatch关闭失败,无效的定时器!\r\n");
		return;
	}

	SYS_DeviceReset(STOP_WATCH_TIM_DEV);					//定时器复位
	SYS_DeviceClockEnable(STOP_WATCH_TIM_DEV, FALSE);		//关闭定时器时钟
	SYS_NVIC_IntEnable(STOP_WATCH_NVIC_IRQn, FALSE);		//中断关闭
}





//定时器中断处理函数
void STOP_WATCH_TIM_IRQHandler(void)
{
	//uart_printf("中断了 0x%X\r\n", STOP_WATCH_TIMx->SR);	   
	if(STOP_WATCH_TIMx->SR & BIT0)							//溢出中断
	{
		STOP_WATCH_TIMx->SR = 0;							//清除中断标志位 
		g_StopWatchCycleCount += STOP_WATCH_CYCLE;			//溢出一次,计数器增加
						     	    	
	}			   
	STOP_WATCH_TIMx->SR = ~STOP_WATCH_TIMx->SR;				//清除中断标志位-退出前再清除一次
}
/*************************************************************************************************************
 * 文件名		:	StopWatch.h
 * 功能			:	计时器
 * 作者			:	[email protected]
 * 创建时间		:	2020-02-09
 * 最后修改时间	:	2020-02-09
 * 详细:			通过32位的定时器5实现计时器功能,计时分辨率为0.1ms;TIM5的时钟为APB1的时钟的两倍。
*************************************************************************************************************/		
#ifndef __STIP_WATCH_H_
#define __STIP_WATCH_H_
#include "system.h" 

//计时器句柄定义
typedef struct
{
	u64 StartTime;			//启动时的定时器值
	u64 StopTime;			//停止时的定时器值
	u64 ElapsedUs;			//测量的时间,单位us
}STOP_WATCH_HANDLE;

//一个计时器定义(先Restart,再Start,之后Stop,最后调用GetElapsedMs或GetElapsedUs获取Start与Stop之间的时间)
typedef struct
{
	void (*Init)(void);									//初始化全局计时器工具,会初始化定时器,在系统启动时初始化一次即可
	void (*Start)(STOP_WATCH_HANDLE *pHandle);			//开始计数,记录开始值
	void (*Stop)(STOP_WATCH_HANDLE *pHandle);			//停止计数,记录结束值
	void (*Restart)(STOP_WATCH_HANDLE *pHandle);		//复位开始于结束值为0
	u32 (*GetElapsedMs)(STOP_WATCH_HANDLE *pHandle);	//获取过去的时间值,单位ms
	u64 (*GetElapsedUs)(STOP_WATCH_HANDLE *pHandle);	//获取过去的时间值,单位us
	void (*Close)(void);								//关闭全局计时器工具,会停止定时器,降低功耗
}STOP_WATCH_TYPE;


extern STOP_WATCH_TYPE g_mStopWatchClass;				//定义一个全局的计时器工具


#endif //__STIP_WATCH_H_

//测试代码

g_mStopWatchClass.Init();											//计时器初始化

//测试StopWatch,中间是软件延时
	while(1)
	{
		STOP_WATCH_HANDLE mStopWatchHandle;
		
		g_mStopWatchClass.Restart(&mStopWatchHandle);
		g_mStopWatchClass.Start(&mStopWatchHandle);
		SYS_DelayMS(1234);
		g_mStopWatchClass.Stop(&mStopWatchHandle);
		uart_printf("耗时:%lluus %lums\r\n", g_mStopWatchClass.GetElapsedUs(&mStopWatchHandle), g_mStopWatchClass.GetElapsedMs(&mStopWatchHandle));
	}

测试结果

发布了143 篇原创文章 · 获赞 370 · 访问量 81万+

猜你喜欢

转载自blog.csdn.net/cp1300/article/details/104234753
今日推荐