Merge pull request #6 from recan-li/master

【PR】修复并优化若干问题
master
0x1abin 4 years ago committed by GitHub
commit 2e5223c645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,38 @@
CC = gcc
DEL = rm -rf
CFLGAS += -std=c99
CFLAGS += -D TEST
CFLAGS += -g
OBJ_PATH = .
BIN_PATH = .
SRC_PATH = .
IDIR = .
INC += -I$(IDIR)
TARGET = $(BIN_PATH)/test
C_SRCS += examples/test_linux.c
C_SRCS += multi_timer.c
OBJ := $(patsubst %.c,%.o,$(filter %.c,$(addprefix $(SRC_PATH)/,$(C_SRCS))))
TARGET_OBJ := $(addprefix $(OBJ_PATH)/,$(OBJ))
$(warning "TARGET_OBJ=$(TARGET_OBJ)")
.PHONY : clean all
all: $(TARGET)
$(TARGET) : $(TARGET_OBJ)
$(CC) $(INC) $(CFLAGS) $^ -o $@
$(TARGET_OBJ): %.o : %.c
$(CC) $(INC) $(CFLAGS) -c $< -o $@
clean:
-$(DEL) $(OBJ_PATH)/$(OBJ)
-$(DEL) $(TARGET)

@ -4,23 +4,35 @@
MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。 MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
## 使用方法 ## 使用方法
1.先申请一个定时器管理handle 1.在multi_timer.h中配置定时器tick时钟频率即1个tick代表N毫秒钟
```
/*
It means 1 tick for 1ms.
Your can configurate for your tick time such as 5ms/10ms and so on.
*/
#define CFG_TIMER_1_TICK_N_MS 1
```
2.先申请一个定时器管理handle
``` ```
struct Timer timer1; struct Timer timer1;
``` ```
2.初始化定时器对象注册定时器回调处理函数设置延迟启动时间ms循环定时触发时间
3.初始化定时器对象注册定时器回调处理函数设置延迟启动时间ms循环定时触发时间
``` ```
timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat); timer_init(struct Timer* handle, void(*timeout_cb)(void *arg), uint32_t timeout, uint32_t repeat);
``` ```
3.启动定时器 4.启动定时器
``` ```
timer_start(&timer1); timer_start(&timer1);
``` ```
4.设置1ms的硬件定时器循环调用 *timer_ticks()* 以提供时间基准
5.设置1ms的硬件定时器循环调用 *timer_ticks()* 以提供时间基准
``` ```
void HAL_SYSTICK_Callback(void) void HAL_SYSTICK_Callback(void)
@ -29,8 +41,7 @@ void HAL_SYSTICK_Callback(void)
} }
``` ```
6.在主循环调用定时器后台处理函数
5.在主循环调用定时器后台处理函数
``` ```
int main() int main()
@ -43,20 +54,31 @@ int main()
} }
``` ```
## 功能限制
1.定时器的时钟频率直接影响定时器的精确度尽可能采用1ms/5ms/10ms这几个精度较高的tick;
2.定义应用定时器时,超时时间应合理设置,不应过大或过小,否则可能导致定时器超时时间不精准;
3.定时器的回调函数内不应执行耗时操作否则可能因占用过长的时间导致其他定时器无法正常超时一般来说若干个tick的时间是可以接受的
4.由于定时器的回调函数是在timer_loop内执行的需要注意栈空间的使用不能过大否则可能会导致栈溢出。
## Examples ## Examples
见example目录下的测试代码main.c为普通平台测试demotest_linux.c为linux平台的测试demo。
``` ```
#include "multi_timer.h" #include "multi_timer.h"
struct Timer timer1; struct Timer timer1;
struct Timer timer2; struct Timer timer2;
void timer1_callback() void timer1_callback(void *arg)
{ {
printf("timer1 timeout!\r\n"); printf("timer1 timeout!\r\n");
} }
void timer2_callback() void timer2_callback(void *arg)
{ {
printf("timer2 timeout!\r\n"); printf("timer2 timeout!\r\n");
} }

