think_a_second 发表于 2012-3-29 10:17:45

[分享]我山寨的定时器microtimer,用于少于tick的定时。欢迎拍

本帖最后由 think_a_second 于 2012-3-29 10:17 编辑

microtimer.h
#define USING_RT_THREAD
//#define MTIMER_TEST

#define MTIMER_FLAG_DEACTIVATED                0x0                                /* timer is deactive.                                                 */
#define MTIMER_FLAG_ACTIVATED                        0x1                                /* timer is active.                                                 */
#define MTIMER_FLAG_ONE_SHOT                        0x0                                /* one shot timer.                                                         */
#define MTIMER_FLAG_PERIODIC                        0x2                                /* periodic timer.                                                         */

#define MAX_MTIMER 3
#define MAX_MTIMER_NAME 8
#define MT_FULL 0xff
#define MT_NULL   ((void *)0)

#define MT_US 100

typedef struct mtimer* mtimer_t;
struct mtimer
{
        //charname;
        char flag;
        void (*timeout_func)(void* parameter);                                /* timeout function.                                                 */
        void *parameter;                                                                        /* timeout function's parameter.                         */

        unsigned long init_tick;                                                                /* timer timeout tick.                                                 */
        unsigned long timeout_tick;                                                                /* timeout tick.                                                         */
};
typedef unsigned long mtimer_app_t;


//不会检测name长度,所以没用name操作,直接用index操作
mtimer_app_tmtimer_create(const char* name,          //暂时无实际作用
                                                   void (*timeout)(void* parameter), void* parameter,
                                                   unsigned long time, char flag);
void mtimer_start(mtimer_app_t index);
void mtimer_stop(mtimer_app_t index);
void mtimer_detach(mtimer_app_t index);
unsigned long mtimer_get_run_tick(mtimer_app_t index);
void mtimer_conf(void);         //硬件定时器配置

// <<< Use Configuration Wizard in Context Menu >>>
// <h>Timer Choose

// <o> Default Timerx <0=>TIM2 <1=> TIM3 <2=>TIM4
//        <i>Default: 2
#define MT_TIMERX_VALUE1
#if MT_TIMERX_VALUE==0
#define MT_TIMERX            TIM2
#define MT_TIMERX_IRQN         TIM2_IRQn
#define MT_TIMERX_IRQHandler   TIM2_IRQHandler
#elif MT_TIMERX_VALUE==1
#define MT_TIMERX            TIM3
#define MT_TIMERX_IRQN         TIM3_IRQn
#define MT_TIMERX_IRQHandler   TIM3_IRQHandler
#elif MT_TIMERX_VALUE==2
#define MT_TIMERX            TIM4
#define MT_TIMERX_IRQN         TIM4_IRQn
#define MT_TIMERX_IRQHandler   TIM4_IRQHandler
#endif

// </h>
// <<< Use Configuration Wizard in Context Menu >>>



microtimer.c
/*
* File      : microtimer.c
*用于少于tick的短延时
*参考rt_timer
*
* Change Logs:
* Date         Author       Ver   Notes
* 2011-11-02   DZ          0.1   第一个版本
*/
#ifdef USING_RT_THREAD
#include <rthw.h>
#include <rtthread.h>
#endif

#include "microtimer.h"
#include "stm32f10x.h"

volatile unsigned long mtimer_tick;
struct mtimer mt_array;        //由于只用于少量定时器的场合,不使用链表

//不会检测name长度,所以没用name操作,直接用index操作
mtimer_app_tmtimer_create(const char* name,          //暂时无实际作用
                                                   void (*timeout)(void* parameter), void* parameter,
                                                   unsigned long time, char flag)
{
        char index=0;
        mtimer_t timer;
        for(index=0;index<MAX_MTIMER;index++)
        {
                if(mt_array.flag==MTIMER_FLAG_DEACTIVATED)
                        break;
        }
        if(index==MAX_MTIMER)
                return MT_FULL;//(void*)0!=0
        else if(timeout==MT_NULL)
                return MT_FULL;
        timer = (mtimer_t)&mt_array;
        timer->timeout_func = timeout;
        timer->parameter           = parameter;
        timer->flag = flag;
        timer->timeout_tick        = 0;
        timer->init_tick         = time;
       
        return index;
}
void mtimer_start(mtimer_app_t index)
{
        mtimer_t timer;
        if(index>=MAX_MTIMER)
                return;
        timer = (mtimer_t)&mt_array;
        timer->flag |= MTIMER_FLAG_ACTIVATED;
        timer->timeout_tick = mtimer_tick + timer->init_tick;
}

