1.什么是软件定时器
软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需要使用较多定时器的时候就不会受限于硬件资源的不足,这是软件定时器的一个优点,即数量不受限制。但由于软件定时器是通过程序实现的,其运行和维护都需要耗费一定的CPU资源,同时精度也相对硬件定时器要差一些
2.声明文件
/*
* @Descripttion:
* @version: V0.1
* @Author: Kris
* @Date: 2020
* @LastEditors: Kris
* @LastEditTime: 2020
*/
#include "gd32e23x.h"
#include "main.h"
#define TIMER_NUM_MAX 10
//创建的定时器id号
typedef enum{
TMR_STRING_PRINT = 0,
TMR_TWINKLING,
}tim_mode_t;
typedef void (*callback_t)(void *argv, uint16_t argc);
/**
* @brief:定时器运行状态
*/
typedef enum
{
SOFT_TIMER_STOP = 0, //停止
SOFT_TIMER_RUNNING, //运行
SOFT_TIMER_TIMEOUT //超时
}tmrState_t;
/**
* @brief:定时器运行模式
*/
typedef enum
{
MODE_ONE_SHOT = 0, //单次模式
MODE_PERIODIC, //周期模式
}tmrMode_t;
/**
* @brief:软件定时器的结构
*/
typedef struct
{
char name[12]; //名字最大12个字节
tmrState_t state; //状态
tmrMode_t mode; //模式
uint32_t match; //到期时间
uint32_t period; //定时周期
callback_t cb; //回调函数指针
void *argv; //参数指针
uint16_t argc; //参数个数
}softTimer_t;
//软件定时器所有函数入口
struct soft_timer_t
{
const uint8_t * const pre_num_of_sft;
uint8_t (*creat_start)(char *, uint8_t , tmrMode_t , uint32_t , callback_t , void *, uint16_t);
void (*stop)(char* );
void (*reply)(char* );
tmrState_t (* get_status)(char* );
void (*updata)(void );
uint32_t (*get_time)(void);
};
extern struct soft_timer_t g_soft_timer;
extern uint8_t g_softTimer_creat_start(char *name, uint8_t id,tmrMode_t mode, uint32_t time, callback_t cb, void *argv, uint16_t argc);
#if 0
extern void g_softTimer_Update(void);
extern void g_softTimer_reply(char *name);
extern void g_softTimer_Stop(char *name);
extern tmrState_t g_softTimer_GetState(char *name);
#endif
PS:获取的时间在函数systick中计数,通过***g_get_systickcnt()***获取当前的计时
static volatile uint16_t systick_Cnt;
static volatile uint32_t systick_cnt = 0;
void SysTick_Handler(void)
{//1m-ssystick中断
delay_decrement();
systick_Cnt++;
if(systick_Cnt >= 50)//50ms
{
systick_Cnt = 0;
systick_cnt++;
}
}
//获取当前softtime全局值
uint32_t g_get_systickcnt(void)
{
return systick_cnt;//g_tim13_cnt;
}
3.源文件
由于有单次定时中断的软件定时器,如果单次检测结束会一直占用堆栈内存,因此就此添加了单次软件定时结束后自动删除当前的单次软件定时器,增加定时器软件定时的效率.
/*
* @Descripttion:
* @version: V0.1
* @Author: Kris
* @Date: 2020
* @LastEditors: Kris
* @LastEditTime: 2020
*/
static softTimer_t softTimer[TIMER_NUM_MAX];//软件定时器数组
static uint8_t present_tim_num = 0; //当前软件定时器个数
/**
* @name: softTimer_creat_start
* @brief: 创建并启动一个定时器
* @param {name:定时器的名字标识符,可以通过name定位到哪一个软件定时器
* id:当前没有用
* mode:设备模式,单次还是周期
* time:软件定时器中断时长 基准为50ms 最小软件定时器50 delay
* cb:回调函数处理
* argv:回调函数的参数 没有就是NULL
* argc:回调函数的参数 没有就是null
* @return: 当前软件定时器数量
*/
uint8_t g_softTimer_creat_start( char *name,
uint8_t id,
tmrMode_t mode,
uint32_t time,
callback_t cb,
void *argv,
uint16_t argc)
{
//assert_param(id < TIMER_NUM_MAX);
//assert_param(mode == MODE_ONE_SHOT || mode == MODE_PERIODIC);
if((present_tim_num > TIMER_NUM_MAX) || (strlen(name) > 12) || (time < 50))
{
printf("Softtime creat error!\r\n");
return present_tim_num;
}
for(size_t i = 0;i < present_tim_num;i++)
{
if(0 == strcmp(softTimer[id].name,name))
{
printf("Already hava same name time,please change name!\r\n");
return present_tim_num;
}
}
present_tim_num ++;
id = present_tim_num -1;
memcpy(&softTimer[id].name,name,strlen(name));
softTimer[id].match = g_get_systickcnt() + time/50;
softTimer[id].period = time/50;
softTimer[id].state = SOFT_TIMER_RUNNING;
softTimer[id].mode = mode;
softTimer[id].cb = cb;
softTimer[id].argv = argv;
softTimer[id].argc = argc;
return present_tim_num;
}
/**
* @name: softTimer_stop
* @brief: //停止定时器计时
* @param {name:具体的那个一软件定时器}
* @return: NULL
*/
static void softTimer_stop(char *name)
{
//assert_param(id < TIMER_NUM_MAX);
for(size_t i=0;i<present_tim_num;i++)
{
if(0 == strcmp(softTimer[i].name,name))
{
softTimer[i].state = SOFT_TIMER_STOP;
break;
}
else
{
//printf("name no match or the time already delete in list\r\n");
}
}
}
/**
* @name: softTimer_reply
* @brief: //恢复定时器计时 只能回复周期定时器
* @param {name:具体的那个一软件定时器}
* @return: NULL
*/
static void softTimer_reply(char *name)
{
//assert_param(id < TIMER_NUM_MAX);
for(size_t i=0;i<present_tim_num;i++)
{
if(0 == strcmp(softTimer[i].name,name))
{
softTimer[i].state = SOFT_TIMER_RUNNING;
softTimer[i].match = g_get_systickcnt() + softTimer[i].period;
break;
}
}
}
/**
* @name: softTimer_getstate
* @brief: 获取定时器状态
* @param {name:具体的那个一软件定时器}
* @return: NULL
*/
static tmrState_t softTimer_getstate(char *name)
{
uint8_t i;
for (i=0;i<present_tim_num;i++)
{
if(0 == strcmp(softTimer[i].name,name))
{
printf("123123\r\n");
break;
}
}
return softTimer[i].state;
}
//更新定时器值
static void softTimer_update(void)
{
uint8_t i;
uint8_t tempbuf[10] = {0,};//buf是存下标,表明哪一个定时器已经定时结束,
uint8_t already_subscript = 0;//
for(i=0; i<present_tim_num; i++)
{
switch (softTimer[i].state)
{
case SOFT_TIMER_STOP:
if(softTimer[i].mode == MODE_ONE_SHOT)
{//单侧定时中断结束
uint8_t tempbuf_value;
already_subscript++;
tempbuf[already_subscript] = i;
//定时器下标比较前后
if(tempbuf[already_subscript] < tempbuf[already_subscript-1])
{
tempbuf_value = tempbuf[already_subscript - 1];
tempbuf[already_subscript - 1] = tempbuf[already_subscript];
tempbuf[already_subscript] = tempbuf_value;
}
}
break;
case SOFT_TIMER_RUNNING:
if(softTimer[i].match <= g_get_systickcnt())
{
softTimer[i].state = SOFT_TIMER_TIMEOUT;
softTimer[i].cb(softTimer[i].argv, softTimer[i].argc); //执行回调函数
}
break;
case SOFT_TIMER_TIMEOUT:
if(softTimer[i].mode == MODE_ONE_SHOT)
{
softTimer[i].state = SOFT_TIMER_STOP;
}
else
{
softTimer[i].match = g_get_systickcnt() + softTimer[i].period;
softTimer[i].state = SOFT_TIMER_RUNNING;
//periodcnt++;
}
break;
default:
printf("timer[%d] state error!\r\n", i);
break;
}
}
if(already_subscript == 0)
return;
if( already_subscript == present_tim_num)
{
memset(&softTimer[0].name,0,12);
present_tim_num = 0;
return;
}
for(i = 0;i<already_subscript;i++)//循环次数
{
for(size_t start = tempbuf[already_subscript - i];start <= (present_tim_num - (tempbuf[already_subscript]+1));start++)
{//起始位置为tempbuf中最后面的值,循环次数为当前软件定时器总数量-当前位置的下标(下标从0开始)
memcpy(&softTimer[start],&softTimer[start+1],sizeof(softTimer_t));
}
}
memset(&softTimer[present_tim_num-1].name,0,12);
present_tim_num -= already_subscript;
}
//软件定时器入口
struct soft_timer_t g_soft_timer =
{
&present_tim_num,
g_softTimer_creat_start,
softTimer_stop,
softTimer_reply,
softTimer_getstate,
softTimer_update,
g_get_systickcnt,
};
之后 可以在main函数里面循环调用updata函数,单次函数单次中断结束就不再运行,周期软件定时器进行周期定时中断
void stringPrint(void *argv, uint16_t argc)
{
printf("111TEST\r\n");
}
void stringPrint111(void *argv, uint16_t argc)
{
printf("222TEST\r\n");
}
void test_tt1(void *argv, uint16_t argc)
{
printf("TTT111\r\n");
}
void test_tt2(void *argv, uint16_t argc)
{
printf("TTT222\r\n");
}
void LED0_Twinkling(void *argv, uint16_t argc)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
printf("TEST.\r\n");
}
int main(void)
{
/*
*初始化函数
*/
//创建3个软件定时器
g_softTimer_creat_start("POWERON", 0, MODE_ONE_SHOT, 1000, LED0_Twinkling, NULL, NULL);
g_softTimer_creat_start("ADCCHECK", 0, MODE_PERIODIC, 5000, stringPrint111, NULL, NULL);
g_softTimer_creat_start("test1", 0, MODE_ONE_SHOT, 2000, test_tt1, NULL, NULL);
g_softTimer_creat_start("221", 0, MODE_PERIODIC, 2500, test_tt2, NULL, NULL);
for(;;)
{
g_soft_timer.updata();
}
}