@ -3,28 +3,29 @@
struct Timer timer1; struct Timer timer1;
struct Timer timer2; struct Timer timer2;
void timer1_callback() void timer1_callback(void *arg)
{ {
printf("timer1 timeout!\r\n"); printf("timer1 timeout! arg: %p\r\n", arg);
} }
void timer2_callback() void timer2_callback(void *arg)
{ {
printf("timer2 timeout!\r\n"); printf("timer2 timeout! arg: %p\r\n", arg);
} }
int main() int main(void)
{ {
timer_init(&timer1, timer1_callback, 1000, 1000); //1s loop timer_init(&timer1, timer1_callback, 1000, 1000, NULL); //1s loop
timer_start(&timer1); timer_start(&timer1);
timer_init(&timer2, timer2_callback, 50, 0); //50ms delay timer_init(&timer2, timer2_callback, 50, 0, NULL); //50ms delay
timer_start(&timer2); timer_start(&timer2);
while(1) { while(1) {
timer_loop(); timer_loop();
} }
return 0;
} }
void HAL_SYSTICK_Callback(void) void HAL_SYSTICK_Callback(void)

@ -1,15 +1,52 @@
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>
#include "../multi_timer.h" #include "../multi_timer.h"
#define LOG_TIMESTAMP_FORMAT "[%Y-%m-%d %H:%M:%S]"
#define LOG_TIMESTAMP_LEN 21
#define MS_TIMESTAMP_LEN 5
int32_t printf_timestamp(const char *msg, ...)
{
char content[1024] = {0};
time_t time_write;
struct tm tm_Log;
struct timeval t;
uint32_t len = 0;
va_list vl_list;
time_write = time(NULL);
localtime_r(&time_write, &tm_Log);
strftime((char *)&content[len], sizeof(content) - len - 1, LOG_TIMESTAMP_FORMAT, &tm_Log);
len = strlen(&content[len]);
/* .msec] */
gettimeofday(&t, NULL);
len--; // min a ']' char
snprintf((char*)&content[len], sizeof(content) - len, ".%03d]", (int)(t.tv_usec / 1000));
len += MS_TIMESTAMP_LEN;
va_start(vl_list, msg);
vsnprintf((char *)&content[len], sizeof(content) - len - 1, (const char *)msg, vl_list);
va_end(vl_list);
printf("%s", content);
return 0;
}
void signalHandler(int signo) void signalHandler(int signo)
{ {
switch(signo) switch(signo)
{ {
case SIGALRM: case SIGALRM:
timer_ticks(); timer_ticks();
//printf("Caught the SIGALRM signal!\n"); //printf_timestamp("Caught the SIGALRM signal every 1ms !\n");
break; break;
} }
} }
@ -17,36 +54,39 @@ void signalHandler(int signo)
struct Timer timer1; struct Timer timer1;
struct Timer timer2; struct Timer timer2;
void timer1_callback() void timer1_callback(void *arg)
{ {
printf("timer1 timeout!\r\n"); printf_timestamp("timer1 timeout! arg: %p\r\n", arg);
} }
void timer2_callback() void timer2_callback(void *arg)
{ {
printf("timer2 timeout!\r\n"); printf_timestamp("timer2 timeout! arg: %p\r\n", arg);
} }
int main(void) int main(void)
{ {
printf_timestamp("%s start ...\r\n", __func__);
signal(SIGALRM, signalHandler); signal(SIGALRM, signalHandler);
struct itimerval new_value, old_value; struct itimerval new_value, old_value;
new_value.it_value.tv_sec = 1; new_value.it_value.tv_sec = 0; // should be 0x00 !!!
new_value.it_value.tv_usec = 0; new_value.it_value.tv_usec = 1; // non-zero is OK !!!
new_value.it_interval.tv_sec = 0; new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_usec = 1000; new_value.it_interval.tv_usec = 1000 * CFG_TIMER_1_TICK_N_MS; // 1ms
setitimer(ITIMER_REAL, &new_value, &old_value); setitimer(ITIMER_REAL, &new_value, &old_value);
timer_init(&timer1, timer1_callback, 4000, 1000); // start timer after 4s timer_init(&timer1, timer1_callback, 4000, 1000, &timer1); // start timer after 4s
timer_start(&timer1); timer_start(&timer1);
timer_init(&timer2, timer2_callback, 0, 2000); timer_init(&timer2, timer2_callback, 0, 5000, &timer2); // start timer right now
timer_start(&timer2); timer_start(&timer2);
while(1) while(1) {
{ /* Maybe some sleep time is needed to avoid running CPU all the time. */
timer_loop(); timer_loop();
} }
return 0; return 0;
} }

