软件定时器实现源码

原理:软件定时器的原理其实很简单,就是在启动定时器的时候获取当前系统的时间戳start_ts,然后用start_ts加上要定时的时间dly_ts(timeout= start_ts + dly_ts),在心跳定时器中断中查询当前时间计数值(时间戳),如果查询到的计数值大于timeout,说明定时时间到,并调用回调函数执行操作。

资源:1个硬件定时器,用作心跳时钟

下面我们来实现一个简单的基于裸机(不带操作系统)的软件定时器设施,共实现了6个基本接口,设计中没有使用时间轮盘的算法,软件用指针数组代替了需要动态分配内存的列表,从而简化了定时器的实现,定时器的数量可通过调整数组列表的长度来实现,默认最大支持5个软定时器。启动定时器时把定时器指针加入到数组,停止定时器时把定时器对应的指针设定为NULL。


一、timer.h

/**
  ******************************************************************************
  *  File Name              : timer.h
  *  Describe               :
  *  Created                : 09/10/2016
  ******************************************************************************
  */

#ifndef _I_TIMER_H
#define _I_TIMER_H

#include "stddef.h"
#include "stdint.h"

typedef void   (*tmr_fnct_ptr) (void);
typedef uint8_t TMR_STATE;



typedef struct{
	uint32_t		expire;					/* 定时器到期时间             */
    uint32_t        period;
	tmr_fnct_ptr	callback;				/* 回调函数					  */
	TMR_STATE		state;					/* 定时器状态				  */
	uint32_t		opt;					/* 操作类型        			  */
}timer_t;


#define   TIMER_LIST_MAX		5U		/* 计时器列表大小,支持5个软件定时器 */
 

/* timer state */
#define  TMR_STATE_UNUSED                    (TMR_STATE)(0u)
#define  TMR_STATE_STOPPED                   (TMR_STATE)(1u)
#define  TMR_STATE_RUNNING                   (TMR_STATE)(2u)
#define  TMR_STATE_COMPLETED                 (TMR_STATE)(3u)

#define  OPT_TMR_NONE                        (0u)  /* No option selected                                 */

#define  OPT_TMR_ONE_SHOT                    (1u)  /* Timer will not auto restart when it expires        */
#define  OPT_TMR_PERIODIC                    (2u)  /* Timer will     auto restart when it expires        */






void timer_init(void);

uint8_t timer_create(timer_t   		*ptimer,	/* point to timer_t */
					 uint32_t  		period,		/* period			*/
					 uint32_t  		opt,
					 tmr_fnct_ptr	pcallback);

uint8_t timer_del(timer_t *ptimer);
uint8_t timer_start(timer_t *ptimer);
uint8_t timer_cancel(timer_t *ptimer);

void timer_task(void);



#endif

二、timer.c

/**
  ******************************************************************************
  *  File Name              :  timer.c
  *  Describe               :
  *  Created                :
  ******************************************************************************
  */



#include "timer.h"



/* timer list(arry) */
static timer_t		*timer_list[TIMER_LIST_MAX] = {NULL};
static uint8_t		timer_count = 0; /* 已经使用的软件计时器数量,取值范围0...TIMER_LIST_MAX */
static uint32_t     timer_tick;      /* 软件计时器时基,表示1个timer_tick代表多少时间,这里为10ms */


/* privat prototype **************************************/
static void timer_cleanup(timer_t *ptimer);
static uint8_t timer_link(timer_t *ptimer);
static uint8_t timer_unlink(timer_t *ptimer);





/**************** public function implement ***********************************/
/*
 * 初始化软件计时器,
 */
void timer_init(void)
{
    for(uint8_t i=0;iexpire)
        {
            if(ptmr->callback != NULL){
                ptmr->callback();
            }
            
            if(ptmr->opt == OPT_TMR_PERIODIC){
                //timer_link(timer_list[i]);
				ptmr->expire = timer_tick + ptmr->period;
            }else{
                ptmr->state = TMR_STATE_COMPLETED;
                timer_unlink(timer_list[i]);
            }
        }
    }
}


/* initalize timer,1:OK ; 0: fail   
 * 创建1个计时器,该操作分配一个软件计时器结构,任何企图安装软件计时器的
 * 的软件模块必须首先创建一个计时器结构。计时器结构包含允许更改计时器处理
 * 设施和超过软件计时器的控制信息。此操作创立的计时器将引用到软件计时器列
 * 表的一个入口
 */
uint8_t timer_create(timer_t   		*ptimer,	/* point to timer_t */
					 uint32_t  		period,		/* period			*/
					 uint32_t  		opt,
					 tmr_fnct_ptr	pcallback)
{
	if(!ptimer)
		return  0;
	
	ptimer->expire   = 0;
    ptimer->period   = period;
	ptimer->opt      = opt;
	ptimer->callback = pcallback;
	ptimer->state    = TMR_STATE_STOPPED;
	
	return 1;
}
					 
/* 
 * 删除一个计时器。此操作删除先前创立的软件计时器,释放计时器结构占据的内存。
 * 1:成功;0:失败
 */
