之前偶爾瞭解到軟件定時器,也在網上找了許多網友寫的各種版本,知道讀到嵌入式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);
}