之前偶尔了解到软件定时器,也在网上找了许多网友写的各种版本,知道读到嵌入式TCP/IP协议栈中的软件定时器的写法时,叹为观止,故将其修改移植到裸机stm32上使用,并向大家做一分享。
首先得感谢那些兢兢业业从事着自己的工作,并毫不吝啬的向别人公布自己源代码的前辈们,正因为他们慷慨无私,我们才能阅读到各种精巧的代码,并从中汲取养分,从而培养了许多热爱技术,真诚无私的人。
/**@brief:1、该文件参考LWIP协议中的times.c编写
* 2、该超时定时器按链表的形式进行组织,按时间长短进行排序,时间最短的永远排在最前面
* 3、移植时应该注意的几点:
* a.周期性的调用函数。b.需要外部定时器实现时基。c.注意动态内存分配mallco的使用。
*@author: LT
*@date: 2016/12/3
*/
#ifndef __SOFT_TIME_H
#define __SOFT_TIME_H
#include "typedef.h"
#include <string.h>
#include <stdlib.h>
/* 定时器超时处理函数指针 */
typedef void (* soft_timeout_handler)(void *arg);
/* 超时定时器 */
struct soft_timeo {
struct soft_timeo *next;
u32 time;
soft_timeout_handler h;
void *arg;
};
#define MEMP_soft_TIMEOUT (sizeof(struct soft_timeo))
void soft_timeouts_init(u32 msecs, soft_timeout_handler handler, void *arg);
void soft_timeout(u32 msecs, soft_timeout_handler handler, void *arg);
void soft_untimeout(soft_timeout_handler handler, void *arg);
void soft_check_timeouts(void);
void soft_restart_timeouts(void);
void soft_run_timeout(soft_timeout_handler handler, void *arg);
u32 time_to_sec(char *RTC_set);
u32 RTC_set(char* RTC_set);
#endif
#include "soft_time.h"
#include "bsp.h"
#include "malloc.h"
extern volatile u32 g_soft_timer_count;
static u32 timeouts_last_time;
static struct soft_timeo *next_timeout;
/*从字符串的左边截取n个字符*/
char * str_left(char *dst,const char *src, int n)
{
const char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len;
while(n--) *(q++) = *(p++);
*(q++)='\0'; /*有必要吗?很有必要*/
return dst;
}
u32 soft_time_now(void)
{
return RTC_GetCounter();
}
/** @brief 计算预定时间距现在的时间(单位:s)
* @param 预定时间转成的字符串(例如:2016 12 03 18 30 00 错误)
* ( 2016 12 3 18 30 0 正确)
* @retval
* @tips 注意strtol函数的使用
*/
u32 time_to_sec(char *RTC_set)
{
u32 set_sec;
// u32 now_sec;
u8 n;
char *pEnd;
n = accumulationdayfrom1970((int*)&set_sec, RTC_set);
set_sec = set_sec * 3600 * 24 + (int)strtol(RTC_set + n,&pEnd,0) * 3600 ;
set_sec = set_sec + (int)strtol(pEnd, &pEnd, 0) * 60;
set_sec = set_sec + (int)strtol(pEnd, NULL, 0);
/*
RTC_Get_str(RTC_now);
n = accumulationdayfrom1970((int*)&now_sec, RTC_now);
now_sec = now_sec * 3600 * 24 + (int)strtol(RTC_now + n,&pEnd_,0) * 3600 ;
now_sec = now_sec + (int)strtol(pEnd_, &pEnd_, 0) * 60;
now_sec = now_sec + (int)strtol(pEnd_, NULL, 0);
printf("%d \n",set_sec - now_sec);
*/
return (set_sec - RTC_GetCounter());
}
/** @brief 计算预定时间距1970\1\1的时间(单位:s)
* @param 预定时间转成的字符串(例如:2016 12 03 18 30 00 错误)
* ( 2016 12 3 18 30 0 正确)
* @retval 时间 单位 S
* @tips 注意strtol函数的使用
*/
u32 RTC_set(char* RTC_set)
{
u32 set_sec;
char* pEnd;
u8 n;
n = accumulationdayfrom1970((int*)&set_sec, RTC_set);
set_sec = set_sec * 3600 * 24 + (int)strtol(RTC_set + n,&pEnd,0) * 3600 ;
set_sec = set_sec + (int)strtol(pEnd, &pEnd, 0) * 60;
set_sec = set_sec + (int)strtol(pEnd, NULL, 0);
return set_sec;
}
/** Initialize this module */
void soft_timeouts_init(u32 msecs, soft_timeout_handler handler, void *arg)
{
soft_timeout(msecs, handler, arg);
timeouts_last_time = soft_time_now();
}
/*
* Must be called periodically from your main loop.
* 检查是否有某个定时器的时间到了,以作出进一步的处理
*/
void
soft_check_timeouts(void)
{
if (next_timeout) {
struct soft_timeo *tmptimeout;
u32 diff;
soft_timeout_handler handler;
void *arg;
u8 had_one;
u32 now;
now = soft_time_now();
/* this cares for wraparounds */
diff = now - timeouts_last_time;
do
{
had_one = 0;
tmptimeout = next_timeout;
if (tmptimeout && (tmptimeout->time <= diff)) {
/* timeout has expired */
had_one = 1;
timeouts_last_time = now;
diff -= tmptimeout->time;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
myfree(SRAMIN, tmptimeout);
if (handler != NULL) {
handler(arg);
}
}
/* repeat until all expired timers have been called */
}while(had_one);
}
}
/*
* 功能:添加超时定时器
*
*/
void
soft_timeout(u32 msecs, soft_timeout_handler handler, void *arg)
{
struct soft_timeo *timeout, *t;
timeout = (struct soft_timeo *)mymalloc(SRAMIN, MEMP_soft_TIMEOUT);
if (timeout == NULL) {
printf("soft_timeout: timeout != NULL, pool MEMP_soft_TIMEOUT is empty");
return;
}
timeout->next = NULL;
timeout->h = handler;
timeout->arg = arg;
timeout->time = msecs;
if (next_timeout == NULL) {
next_timeout = timeout;
return;
}
/* 实现对定时器链表的插入,排列顺序按照定时时间的长短确定 */
if (next_timeout->time > msecs) {
next_timeout->time -= msecs;
timeout->next = next_timeout;
next_timeout = timeout;
} else {
for(t = next_timeout; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/*
* 功能:删除与所指定的回调函数及参数相同的第一个定时器
*/
void
soft_untimeout(soft_timeout_handler handler, void *arg)
{
struct soft_timeo *prev_t, *t;
if (next_timeout == NULL) {
return;
}
for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == handler) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL) {
next_timeout = t->next;
} else {
prev_t->next = t->next;
}
/* If not the last one, add time of this one back to next */
if (t->next != NULL) {
t->next->time += t->time;
}
myfree(MEMP_soft_TIMEOUT, t);
return;
}
}
return;
}
/*
* 功能:如果定时器回调函数在很久没有被调用,可以使用该函数更新
* 计数值,使之前的函数被调用。
*/
void
soft_restart_timeouts(void)
{
timeouts_last_time = soft_time_now();
}
/*
* 功能:直接指定相应的定时器执行
*/
void
soft_run_timeout(soft_timeout_handler handler, void *arg)
{
soft_untimeout(handler,arg);
soft_timeout(0, handler, arg);
}