uint8_t timer_del(timer_t *ptimer)
{
	if(!ptimer)
		return 0;
	timer_cleanup(ptimer);
	ptimer = NULL;
	
	return 1;
}


/*
 * 启动一个计时器。该操作安装一个先前创立的软件计时器到计时器处理设施中
 * 计时器在此操作完成后开始运行
 */
uint8_t timer_start(timer_t *ptimer)
{
    if(!ptimer)
        return 0;
    
    switch(ptimer->state)
    {
    case TMR_STATE_RUNNING:
        timer_unlink(ptimer);
        timer_link(ptimer);
        return 1;
    case TMR_STATE_STOPPED:
    case TMR_STATE_COMPLETED:
        timer_link(ptimer);
        return 1;
    case TMR_STATE_UNUSED:
        return 0;
    default:
        return 0;
    }
}


/* 取消当前运行的计时。此操作通过从计时器处理设施中删除当前运行的计时器,
 * 取消一个计时器,把timer_id指向的列表项设置为NULL
 */
uint8_t timer_cancel(timer_t *ptimer)
{
    if(!ptimer)
        return 0;
    
   return timer_unlink(ptimer);
}




/* static function implement **************************************/
static void timer_cleanup(timer_t *ptimer)
{
	if(!ptimer)
		return;
	ptimer->state    = TMR_STATE_UNUSED;
	ptimer->callback = NULL;
	ptimer->expire   = 0;
	ptimer->opt      = 0;
}


static uint8_t timer_link(timer_t *ptimer)
{
	uint8_t i;
	
	if(!ptimer)
		return 0;
	
	if(timer_count >= TIMER_LIST_MAX)
		return 0;
	
	for(i=0;istate  = TMR_STATE_RUNNING;
        ptimer->expire = ptimer->period + timer_tick;
        timer_list[i]  = ptimer;
        timer_count++;
        return 1;
	}
    
    return 0;
}


static uint8_t timer_unlink(timer_t *ptimer)
{
    uint8_t i;
    
    if(!ptimer)
        return 0;
    
    for(i=0;istate = TMR_STATE_STOPPED;
        timer_count--;
        return 1;
    }
    return 0;
}



三、hal_tick.h

/**
  ******************************************************************************
  * File Name          : hal_tick.h
  * Description        : 
  ******************************************************************************
  */


#ifndef  HAL_TICK_H
#define  HAL_TICK_H



#include "stm32f1xx.h"

   
#define TIM_MST             TIM4
#define TIM_MST_IRQ         TIM4_IRQn
#define TIM_MST_RCC         __TIM4_CLK_ENABLE()

#define TIM_MST_RESET_ON    __TIM4_FORCE_RESET()
#define TIM_MST_RESET_OFF   __TIM4_RELEASE_RESET()

#define HAL_TICK_DELAY      1000u // 1 ms
#define HAL_HZ				1000000U





void TIM4_IRQHandler(void);
void hal_tick_init( void);

uint32_t us_ticker_read(void);

#endif

四、hal_tick.c

/**
  ******************************************************************************
  * File Name          : hal_tick.c
  * Description        : 
  ******************************************************************************
  */

#include "hal_tick.h"
#include "timer.h"


#define  TIMER_TICK_RATE                      10000U  /* 10ms */

TIM_HandleTypeDef   htim4;
volatile uint32_t   hal_jiffies;
uint8_t             tick_inited = 0;


void TIM4_IRQHandler(void)
{
    // Clear Update interrupt flag
    if (__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE) == SET) {
        __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);
        hal_jiffies++;
        timer_task();               /* soft timer task */
    }    
}


void hal_tick_init( void)
{
    // Enable timer clock
    TIM_MST_RCC;

    // Reset timer
    TIM_MST_RESET_ON;
    TIM_MST_RESET_OFF;

    // Update the SystemCoreClock variable
    SystemCoreClockUpdate();

    htim4.Instance = TIM_MST;
    
    htim4.Init.Period        = TIMER_TICK_RATE;        /* timer tick period 10ms */
    htim4.Init.Prescaler     = (uint32_t)(SystemCoreClock / 1000000) - 1; // 1 us tick
    htim4.Init.ClockDivision = 0;
    htim4.Init.CounterMode   = TIM_COUNTERMODE_UP;
    HAL_TIM_Base_Init(&htim4);

    HAL_NVIC_SetPriority(TIM_MST_IRQ,15,0);
    NVIC_EnableIRQ(TIM_MST_IRQ);

    // Enable interrupts
    __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); // For 32-bit counter
    
    // Enable timer
    HAL_TIM_Base_Start(&htim4);
    
    tick_inited =1;
}


uint32_t us_ticker_read(void)
{
    uint32_t counter, counter2;
    
    if(!tick_inited)
        hal_tick_init();
    
    counter = (uint32_t)(hal_jiffies * TIMER_TICK_RATE);
    counter += TIM_MST->CNT;
    while (1) {
        counter2 = (uint32_t)(hal_jiffies * TIMER_TICK_RATE);
        counter2 += TIM_MST->CNT;
        if (counter2 > counter) {
            break;
        }
        counter = counter2;
    }
    return counter2;    
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章