@ -1,31 +0,0 @@
CC = gcc
CFLGAS += -std=c99
CFLAGS += -D TEST
CFLAGS += -g
OBJ_PATH = .
BIN_PATH = .
SRC_PATH = .
IDIR = .
INC += -I$(IDIR)
TARGET = $(BIN_PATH)/test
C_SRCS += ./examples/test_linux.c
C_SRCS += ./multi_timer.c
OBJ := $(patsubst %.c,%.o,$(filter %.c,$(C_SRCS)))
$(TARGET) : $(OBJ_PATH)/$(OBJ)
$(CC) $(INC) $(CFLAGS) $(OBJ) -o $(TARGET)
$(OBJ): %.o : %.c
$(CC) $(INC) $(CFLAGS) -c $< -o $@
.PHONY : clean
clean:
@-rm *.exe
@-rm *.o

@ -3,27 +3,37 @@
* All rights reserved * All rights reserved
*/ */
#include <stdio.h>
#include "multi_timer.h" #include "multi_timer.h"
//timer handle list head. //timer handle list head.
static struct Timer* head_handle = NULL; static struct Timer* head_handle = NULL;
//Timer ticks //Timer ticks
//static uint32_t _timer_ticks = (1 << 32)- 1000; // only for test tick clock overflow
static uint32_t _timer_ticks = 0; static uint32_t _timer_ticks = 0;
/** /**
* @brief Initializes the timer struct handle. * @brief Initializes the timer struct handle.
* @param handle: the timer handle strcut. * @param handle: the timer handle strcut.
* @param timeout_cb: timeout callback. * @param timeout_cb: timeout callback.
* @param timeout: delay to start the timer.
* @param repeat: repeat interval time. * @param repeat: repeat interval time.
* @param arg: the input argument for timeout_cb fucntion.
* @retval None * @retval None
*/ */
void timer_init(struct Timer* handle, void (*timeout_cb)(), uint32_t timeout, uint32_t repeat) void timer_init(struct Timer* handle, void (*timeout_cb)(void *arg), \
uint32_t timeout, uint32_t repeat, void *arg)
{ {
// memset(handle, sizeof(struct Timer), 0); // memset(handle, sizeof(struct Timer), 0);
handle->timeout_cb = timeout_cb; handle->timeout_cb = timeout_cb;
handle->timeout = _timer_ticks + timeout; handle->timeout = timeout;
handle->repeat = repeat; handle->repeat = repeat;
handle->cur_ticks = _timer_ticks;
handle->cur_expired_time = handle->timeout;
handle->arg = arg;
//printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u, timeout: %u\r\n",
// handle->cur_ticks, handle->cur_expired_time, _timer_ticks, timeout);
} }
/** /**
@ -34,36 +44,40 @@ void timer_init(struct Timer* handle, void (*timeout_cb)(), uint32_t timeout, ui
int timer_start(struct Timer* handle) int timer_start(struct Timer* handle)
{ {
struct Timer* target = head_handle; struct Timer* target = head_handle;
while(target)
{ while(target) {
if(target == handle) if(target == handle) {
return -1; //already exist. return -1; //already exist.
}
target = target->next; target = target->next;
} }
handle->next = head_handle; handle->next = head_handle;
head_handle = handle; head_handle = handle;
return 0; return 0;
} }
/** /**
* @brief Stop the timer work, remove the handle off work list. * @brief Stop the timer work, remove the handle off work list.
* @param handle: target handle strcut. * @param handle: target handle strcut.
* @retval None * @retval 0: succeed. -1: timer not exist.
*/ */
void timer_stop(struct Timer* handle) int timer_stop(struct Timer* handle)
{ {
struct Timer** curr; struct Timer** curr;
for(curr = &head_handle; *curr;)
{ for(curr = &head_handle; *curr;) {
struct Timer* entry = *curr; struct Timer* entry = *curr;
if(entry == handle) if(entry == handle) {
{
*curr = entry->next; *curr = entry->next;
// free(entry); //free(entry);
} return 0; // found specified timer
else } else {
curr = &entry->next; curr = &entry->next;
}
} }
return 0;
} }
/** /**
@ -71,33 +85,34 @@ void timer_stop(struct Timer* handle)
* @param None. * @param None.
* @retval None * @retval None
*/ */
void timer_loop() void timer_loop(void)
{ {
struct Timer* target; struct Timer* target;
for(target = head_handle; target; target = target->next)
{ for(target = head_handle; target; target = target->next) {
if(_timer_ticks >= target->timeout) /*
{ More detail on tick-clock overflow, please see https://blog.csdn.net/szullc/article/details/115332326
if(target->repeat == 0) */
{ if(_timer_ticks - target->cur_ticks >= target->cur_expired_time) {
//printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u\r\n",
// target->cur_ticks, target->cur_expired_time, _timer_ticks);
if(target->repeat == 0) {
timer_stop(target); timer_stop(target);
} } else {
else target->cur_ticks = _timer_ticks;
{ target->cur_expired_time = target->repeat;
target->timeout = _timer_ticks + target->repeat; }
} target->timeout_cb(target->arg);
target->timeout_cb();
} }
} }
} }
/** /**
* @brief background ticks, timer repeat invoking interval 1ms. * @brief background ticks, timer repeat invoking interval nms.
* @param None. * @param None.
* @retval None. * @retval None.
*/ */
void timer_ticks() void timer_ticks(void)
{ {
_timer_ticks++; _timer_ticks += CFG_TIMER_1_TICK_N_MS;
} }