void mtimer_stop(mtimer_app_t index)
{
        mtimer_t timer;
        if(index>=MAX_MTIMER)
                return;
        timer = (mtimer_t)&mt_array;
        timer->flag &= ~MTIMER_FLAG_ACTIVATED;
}

void mtimer_detach(mtimer_app_t index)
{
        mtimer_t timer;
        if(index>=MAX_MTIMER)
                return;
        timer = (mtimer_t)&mt_array;
        timer->flag = MTIMER_FLAG_DEACTIVATED;
        timer->timeout_func = MT_NULL;
}

static mtimer_isr(void)
{
        char index;
        mtimer_t p;
        mtimer_tick++;
        for(index=0;index<MAX_MTIMER;index++)
        {
                p = (mtimer_t)&mt_array;
                if( (p->flag&MTIMER_FLAG_ACTIVATED) && ((mtimer_tick>=p->timeout_tick)) )
                {
                        if(p->flag&MTIMER_FLAG_PERIODIC)
                                p->timeout_tick = mtimer_tick + p->init_tick;
                        else
                                p->flag &= ~ MTIMER_FLAG_ACTIVATED;
                        p->timeout_func(p->parameter);
                }
        }
}

unsigned long mtimer_get_run_tick(mtimer_app_t index)
{
        unsigned long runtime=0;
        mtimer_t p;
        p = (mtimer_t)&mt_array;
        if(mtimer_tick<p->timeout_tick)
                runtime = p->init_tick - (p->timeout_tick - mtimer_tick);
        //else
        return runtime;               
}

//硬件相关函数
void MT_TIMERX_IRQHandler(void)
{
#ifdef USING_RT_THREAD
        volatile long level;
        /* disable interrupt */
        level = rt_hw_interrupt_disable();
#endif
        if(MT_TIMERX->SR&0X0001)//溢出中断
        {
                mtimer_isr();
        }
        MT_TIMERX->SR&=~(1<<0);//清除中断标志位           

#ifdef USING_RT_THREAD
        /* enable interrupt */
        rt_hw_interrupt_enable(level);
#endif
}
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
void mtimer_conf(void)         //硬件定时器配置
{
        mtimer_tick = 0;

        RCC->APB1ENR|=1<<1;//TIM3时钟使能   
        MT_TIMERX->ARR=MT_US;//设定计数器自动重装值   
        MT_TIMERX->PSC=71;//预分频器72,1us

        MT_TIMERX->DIER|=1<<0;   //允许更新中断                               
        MT_TIMERX->DIER|=1<<6;   //允许触发中断
                                                                            
        MT_TIMERX->CR1|=0x01;    //使能定时器3
        //这里还需要配置定时器中断
}


//测试

#ifdef MTIMER_TEST
mtimer_app_t mt1;


void mt_test_handle(void)
{
        volatile static char i;
        i++;
        if(i%2)
                GPIOC->BSRR = 1;
        else
                GPIOC->BRR = 1;
}
void microtimer_test(void)
{
        mt1 =mtimer_create("mt1",
                                        mt_test_handle, (void*)0,
                                        10000,
                                        MTIMER_FLAG_PERIODIC);
        if(mt1!=MT_FULL)
                mtimer_start(mt1);   
}
#endif //MTIMER_TEST

应用举例
1.485收发切换,发送以后延时几百us到1ms再切换为接收
2.多机通信时,收到数据,要求按站ID*1ms后返回。
初始化
    mtb =mtimer_create("mtb",
                  send_back, (void*)0,    //超时调用send_back
                  10000,
                  MTIMER_FLAG_ONE_SHOT);
收到事件后,调用
   mtimer_stop(mtb );
   mtimer_start(mtb );

3.测试某些外设的运行时间,如测试spi_flash的读写时间
static void flash_read_entry(void *parameter)
{
    mtimer_app_t mtf;
    rt_uint32_t runtime;
    mtf =mtimer_create("mtf",
                  mt_flash_read, (void*)0, //mt_flash_read里并没实质内容
                  10000,//设一个较大的值,让它不超时
                  MTIMER_FLAG_ONE_SHOT);
    while(1)
    {
      mtimer_start(mtf);
      sst25_test();
      runtime = mtimer_get_run_tick(mtf);
      rt_kprintf("runtime %d\n", runtime);
      mtimer_stop(mtf);
      rt_thread_delay(RT_TICK_PER_SECOND*5);
    }
}

32446975 发表于 2013-7-7 22:37:03

RTT定时器的修改版.
如果同时运行几十个(如20个多个)定时器,可能处理不过来吧.
页: [1]
查看完整版本: [分享]我山寨的定时器microtimer,用于少于tick的定时。欢迎拍