目录
一、软件定时器功能描述
通用软件定时器是通过一个硬件定时器产生固定的时钟节拍,每次硬件定时器中断时,就对链表中处于运行状态的软件定时器的计数值进行递减,并判断是否递减到0以判断是否超时,如超时则执行相应的回调函数。在执行完超时回调函数后,如该软件定时器模式为单次定时则将定时器状态置为完成状态;如该软件定时器为周期定时则将定时器状态置为运行状态,并重新装载软件定时器的计数值为周期时间,重新开始计数。
二、使用场景
在硬件定时器资源受限,但又有较多任务需要周期处理,对执行周期要求不是很严格的情况下,可以由一个硬件定时器产生固定的时钟节拍,模拟出多个软件定时器来单次或周期性的执行相应的任务,这样就不会受限于硬件资源的不足
三、使用注意事项
1、不要在软件定时器的超时回调函数中做一些耗时的处理,比如延时、多次循环等
2、如果使用了RTOS,并在超时回调函数中调用了RTOS的API,需要注意是否有只能在中断中调用的限制,如FreeRTOS中就有专门在中断中使用的释放信号量、发送消息到消息队列的API
扫描二维码关注公众号,回复:
9399852 查看本文章
3、需要根据硬件定时器周期重新设置软件定时器的时钟节拍
四、数据结构
/* It needs to be modified according to the user's own environment before use !!!!!!!*/
#define SOFT_TIMER_TICK_MS 5
#define SOFT_TIMER_MALLOC(size) pvPortMalloc(size)
#define SOFT_TIMER_FREE(p) vPortFree(p)
/* soft timer unit */
#define SOFT_TIMER_UNIT_MIN 1
#define SOFT_TIMER_UNIT_S 2
#define SOFT_TIMER_UNIT_MS 3
/* soft timer mode */
#define SOFT_TIMER_MODE_UNUSED 0
#define SOFT_TIMER_MODE_SIGLE 1
#define SOFT_TIMER_MODE_RERIOD 2
/* soft timer status */
#define SOFT_TIMER_STATUS_UNUSED 0
#define SOFT_TIMER_STATUS_STOP 1
#define SOFT_TIMER_STATUS_RUNNING 2
#define SOFT_TIMER_STATUS_COMPLETED 3
struct soft_timer
{
struct soft_timer *next; /* timer list */
unsigned char mode; /* timer mode */
unsigned char status; /* timer status */
unsigned char unit; /* set unit:min/s/ms */
unsigned long timeout; /* soft timer period(ms) */
unsigned long count; /* timeout decrement value */
void *param; /* timeout_callback param */
void (*timeout_cb)(void *param);/* timeout_callback */
};
五、操作函数声明
extern struct soft_timer *creat_soft_timer(void);
extern void soft_timer_del (struct soft_timer *this_timer);
extern void soft_timer_start (struct soft_timer *this_timer);
extern void soft_timer_stop (struct soft_timer *this_timer);
extern void soft_timer_reload(struct soft_timer *this_timer);
extern void soft_timer_config(struct soft_timer *this_timer, \
unsigned long timeout, \
unsigned char mode, \
unsigned char unit, \
void *param,\
void (*timeout_cb)(void *param));
extern void soft_timer_set_timeout(struct soft_timer *this_timer, unsigned long timeout);
extern unsigned char get_soft_timer_status(struct soft_timer *this_timer);
extern void soft_timer_exe(void);
六、具体实现
#include <stdlib.h>
#include <stdio.h>
#include "drv_soft_timer.h"
static struct soft_timer *soft_timer_list_head = NULL;/*the head of the soft timer list*/
/**
* dynamically create a soft timer.
*
* @param NONE
* @return NULL:malloc fail
* !NULL:the soft timer
*/
struct soft_timer *creat_soft_timer(void)
{
struct soft_timer *new_timer = NULL;
struct soft_timer *p_timer = NULL;
/* create a new soft timer */
new_timer = SOFT_TIMER_MALLOC(sizeof(struct soft_timer));
/* does the new soft timer created success */
if (new_timer == NULL)
{
return NULL;
}
else
{
new_timer->timeout = 0;
new_timer->count = 0;
new_timer->mode = SOFT_TIMER_MODE_UNUSED;
new_timer->status = SOFT_TIMER_STATUS_UNUSED;
}
/* does the soft timer list already exit */
if (soft_timer_list_head == NULL)
{
new_timer->next = NULL;
soft_timer_list_head = new_timer;
}
else
{
/* add the new soft timer to the end of the soft timer list */
p_timer = soft_timer_list_head;
while(p_timer->next != NULL)
{
p_timer = p_timer->next;
}
new_timer->next = NULL;
p_timer->next = new_timer;
}
return new_timer;
}
/**
* delete a soft timer from the timer list.
*
* @param this_timer:soft timer to be deleted
* @return NONE
*/
void soft_timer_del(struct soft_timer *this_timer)
{
struct soft_timer *cur_timer = soft_timer_list_head;
struct soft_timer *pre_timer = NULL;
/* does this soft timer is vaild */
if (this_timer == NULL)
return;
/* find this timer delete it from timer list */
while (cur_timer != NULL)
{
if (cur_timer == this_timer)
{
/* head node is the find soft timmer */
if (cur_timer == soft_timer_list_head)
soft_timer_list_head = cur_timer->next;
else
pre_timer->next = cur_timer->next;
cur_timer->next = NULL;
SOFT_TIMER_FREE(cur_timer);
cur_timer = NULL;
break;
}
pre_timer = cur_timer;
cur_timer = cur_timer->next;
}
}
/**
* start the soft timer.
*
* @param this_timer:soft timer to start
* @return NONE
*/
void soft_timer_start(struct soft_timer *this_timer)
{
if (this_timer->timeout == 0)
return;
this_timer->status = SOFT_TIMER_STATUS_RUNNING;
this_timer->count = this_timer->timeout;
}
/**
* stop the soft timer.
*
* @param this_timer:soft timer to stop
* @return NONE
*/
void soft_timer_stop(struct soft_timer *this_timer)
{
this_timer->status = SOFT_TIMER_STATUS_STOP;
}
/**
* reload the soft timer.
*
* @param this_timer:soft timer to reload
* @return NONE
*/
void soft_timer_reload(struct soft_timer *this_timer)
{
if (this_timer->timeout == 0)
return;
this_timer->status = SOFT_TIMER_STATUS_RUNNING;
this_timer->count = this_timer->timeout;
}
/**
* config the soft timer.
*
* @param this_timer:soft timer to config
* @param timeout:soft timer period
* @param mode:SOFT_TIMER_MODE_SIGLE SOFT_TIMER_MODE_RERIOD
* @param unit:SOFT_TIMER_UNIT_MIN SOFT_TIMER_UNIT_S SOFT_TIMER_UNIT_MS
* @param param:timeout callback param
* @param timeout_cb:timeout callback
*
* @return NONE
*/
void soft_timer_config(struct soft_timer *this_timer, \
unsigned long timeout, \
unsigned char mode, \
unsigned char unit, \
void *param,\
void (*timeout_cb)(void *param))
{
this_timer->mode = mode;
this_timer->unit = unit;
this_timer->param = param;
this_timer->timeout_cb = timeout_cb;
soft_timer_set_timeout(this_timer, timeout);
}
/**
* set the soft timer timeout.
*
* @param this_timer:soft timer to config
* @param timeout:soft timer period
*
* @return NONE
*/
void soft_timer_set_timeout(struct soft_timer *this_timer, unsigned long timeout)
{
/* since the increments are ms, different units of timing need to be converted to ms */
if (this_timer->unit == SOFT_TIMER_UNIT_MS)
this_timer->timeout = timeout;
else if (this_timer->unit == SOFT_TIMER_UNIT_S)
this_timer->timeout = timeout*1000;
else if (this_timer->unit == SOFT_TIMER_UNIT_MIN)
this_timer->timeout = timeout*60*1000;
}
/**
* get the soft timer status.
*
* @param this_timer:soft timer to get
*
* @return soft timer status
*/
unsigned char get_soft_timer_status(struct soft_timer *this_timer)
{
return this_timer->status;
}
/**
* soft timer execute.
*
* @param NONE
*
* @return NONE
*/
void soft_timer_exe(void)
{
struct soft_timer *p_timer = soft_timer_list_head;
/* effective timer */
while (p_timer != NULL)
{
if (p_timer->status == SOFT_TIMER_STATUS_RUNNING)
{
/* Counting time decrement */
if (p_timer->count < SOFT_TIMER_TICK_MS)
p_timer->count = 0;
else
p_timer->count -= SOFT_TIMER_TICK_MS;
/* time out */
if (p_timer->count == 0)
{
if (p_timer->mode == SOFT_TIMER_MODE_SIGLE)
{
p_timer->status = SOFT_TIMER_STATUS_COMPLETED;
if (p_timer->timeout_cb != NULL)
p_timer->timeout_cb(p_timer->param);
}
else if (p_timer->mode == SOFT_TIMER_MODE_RERIOD)
{
p_timer->status = SOFT_TIMER_STATUS_RUNNING;
p_timer->count = p_timer->timeout;
if (p_timer->timeout_cb != NULL)
p_timer->timeout_cb(p_timer->param);
}
}
}
p_timer = p_timer->next;
}
}