[分享]我山寨的定时器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);
}
}
RTT定时器的修改版.
如果同时运行几十个(如20个多个)定时器,可能处理不过来吧.
页:
[1]