软件定时器(一)

之前偶尔了解到软件定时器,也在网上找了许多网友写的各种版本,知道读到嵌入式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);
}


















  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值