都說程序設計 = 算法 + 數據結構。數據結構是挨踢必修課,不過好像學了數據結構之后也沒用來做過啥。不知道做啥,就寫個軟件定時器。
軟件定時器數據結構
typedef struct __software_timer{
u32 timeout; //初始化時間計數器
u32 repeat; //運行間隔:repeat > 0 :周期定時時間 repeat == 0 :只定時一次
void (*timeout_callback_handler)(void *para); //超時回調函數
struct __software_timer *next;
}software_timer_t;
判斷軟件定時器鏈表是否為空
/**
* @brief: Determine if the software timer list is empty
* @param[in]: None
* @retval[out]: None
* @note:
* @author: AresXu
* @github:
* @version: v1.0.0
*/
static u8 is_softtimer_list_empty(void)
{
if(software_timer_list_head.next == NULL)
return TRUE;
else
return FALSE;
}
插入定時器到軟件定時器鏈表
鏈表使用單向鏈表。
/**
* @brief: Insert the software timer node into the linked list
* @param[in]: None
* @retval[out]: None
* @note:
* @author: AresXu
* @github:
* @version: v1.0.0
*/
static void insert_software_timer(software_timer_t *timer_handle)
{
software_timer_t *tmp;
software_timer_t *list_head = &software_timer_list_head;
if(is_softtimer_list_empty())
{
list_head->next = timer_handle;
}
else
{
tmp = list_head->next;
while(tmp->next)
{
if(timer_handle == tmp) //定時器已經存在
{
printf("The timer already exists\r\n");
return;
}
tmp = tmp->next;
}
tmp->next = timer_handle;
}
}
將定時器從軟件定時器鏈表移除
/**
* @brief: Removes the software timer node from the list
* @param[in]: None
* @retval[out]: None
* @note:
* @author: AresXu
* @github:
* @version: v1.0.0
*/
static void remove_software_timer(software_timer_t *timer_handle)
{
software_timer_t *list_head = &software_timer_list_head;
software_timer_t *tmp = list_head;
if(is_softtimer_list_empty())
return;
while(tmp && tmp->next != timer_handle)
{
tmp = tmp->next;
}
if(tmp == NULL)
return;
tmp->next = timer_handle->next;
timer_handle->next = NULL;
}
初始化軟件定時器
回調函數不能過長,執行時間不能超過定時時間。
/**
* @brief: Initializes the software timer
* @param[in]: None
* @retval[out]: None
* @note:
* @author: AresXu
* @github:
* @version: v1.0.0
*/
void software_timer_init(software_timer_t *timer_handle,u32 timeout,u32 repeat,void (*timerout_cb)(void *))
{
timer_handle->timeout = timeout;
timer_handle->repeat = repeat;
timer_handle->timeout_callback_handler = timerout_cb;
timer_handle->next = (void *)0;
}
啟動定時器
/**
* @brief: Start timer
* @param[in]: None
* @retval[out]: None
* @note:
* @author: AresXu
* @github:
* @version: v1.0.0
*/
void software_timer_start(software_timer_t *timer_handle)
{
insert_software_timer(timer_handle);
}
停止定時器
/**
* @brief: stop timer
* @param[in]: None
* @retval[out]: None
* @note:
* @author: AresXu
* @github:
* @version: v1.0.0
*/
void software_timer_stop(software_timer_t *timer_handle)
{
remove_software_timer(timer_handle);
}
定時器處理函數(主函數調用)
/**
* @brief: Timer processing function
* @param[in]: None
* @retval[out]: None
* @note: Must be called by the main function
* @author: AresXu
* @github: https://github.com/EmbeddedXGJ
* @version: v1.0.0
*/
void software_timer_main_loop(void)
{
software_timer_t *tmp = &software_timer_list_head;
tmp = tmp->next;
while(tmp)
{
if(tmp->timeout <= 0)
{
tmp->timeout_callback_handler((void *)0);
if(tmp->repeat > 0)
{
tmp->timeout = tmp->repeat;
}
else
{
software_timer_stop(tmp);
}
}
tmp = tmp->next;
}
}
硬件定時器提供時基
1 ms硬件定時器調用函數。
/**
* @brief: Provide a heartbeat to the software timer
* @param[in]: void
* @retval[out]: void
* @note: Must be called by 1ms hardware timer
* @author: AresXu
* @github: https://github.com/EmbeddedXGJ
* @version: v1.0.0
*/
void software_timer_ticks(void)
{
software_timer_t *tmp = &software_timer_list_head;
tmp = tmp->next;
while(tmp)
{
if(tmp->timeout > 0)
{
tmp->timeout--;
}
tmp = tmp->next;
}
}
在STM32上測試
- software_timer_test.c:
software_timer_t timer1_t;
software_timer_t timer2_t;
software_timer_t timer3_t;
void timer1_cb(void *parm)
{
printf("1000ms >>> dyy\r\n");
}
void timer2_cb(void *parm)
{
printf("2000ms >>> dyy\r\n");
}
void timer3_cb(void *parm)
{
printf("500ms >>> dyy\r\n");
}
void SoftWareTimer_Init(void)
{
software_timer_init(&timer1_t,1000,1000,timer1_cb);
software_timer_init(&timer2_t,2000,2000,timer2_cb);
software_timer_init(&timer3_t,500,500,timer3_cb);
software_timer_start(&timer1_t);
software_timer_start(&timer2_t);
software_timer_start(&timer3_t);
串口助手打印信息