1. 程式人生 > 其它 >我的定時器連結串列

我的定時器連結串列

#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 &gtimer_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(); 
    }
}