一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一款可無(wú)限擴(kuò)展的軟件定時(shí)器MultiTimer

strongerHuang ? 來(lái)源:Mculover666 ? 作者:Mculover666 ? 2021-11-16 09:23 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1. MultiTimer

今天給大家?guī)?lái)的開源項(xiàng)目是 MultiTimer,一款可無(wú)限擴(kuò)展的軟件定時(shí)器,作者0x1abin,目前收獲 95 個(gè) star,遵循 MIT 開源許可協(xié)議。

MultiTimer 是一個(gè)軟件定時(shí)器擴(kuò)展模塊,可無(wú)限擴(kuò)展你所需的定時(shí)器任務(wù),取代傳統(tǒng)的標(biāo)志位判斷方式, 更優(yōu)雅更便捷地管理程序的時(shí)間觸發(fā)時(shí)序。

項(xiàng)目地址:https://github.com/0x1abin/MultiTimer

2. 移植MultiTimer

2.1. 移植思路

開源項(xiàng)目在移植過(guò)程中主要參考項(xiàng)目的readme文檔,一般只需兩步:

  • ① 添加源碼到裸機(jī)工程中;
  • ② 實(shí)現(xiàn)需要的接口;

2.2. 準(zhǔn)備裸機(jī)工程

本文中我使用的是小熊派IoT開發(fā)套件,主控芯片為STM32L431RCT6:

移植之前需要準(zhǔn)備一份裸機(jī)工程,我使用STM32CubeMX生成,需要初始化以下配置:

  • 配置一個(gè)串口用于打印信息
  • printf重定向

2.3. 添加MultiTimer到工程中

① 復(fù)制MultiTimer源碼到工程中

② 在keil中添加 MultiTimer的源碼文件

③ 將MultiTimer頭文件路徑添加到keil中

3. 使用MultiTimer

使用時(shí)包含頭文件:

#include "multi_timer.h"

如果遇到multi_timer.c文件中NULL宏定義報(bào)錯(cuò),則在multi_timer.h中添加頭文件即可。

3.1. 創(chuàng)建Timer對(duì)象

/* USER CODE BEGIN PV */struct Timer timer1;struct Timer timer2;
/* USER CODE END PV */

3.2. Timer回調(diào)函數(shù)

/* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 */void timer1_callback(){    printf("timer1 timeout!
");}
void timer2_callback(){    printf("timer2 timeout!
");}/* USER CODE END 0 */

3.3. 初始化并啟動(dòng)Timer

始化定時(shí)器對(duì)象,注冊(cè)定時(shí)器回調(diào)處理函數(shù),設(shè)置定時(shí)時(shí)間(ms),循環(huán)定時(shí)觸發(fā)時(shí)間:

/* USER CODE BEGIN 2 */printf("multi timer test...
");
//重復(fù)計(jì)時(shí),周期為1000次,即1000ms=1stimer_init(&timer1, timer1_callback, 1000, 1000);timer_start(&timer1);
//單次計(jì)時(shí),周期為50次,即50mstimer_init(&timer2, timer2_callback, 50, 0);timer_start(&timer2);
/* USER CODE END 2 */

3.4. Timer對(duì)象處理

在循環(huán)中調(diào)用Timer對(duì)象處理函數(shù),處理函數(shù)會(huì)判斷鏈表上的每個(gè)定時(shí)器是否超時(shí),如果超過(guò),則拉起注冊(cè)的回調(diào)函數(shù):

/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){  /* USER CODE END WHILE */
  /* USER CODE BEGIN 3 */  timer_loop();} /* USER CODE END 3 */

3.5. 提供Timer時(shí)基信號(hào)

MultiTimer中所有的定時(shí)器都是通過(guò)一個(gè)32位的計(jì)數(shù)值_timer_ticks來(lái)判斷的,所以需要一個(gè)硬件定時(shí)器提供時(shí)基信號(hào),遞增該值。

本文中使用的是STM32HAL庫(kù),所以通過(guò)Systick來(lái)提供,無(wú)需設(shè)置額外的定時(shí)器。

main.c文件的最后編寫Systick回調(diào)函數(shù):

/* USER CODE BEGIN 4 */void HAL_SYSTICK_Callback(void){    //給multitimer提供時(shí)基信號(hào)    timer_ticks(); //1ms ticks}
/* USER CODE END 4 */

然后在stm32l4xx_it.c中調(diào)用該回調(diào)函數(shù):

/**  * @brief This function handles System tick timer.  */void SysTick_Handler(void){  /* USER CODE BEGIN SysTick_IRQn 0 */  HAL_SYSTICK_IRQHandler();
  /* USER CODE END SysTick_IRQn 0 */  HAL_IncTick();  /* USER CODE BEGIN SysTick_IRQn 1 */
  /* USER CODE END SysTick_IRQn 1 */}

接下來(lái)編譯下載,看在串口助手中看到打印的日志:b416dbb8-4441-11ec-b939-dac502259ad0.png

4. MultiTimer設(shè)計(jì)思想解讀

4.1. 軟件定時(shí)器設(shè)計(jì)思想

MultiTimer的設(shè)計(jì)比較簡(jiǎn)潔。

設(shè)置一個(gè)計(jì)數(shù)值_timer_ticks不斷遞增,由定時(shí)器提供的中斷驅(qū)動(dòng),只計(jì)次數(shù),不計(jì)時(shí)間,有了很大的自由度,一般時(shí)基信號(hào)設(shè)置為1ms一次:

/**  * @brief  background ticks, timer repeat invoking interval 1ms.  * @param  None.  * @retval None.  */void timer_ticks(){  _timer_ticks++;}

在程序運(yùn)行時(shí)循環(huán)比較定時(shí)器設(shè)置的超時(shí)值是否大于當(dāng)前_timer_ticks的計(jì)數(shù)值,如果是則再次判斷是否重復(fù)計(jì)數(shù)值是否為0,是則停止定時(shí)器,完成單次計(jì)時(shí)效果,否則修改計(jì)數(shù)值,最后拉起注冊(cè)到該定時(shí)器的回調(diào)函數(shù)執(zhí)行:

/**  * @brief  main loop.  * @param  None.  * @retval None  */void timer_loop(){  struct Timer* target;  for(target=head_handle; target; target=target->next) {    if(_timer_ticks >= target->timeout) {      if(target->repeat == 0) {        timer_stop(target);      } else {        target->timeout = _timer_ticks + target->repeat;      }      target->timeout_cb();    }  }}

4.2. 單鏈表操作

MultiTimer的代碼少,非常適合拿來(lái)學(xué)習(xí)單鏈表的操作,學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的過(guò)程是乏味的,不如直接來(lái)個(gè)實(shí)例看看是如何操作的。

① 鏈表的節(jié)點(diǎn)設(shè)計(jì)為一個(gè)軟件定時(shí)器,所以理論上支持的定時(shí)器數(shù)量只受內(nèi)存限制。

typedef struct Timer {    uint32_t timeout;    uint32_t repeat;    void (*timeout_cb)(void);    struct Timer* next;}Timer;

定時(shí)器初始化函數(shù)timer_init就是初始化一個(gè)鏈表節(jié)點(diǎn):

void timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat){  // memset(handle, sizeof(struct Timer), 0);  handle->timeout_cb = timeout_cb;  handle->timeout = _timer_ticks + timeout;  handle->repeat = repeat;}

② 設(shè)置鏈表頭指針,只需知道頭指針就能完成對(duì)整個(gè)單鏈表的操作:

//timer handle list head.static struct Timer* head_handle = NULL;

③ 向單鏈表增加一個(gè)節(jié)點(diǎn)

向單鏈表增加一個(gè)節(jié)點(diǎn)有三種方式:

  • 在單鏈表尾部增加一個(gè)節(jié)點(diǎn)
  • 在單鏈表頭部增加一個(gè)節(jié)點(diǎn)
  • 在單鏈表中間增加一個(gè)節(jié)點(diǎn)

MultiTimer中所有的結(jié)點(diǎn)都是定時(shí)器,每個(gè)定時(shí)器之間相互獨(dú)立,不存在先后次序關(guān)系,所以無(wú)論加到中間,還是加到尾部,還是加到頭部,最后的功能都是一樣的,但是在插入算法上有優(yōu)劣性能之分。

先來(lái)看看再單鏈表尾部增加一個(gè)節(jié)點(diǎn)的算法:b4a1d22c-4441-11ec-b939-dac502259ad0.gif( 我會(huì)動(dòng)哦 )

int timer_start(struct Timer* handle){  /**    * 算法1 —— 向單鏈表尾部添加節(jié)點(diǎn)   * 時(shí)間復(fù)雜度O(n)   * Mculover666   */  struct Timer* target = head_handle;  if(head_handle == NULL)  {    /* 鏈表為空 */    head_handle = handle;    handle->next = NULL;  }  else  {    /* 鏈表中存在節(jié)點(diǎn),遍歷找最后一個(gè)節(jié)點(diǎn) */    while(target->next != NULL)    {      if(target == handle)        return -1;      target = target->next;    }    target->next = handle;    handle->next = NULL;  }
  return 0;}

這種算法理解簡(jiǎn)單,實(shí)現(xiàn)簡(jiǎn)單,但是算法時(shí)間復(fù)雜度秒變?yōu)镺(n),當(dāng)n很大時(shí),插入一個(gè)節(jié)點(diǎn)的時(shí)間就會(huì)非常久。

再來(lái)看看在鏈表頭部插入一個(gè)新節(jié)點(diǎn)的情況:

(我會(huì)動(dòng)哦)

int timer_start(struct Timer* handle){  /**    * 算法2 —— 向單鏈表頭部添加節(jié)點(diǎn)   * 時(shí)間復(fù)雜度O(n),如果去掉判斷重復(fù),則時(shí)間復(fù)雜度O(1)   * 0x1abin   */   struct Timer *target = head_handle;
   //判斷是否有重復(fù)的定時(shí)器   while(target)   {    if(target == handle)    {      return -1;    }    target = target->next;   }   handle->next = head_handle;   head_handle = handle;   return 0;}

這里第二種頭部插入節(jié)點(diǎn)的算法時(shí)間復(fù)雜度依然是O(n),emmm?

其實(shí),這里因?yàn)閱捂湵砉?jié)點(diǎn)是定時(shí)器,在插入的時(shí)候需要對(duì)整個(gè)鏈表進(jìn)行判斷,避免重復(fù)添加同樣的定時(shí)器節(jié)點(diǎn),所以無(wú)論任何一種算法,都需要對(duì)單鏈表進(jìn)行遍歷。

如果在不需要判斷重復(fù)的情況下,尾部插入算法仍然需要遍歷,但是頭部插入算法只需要插入就可以,時(shí)間復(fù)雜度為O(1),算法更優(yōu)。

④ 單鏈表刪除其中一個(gè)節(jié)點(diǎn)

刪除單鏈表的節(jié)點(diǎn)時(shí),因?yàn)楣?jié)點(diǎn)自身只保存有下一個(gè)節(jié)點(diǎn)的指針,并沒(méi)有指向上一個(gè)節(jié)點(diǎn)的指針,所以不能直接入手刪除節(jié)點(diǎn),那么如何刪除單鏈表的節(jié)點(diǎn)呢?

方法是:設(shè)置二級(jí)指針(指向Timer類型指針的指針),通過(guò)遍歷鏈表的方式來(lái)尋找節(jié)點(diǎn)中next指針指向刪除節(jié)點(diǎn)的那個(gè)節(jié)點(diǎn),代碼如下。

void timer_stop(struct Timer* handle){  struct Timer** curr;  for(curr = &head_handle; *curr; ) {    struct Timer* entry = *curr;    if (entry == handle) {      *curr = entry->next;//      free(entry);    } else      curr = &entry->next;  }}

責(zé)任編輯:haq
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 軟件
    +關(guān)注

    關(guān)注

    69

    文章

    5150

    瀏覽量

    89206
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3298

    瀏覽量

    118864

原文標(biāo)題:MultiTimer,一款可無(wú)限擴(kuò)展的軟件定時(shí)器

文章出處:【微信號(hào):strongerHuang,微信公眾號(hào):strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    stm32H743定時(shí)器溢出的原因?怎么解決?

    我利用定時(shí)器更新中斷實(shí)現(xiàn)軟件計(jì)時(shí),定時(shí)時(shí)間是固定的按照{(diào)10ms, 20ms,650ms, 50ms,50ms}周期性進(jìn)行的。由于下次的計(jì)時(shí)時(shí)間是需要在
    發(fā)表于 06-23 08:26

    MCU定時(shí)器/計(jì)數(shù)

    RISC-V核低功耗MCU通過(guò)靈活的定時(shí)器架構(gòu)、低功耗模式適配及硬件級(jí)中斷優(yōu)化,在工業(yè)控制、智能家居等場(chǎng)景中實(shí)現(xiàn)高精度計(jì)時(shí)與能耗控制的協(xié)同設(shè)計(jì),滿足復(fù)雜任務(wù)調(diào)度與實(shí)時(shí)響應(yīng)的雙重需求?。 、?硬件
    的頭像 發(fā)表于 04-27 13:54 ?290次閱讀

    TPS3435 納米靜態(tài)電流精密超時(shí)看門狗定時(shí)器數(shù)據(jù)手冊(cè)

    TPS3435 是一款超低功耗 (典型值為 250nA) 器件,提供可編程超時(shí)看門狗定時(shí)器。 TPS3435 提供高精度超時(shí)看門狗定時(shí)器,具有適用于各種應(yīng)用的系列功能。超時(shí)看門
    的頭像 發(fā)表于 04-09 15:49 ?368次閱讀
    TPS3435 納米靜態(tài)電流精密超時(shí)看門狗<b class='flag-5'>定時(shí)器</b>數(shù)據(jù)手冊(cè)

    TPS3436-Q1 汽車級(jí)納米靜態(tài)電流精密窗口看門狗定時(shí)器數(shù)據(jù)手冊(cè)

    TPS3436-Q1 是一款超低功耗(典型值為 250 nA)器件,提供可編程窗口看門狗定時(shí)器。 TPS3436-Q1 提供高精度窗口看門狗定時(shí)器,具有許多功能,適用于各種應(yīng)用。關(guān)閉窗口
    的頭像 發(fā)表于 04-09 14:40 ?310次閱讀
    TPS3436-Q1 汽車級(jí)納米靜態(tài)電流精密窗口看門狗<b class='flag-5'>定時(shí)器</b>數(shù)據(jù)手冊(cè)

    TPS3435-Q1 汽車級(jí)納米靜態(tài)電流精密超時(shí)看門狗定時(shí)器數(shù)據(jù)手冊(cè)

    TPS3435-Q1 是一款超低功耗 (典型值為 250nA) 器件,提供可編程超時(shí)看門狗定時(shí)器。 TPS3435-Q1 提供高精度超時(shí)看門狗定時(shí)器,具有許多功能,適用于各種應(yīng)用。超時(shí)看門狗
    的頭像 發(fā)表于 04-09 14:34 ?313次閱讀
    TPS3435-Q1 汽車級(jí)納米靜態(tài)電流精密超時(shí)看門狗<b class='flag-5'>定時(shí)器</b>數(shù)據(jù)手冊(cè)

    圣邦微電子SGM819SxQ車規(guī)級(jí)看門狗定時(shí)器電路特性與數(shù)據(jù)手冊(cè)分享

    SGM819SxQ 是一款獨(dú)立的看門狗定時(shí)器電路,它可以幫助防止因硬件故障(例如外圍設(shè)備錯(cuò)誤、總線占用)或軟件故障(例如循環(huán)中無(wú)限執(zhí)行的代碼)導(dǎo)致的系統(tǒng)故障。 該器件配備了 WDI 輸
    的頭像 發(fā)表于 02-26 17:34 ?1577次閱讀
    圣邦微電子SGM819SxQ車規(guī)級(jí)看門狗<b class='flag-5'>定時(shí)器</b>電路特性與數(shù)據(jù)手冊(cè)分享

    圣邦微電子車規(guī)級(jí)看門狗定時(shí)器電路SGM819SxQ特性與典型應(yīng)用電路

    圣邦微電子推出 SGM819SxQ,一款車規(guī)級(jí)看門狗定時(shí)器電路。 該器件適用于汽車應(yīng)用、工業(yè)設(shè)備、電信、安全應(yīng)用、網(wǎng)絡(luò)、醫(yī)療設(shè)備和不間斷電源系統(tǒng)。 SGM819SxQ 是一款獨(dú)立的看門狗定時(shí)器
    的頭像 發(fā)表于 02-26 09:13 ?1124次閱讀
    圣邦微電子車規(guī)級(jí)看門狗<b class='flag-5'>定時(shí)器</b>電路SGM819SxQ特性與典型應(yīng)用電路

    詳解CKS32F107xx系列的定時(shí)器同步功能

    我們將圍繞定時(shí)器同步功能概述展開,并以其中種功能為例——將定時(shí)器2給定時(shí)器3當(dāng)預(yù)分頻,最終級(jí)聯(lián)同步PWM輸出。
    的頭像 發(fā)表于 11-26 17:51 ?1048次閱讀
    詳解CKS32F107xx系列的<b class='flag-5'>定時(shí)器</b>同步功能

    看門狗定時(shí)器的工作原理

    看門狗定時(shí)器種獨(dú)立的計(jì)時(shí)硬件模塊,其核心功能是倒計(jì)時(shí)。如果系統(tǒng)軟件在計(jì)時(shí)超時(shí)前沒(méi)有對(duì)其進(jìn)行復(fù)位操作(即“喂狗”),看門狗將觸發(fā)
    的頭像 發(fā)表于 10-21 14:18 ?1281次閱讀
    看門狗<b class='flag-5'>定時(shí)器</b>的工作原理

    門頭燈定時(shí)器怎么調(diào)開關(guān)時(shí)間

    在現(xiàn)代商業(yè)環(huán)境中,門頭燈不僅是企業(yè)形象的部分,也是吸引顧客的重要手段。然而,手動(dòng)控制門頭燈的開關(guān)往往既耗時(shí)又容易出錯(cuò)。為了解決這問(wèn)題,門頭燈定時(shí)器應(yīng)運(yùn)而生,它通過(guò)預(yù)設(shè)的時(shí)間表自動(dòng)控制門頭燈的開關(guān)
    的頭像 發(fā)表于 10-17 14:14 ?3447次閱讀

    定時(shí)器自動(dòng)控制開關(guān)怎么設(shè)置

    定時(shí)器自動(dòng)控制開關(guān)是種常見的自動(dòng)化設(shè)備,廣泛應(yīng)用于家庭、工業(yè)、農(nóng)業(yè)等多個(gè)領(lǐng)域。通過(guò)定時(shí)器,用戶可以預(yù)設(shè)時(shí)間,讓設(shè)備在特定時(shí)間自動(dòng)開啟或關(guān)閉,從而實(shí)現(xiàn)節(jié)能、提高效率和便利性。
    的頭像 發(fā)表于 09-19 16:19 ?4063次閱讀

    定時(shí)器的基本組成和工作模式

    定時(shí)器是計(jì)算機(jī)或電子設(shè)備中常見的個(gè)硬件或軟件組件,其主要功能是測(cè)量和控制時(shí)間的流逝。它在各種應(yīng)用中起著至關(guān)重要的作用,如操作系統(tǒng)調(diào)度、多媒體播放、網(wǎng)絡(luò)通信、工業(yè)自動(dòng)化控制以及家電設(shè)備的定時(shí)
    的頭像 發(fā)表于 08-19 18:28 ?2761次閱讀

    簡(jiǎn)述單片機(jī)定時(shí)器的工作原理

    單片機(jī)定時(shí)器的工作原理是個(gè)復(fù)雜而精細(xì)的過(guò)程,它涉及到單片機(jī)內(nèi)部的多個(gè)組件和機(jī)制。
    的頭像 發(fā)表于 08-19 18:20 ?3121次閱讀

    ESP8266的軟件定時(shí)器允許在user_init中定義兩個(gè)不同的定時(shí)器然后去定時(shí)兩個(gè)不同的操作嗎?

    8266的軟件定時(shí)器允許在user_init中定義兩個(gè)不同的定時(shí)器然后去定時(shí)兩個(gè)不同的操作嗎?如果可以需要注意什么,如果不可以,那么我想分別
    發(fā)表于 07-22 06:54