@ -6,28 +6,68 @@
#ifndef _MULTI_TIMER_H_ #ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_ #define _MULTI_TIMER_H_
#include "stdint.h" #include <stdint.h>
#include "stddef.h" #include <stddef.h>
/*
It means 1 tick for 1ms.
Your can configurate for your tick time such as 5ms/10ms and so on.
*/
#define CFG_TIMER_1_TICK_N_MS 1
typedef struct Timer { typedef struct Timer {
uint32_t timeout; uint32_t cur_ticks; /* Record current timer start tick */
uint32_t repeat; uint32_t cur_expired_time; /* Record current timer expired time */
void (*timeout_cb)(void); uint32_t timeout; /* Delay (xx ms) time to start tiemr */
struct Timer* next; uint32_t repeat; /* Timer interval expired time (xx ms) */
}Timer; void * arg; /* Input argument for timeout_cb function */
void (*timeout_cb)(void *arg); /* Timer expired callback function */
struct Timer* next; /* Pointer to next timer */
} Timer;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat); /**
* @brief Initializes the timer struct handle.
* @param handle: the timer handle strcut.
* @param timeout_cb: timeout callback.
* @param timeout: delay to start the timer.
* @param repeat: repeat interval time.
* @param arg: the input argument for timeout_cb fucntion.
* @retval None
*/
void timer_init(struct Timer* handle, void(*timeout_cb)(void *arg), \
uint32_t timeout, uint32_t repeat, void *arg);
/**
* @brief Start the timer work, add the handle into work list.
* @param btn: target handle strcut.
* @retval 0: succeed. -1: already exist.
*/
int timer_start(struct Timer* handle); int timer_start(struct Timer* handle);
void timer_stop(struct Timer* handle);
/**
* @brief Stop the timer work, remove the handle off work list.
* @param handle: target handle strcut.
* @retval 0: succeed. -1: timer not exist.
*/
int timer_stop(struct Timer* handle);
/**
* @brief background ticks, timer repeat invoking interval nms.
* @param None.
* @retval None.
*/
void timer_ticks(void); void timer_ticks(void);
void timer_loop(void);
// void timer_again(struct Timer* handle); /**
// void timer_set_repeat(struct Timer* handle, uint32_t repeat); * @brief main loop.
* @param None.
* @retval None
*/
void timer_loop(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

Loading…
Cancel
Save