1说明
实现一个了软件定时器,在32位平台下均可运行,采用数组法和链表法实现,各有优劣(数组法运行较快,但是数组大小固定,链表法运行较慢,但是支持创建任意数量的软件定时器)
2代码展示
my_softtimer.c
#include "my_softtimer.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
static pMY_SOFT_TIMER g_timer_list = NULL; //链表
static pMY_SOFT_TIMER g_head = NULL; //链表头
#endif
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
static MY_SOFT_TIMER g_time_array[MAX_TIMER_NUM];//定义定时器数组,最大为MY_SOFT_TIMER
#endif
/*定时器系统计数*/
static volatile TIM_U32_TYPE sys_cnt = 0;
/*定时器源 1ms级别*/
void soft_timer_source_tick(void)
{
sys_cnt++;
}
/*软件定时器初始化*/
void soft_timer_init(void)
{
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
g_head = malloc(sizeof(MY_SOFT_TIMER));
g_head->pNext = NULL;
g_timer_list = g_head;
#elif (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
memset(g_time_array,0,sizeof(g_time_array));
#endif
}
/*添加一个定时器*/
char* soft_timer_add(MY_TIMER_CB timer_cb,TIM_U32_TYPE t_ms,char *name)
{
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
//指针头插法
pMY_SOFT_TIMER pt = malloc(sizeof(MY_SOFT_TIMER));
pt->pNext = g_head->pNext;
g_head->pNext = pt;
//赋值
strcpy(pt->name,name);
pt->timr_cb = timer_cb;
pt->par_cnt = t_ms;
pt->cur_cnt = sys_cnt;
pt->set_cnt = sys_cnt + t_ms;
pt->sta = TIMER_RUN;
#elif (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
TIM_S16_TYPE idx = -1;
for(TIM_S16_TYPE i = 0;i<MAX_TIMER_NUM;i++)//寻找数组内的空位
{
if(TIMER_STOP == g_time_array[i].sta)
{
idx = i; //记录数组内空位
break;
}
}
if(idx == -1)
{
//无空位了
return NULL;
}
//赋值操作
strcpy(g_time_array[idx].name,name);
g_time_array[idx].timr_cb = timer_cb;
g_time_array[idx].par_cnt = t_ms;
g_time_array[idx].cur_cnt = sys_cnt;
g_time_array[idx].set_cnt = sys_cnt + t_ms;
g_time_array[idx].sta = TIMER_RUN;
#endif
return name;
}
/*删除一个定时器*/
TIM_S16_TYPE soft_timer_delete_by_name(char *name)
{
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
pMY_SOFT_TIMER ptmp = g_head->pNext;
pMY_SOFT_TIMER pfont= g_head;
while(ptmp)
{
if(0 == strcmp(name,ptmp->name))
{
break;
}
pfont = ptmp;
ptmp = ptmp->pNext;
}
//不存在该名字定时器
if(!ptmp)
{
printf("can't find this node\r\n");
return -1;
}
//找到,删除该节点
pfont->pNext = ptmp->pNext;
//释放该节点
if(ptmp)
{
free(ptmp);
}
return 0;
#elif (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
for(TIM_S16_TYPE i = 0;i<MAX_TIMER_NUM;i++)
{
if(0 == strcmp(name,g_time_array[i].name))
{
memset(&g_time_array[i],0,sizeof(MY_SOFT_TIMER));
return 0;
}
}
return -1;
#endif
}
/*定时器轮询*/
void soft_timer_polling(void)
{
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST
pMY_SOFT_TIMER ptmp = g_timer_list->pNext;
#elif (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
pMY_SOFT_TIMER ptmp = g_time_array;
#endif
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
while(ptmp){
#elif (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
for(TIM_S16_TYPE i=0;i<MAX_TIMER_NUM;i++)
{
ptmp = &g_time_array[i];
#endif
switch(ptmp->sta)
{
case TIMER_STOP: //处于停止状态
{
/*
暂时不做事情
*/
}break;
case TIMER_RUN: //处于计数状态
{
//数据未发生溢出
if((ptmp->set_cnt) > (ptmp->cur_cnt)) //设定值期望>设定记录值
{
if(sys_cnt > (ptmp->set_cnt))
{
ptmp->sta = TIMER_OVER_FLOW;
}
}
else
{
printf("发生数据溢出====================================\r\n");
if((sys_cnt+ptmp->cur_cnt) > (ptmp->set_cnt))
{
ptmp->sta = TIMER_OVER_FLOW;
}
}
}break;
case TIMER_OVER_FLOW://处于溢出状态
{
TIM_S16_TYPE ret = ptmp->timr_cb(NULL);
if(ret >= 0) //返回值>0,继续下一次
{
ptmp->sta = TIMER_RUN;
//赋值
ptmp->cur_cnt = sys_cnt;
ptmp->set_cnt = sys_cnt + ptmp->par_cnt;
}
else //只运行一次
{
ptmp->sta = TIMER_STOP;
soft_timer_delete_by_name(ptmp->name);
}
}break;
default :{}break;
}
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
ptmp = ptmp->pNext;//指向下一个
#endif
}
}
/*链表遍历打印*/
void list_printf_test(void)
{
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
pMY_SOFT_TIMER ptmp = g_timer_list->pNext;
while(ptmp)
{
printf("Ttem name %s,address 0x%p\r\n",ptmp->name,ptmp);
ptmp = ptmp->pNext;
}
#elif (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
#endif
}
my_softtimer.h
#ifndef __MY_SOFT_TIMER_H_
#define __MY_SOFT_TIMER_H_
typedef unsigned int TIM_U32_TYPE;
typedef unsigned short TIM_U16_TYPE;
typedef int TIM_S32_TYPE;
typedef short TIM_S16_TYPE;
#define SOFT_TIMER_BY_LIST 1
#define SOFT_TIMER_BY_ARRAY 2
//定时器方式选择,推荐使用数组法
#define SOFT_TIMER_TYPE SOFT_TIMER_BY_ARRAY
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_ARRAY)
//最大支持多少个软件定时器
#define MAX_TIMER_NUM 5
#endif
#define MAX_CNT 4294967295UL
//声明定时器回调函数的类型
typedef TIM_S16_TYPE (*MY_TIMER_CB)(char *arg);
typedef enum TIMER_STA{
TIMER_STOP = 0,
TIMER_RUN = 1,
TIMER_OVER_FLOW = 2,
}TIMER_STA;
typedef struct MY_SOFT_TIMER{
char name[10]; //名字,句柄
TIM_U32_TYPE par_cnt; //传入值
TIM_U32_TYPE cur_cnt; //当前值
TIM_U32_TYPE set_cnt; //期望值
TIMER_STA sta; //状态值
MY_TIMER_CB timr_cb; //执行回调
#if (SOFT_TIMER_TYPE == SOFT_TIMER_BY_LIST)
struct MY_SOFT_TIMER *pNext;
#endif
}MY_SOFT_TIMER,*pMY_SOFT_TIMER;
void soft_timer_source_tick(void);
void soft_timer_init(void);
char* soft_timer_add(MY_TIMER_CB timer_cb,TIM_U32_TYPE t_ms,char *name);
TIM_S16_TYPE soft_timer_delete_by_name(char *name);
void soft_timer_polling(void);
#endif
3代码移植说明
作者:lin ying wei
版本:V1.0 2022.8.24
移植系统说明:
(1)将soft_timer_source_tick(); 放置在1ms的定时器硬件中断内
(2)将soft_timer_polling(); 函数放置在死循环体内(不能被阻塞)
(3)soft_timer_add(); 添加一个定时器
(4)soft_timer_delete_by_name(); 删除一个定时器
(5)soft_timer_init(); 参数初始化
(6)系统必须能提供32位的无符号变量类型
(7)需要提供几个变量类型
使用说明:
(1)本文件提供了数组法和链表法,建议使用数组法
使用样例:
(1)
void Timer_1ms_ServelFun(void)
{
soft_timer_source_tick();
}
TIM_S16_TYPE led1(char *arg)
{
printf(“This is led1\r\n”);
return 0;
}
TIM_S16_TYPE led2(char *arg)
{
printf(“This is led2\r\n”);
return 0;
}
TIM_S16_TYPE main(void)
{
other_init();//伪代码
soft_timer_init();
soft_timer_add(led1,1000,“led1”); //注册1s的调用回调函数
soft_timer_add(led1,1000,“led2”);
while(1)
{
soft_timer_polling();
}
}
4申明
如有BUG欢迎大家指正