我的定時器連結串列
阿新 • • 發佈:2021-01-23
#ifndef _GKOSONTIMER_H_ #define _GKOSONTIMER_H_ #include <stdlib.h> #include <stdint.h> #include <string.h> typedef void (*time_call_back)(void); //節點的結構體 //因為我放棄了malloc只能引數自己攜帶記憶體 所以也對外提供節點的結構體 typedef struct _time { void *next; uint8_t handle; uint8_t start; uint32_t cnt; uint32_t time_out; void (*fun)(void); }gtime_type; //再次抽象 控制代碼結構體 typedef struct { uint8_t (*creat) ( gtime_type *timenode ,uint32_t time_out ,uint8_t start, time_call_back call_back); uint8_t (*stop) ( uint8_t handle); uint8_t (*start) ( uint8_t handle); }time_ops_type; //對外提供的控制代碼 extern time_ops_type gkosonTimer; //週期輪訓業務 輪訓連結串列的函式 void gtimer_loop( void ); #endif #include "gkosontimer.h" #include "stdbool.h" static uint8_t StimerTaskId = 0; //表示每個節點的標號 此後可以對外釋放 方便開 和 關 static gtime_type *Stimerhead = NULL; //連結串列的頭結點 //遍歷連結串列 週期loop執行 void gtimer_loop( void ) { gtime_type *priv = Stimerhead; while( priv != NULL ) { if( priv->start) { if( ++priv->cnt >= priv->time_out) { priv->cnt = 0; if(priv->fun != NULL) priv->fun(); } } priv = priv->next; } } //關閉節點 《並沒有連結串列移除 而是用標記位 優點:方便簡單 缺點:記憶體無法釋放》 uint8_t gtimer_stop_time(uint8_t handle) { gtime_type *priv = Stimerhead; while( priv != NULL ) { if( priv->handle == handle) { priv->start = false; return true; } priv = priv->next; } return false; } //開啟節點 uint8_t gtimer_start_time(uint8_t handle) { gtime_type *priv = Stimerhead; while( priv != NULL ) { if( priv->handle == handle) { priv->start = true; priv->cnt = 0; return true; } priv = priv->next; } return false; } //一個節點新增到連結串列 返回它的ID uint8_t gtimer_register_isr( gtime_type *timenode, uint32_t time_out ,uint8_t start, time_call_back call_back) { gtime_type *priv; gtime_type *this; this = timenode;//可以思考用malloc實現 目前這裡和button一樣我是自帶記憶體 this->cnt = 0;//實際計數值 this->start = start;//開關 this->handle = StimerTaskId++;//統一在連結串列中的ID this->time_out = time_out;//超時計數值 this->fun = call_back;//節點邏輯函式 this->next = NULL;//節點後繼 if( Stimerhead == NULL) { Stimerhead = this;//第一次 例項化head } else { priv = Stimerhead; while( priv->next != NULL ) priv = priv->next;//第一次以後:尾插 priv->next = this; } return (this->handle); } time_ops_type gkosonTimer = { .creat = gtimer_register_isr, .stop = gtimer_stop_time , .start = gtimer_start_time, }; 測試程式碼 #include "gkosontimer.h" uint8_t production_timer; static void production_timeout_handler(void ) { NRF_LOG_DEBUG("hello world"); } static void guiTask(void *pvParameters) { static gtime_type T; production_timer = gkosonTimer.creat(&T, 30, 1 ,production_timeout_handler ); for (; ;) { vTaskDelay(100); gtimer_loop(); } }
程式碼問題:
1---每次開關都需要去遍歷效率低
2--維護的連結串列來自每個static的自帶記憶體 主要是第二點導致前面必須去查詢==判斷
3--同樣是第二點導致H檔案必須對外提供節點的結構體
現在想優化一下
做一個數組池 這樣地址就是連續的 這樣的話每次不需要自帶記憶體 而且 開關我可以通過ID直接關閉!第三點我完全封閉了!
#ifndef _GKOSONTIMER_H_ #define _GKOSONTIMER_H_ #include <stdlib.h> #include <stdint.h> #include <string.h> typedef void (*time_call_back)(void); //再次抽象 控制代碼結構體 typedef struct { uint8_t (*creat) ( uint32_t time_out ,uint8_t start, time_call_back call_back); uint8_t (*stop) ( uint8_t handle); uint8_t (*start) ( uint8_t handle); }time_ops_type; //對外提供的控制代碼 extern time_ops_type gkosonTimer; //週期輪訓業務 輪訓連結串列的函式 void gtimer_loop( void ); #endif #include "gkosontimer.h" #include "stdbool.h" //節點的結構體 //因為我放棄了malloc只能引數自己攜帶記憶體 所以也對外提供節點的結構體 typedef struct _time { void *next; uint8_t handle; uint8_t start; uint32_t cnt; uint32_t time_out; void (*fun)(void); }gtime_type; static uint8_t StimerTaskId = 0; //表示每個節點的標號 此後可以對外釋放 方便開 和 關 static gtime_type *Stimerhead = NULL; //連結串列的頭結點 #define MAX_GTIMER_NUM 10 static gtime_type gtimer_memory_bank[MAX_GTIMER_NUM]={0}; gtime_type *gtimer_memory_alloc(uint8_t id) { if(id >= MAX_GTIMER_NUM) return NULL; return >imer_memory_bank[id]; } //遍歷連結串列 週期loop執行 void gtimer_loop( void ) { gtime_type *priv = Stimerhead; while( priv != NULL ) { if( priv->start) { if( ++priv->cnt >= priv->time_out) { priv->cnt = 0; if(priv->fun != NULL) priv->fun(); } } priv = priv->next; } } //關閉節點 uint8_t gtimer_stop_time(uint8_t handle) { if(handle >= MAX_GTIMER_NUM) return false; gtimer_memory_bank[handle].start = false; gtimer_memory_bank[handle].cnt = 0; return true; } //開啟節點 uint8_t gtimer_start_time(uint8_t handle) { if(handle >= MAX_GTIMER_NUM) return false; gtimer_memory_bank[handle].start = true; gtimer_memory_bank[handle].cnt = 0; return true; } //一個節點新增到連結串列 返回它的ID uint8_t gtimer_register_isr(uint32_t time_out ,uint8_t start, time_call_back call_back) { gtime_type *priv; gtime_type *this; this = gtimer_memory_alloc(StimerTaskId);//malloc實現 this->cnt = 0;//實際計數值 this->start = start;//開關 this->handle = StimerTaskId++;//統一在連結串列中的ID this->time_out = time_out;//超時計數值 this->fun = call_back;//節點邏輯函式 this->next = NULL;//節點後繼 if( Stimerhead == NULL) { Stimerhead = this;//第一次 例項化head } else { priv = Stimerhead; while( priv->next != NULL ) priv = priv->next;//第一次以後:尾插 priv->next = this; } return (this->handle); } time_ops_type gkosonTimer = { .creat = gtimer_register_isr, .stop = gtimer_stop_time , .start = gtimer_start_time, }; static void guiTask(void *pvParameters) { production_timer = gkosonTimer.creat(30, 1 ,production_timeout_handler ); for (; ;) { vTaskDelay(100); gtimer_loop(); } }