打印
[应用相关]

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

[复制链接]
650|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32F4或者STM32F7有2个32位定时器,非常适合用来做高精度的时间测量,既可以保证精度,又可以保证量程,测试使用定时器5(32位定时器),实现1us精度的时间测量,函数格式类似于StopWatch类。

/*************************************************************************************************************
* 文件名                :        StopWatch.c
* 功能                        :        计时器
* 作者                        :        cp1300@139.com
* 创建时间                :        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
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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)
* 功能                        :        计时器初始化(会初始化定时器,并将定时器启动)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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:计数句柄
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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:计数句柄
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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:计数句柄
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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:计数句柄
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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:计数句柄
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2020-02-09
* 最后修改时间         :         2020-02-09
* 说明                        :        
*************************************************************************************************************************/
static u64 StopWatch_GetElapsedUs(STOP_WATCH_HANDLE *pHandle)
{
        return pHandle->ElapsedUs;               
}


/*************************************************************************************************************************
* 函数                        :        static void StopWatch_Init(void)
* 功能                        :        关闭全局计时器工具,会停止定时器,降低功耗
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        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;                                //清除中断标志位-退出前再清除一次
}


使用特权

评论回复
沙发
guanjiaer|  楼主 | 2021-8-2 11:11 | 只看该作者
/*************************************************************************************************************
* 文件名                :        StopWatch.h
* 功能                        :        计时器
* 作者                        :        cp1300@139.com
* 创建时间                :        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_



使用特权

评论回复
板凳
guanjiaer|  楼主 | 2021-8-2 11:13 | 只看该作者
//测试代码

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));
        }


使用特权

评论回复
地板
guanjiaer|  楼主 | 2021-8-2 11:15 | 只看该作者

测试结果


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

4116

帖子

2

粉丝