色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一款可無限擴展的軟件定時器MultiTimer

strongerHuang ? 來源:Mculover666 ? 作者:Mculover666 ? 2021-11-16 09:23 ? 次閱讀

1. MultiTimer

今天給大家帶來的開源項目是 MultiTimer,一款可無限擴展的軟件定時器,作者0x1abin,目前收獲 95 個 star,遵循 MIT 開源許可協議。

MultiTimer 是一個軟件定時器擴展模塊,可無限擴展你所需的定時器任務,取代傳統的標志位判斷方式, 更優雅更便捷地管理程序的時間觸發時序。

項目地址:https://github.com/0x1abin/MultiTimer

2. 移植MultiTimer

2.1. 移植思路

開源項目在移植過程中主要參考項目的readme文檔,一般只需兩步:

  • ① 添加源碼到裸機工程中;
  • ② 實現需要的接口

2.2. 準備裸機工程

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

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

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

2.3. 添加MultiTimer到工程中

① 復制MultiTimer源碼到工程中

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

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

3. 使用MultiTimer

使用時包含頭文件:

#include "multi_timer.h"

如果遇到multi_timer.c文件中NULL宏定義報錯,則在multi_timer.h中添加頭文件即可。

3.1. 創建Timer對象

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

3.2. Timer回調函數

/* 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. 初始化并啟動Timer

始化定時器對象,注冊定時器回調處理函數,設置定時時間(ms),循環定時觸發時間:

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

3.4. Timer對象處理

在循環中調用Timer對象處理函數,處理函數會判斷鏈表上的每個定時器是否超時,如果超過,則拉起注冊的回調函數:

/* 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時基信號

MultiTimer中所有的定時器都是通過一個32位的計數值_timer_ticks來判斷的,所以需要一個硬件定時器提供時基信號,遞增該值。

本文中使用的是STM32HAL庫,所以通過Systick來提供,無需設置額外的定時器。

main.c文件的最后編寫Systick回調函數:

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

然后在stm32l4xx_it.c中調用該回調函數:

/**  * @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 */}

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

4. MultiTimer設計思想解讀

4.1. 軟件定時器設計思想

MultiTimer的設計比較簡潔。

設置一個計數值_timer_ticks不斷遞增,由定時器提供的中斷驅動,只計次數,不計時間,有了很大的自由度,一般時基信號設置為1ms一次:

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

在程序運行時循環比較定時器設置的超時值是否大于當前_timer_ticks的計數值,如果是則再次判斷是否重復計數值是否為0,是則停止定時器,完成單次計時效果,否則修改計數值,最后拉起注冊到該定時器的回調函數執行:

/**  * @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的代碼少,非常適合拿來學習單鏈表的操作,學習數據結構的過程是乏味的,不如直接來個實例看看是如何操作的。

① 鏈表的節點設計為一個軟件定時器,所以理論上支持的定時器數量只受內存限制。

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

定時器初始化函數timer_init就是初始化一個鏈表節點:

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;}

② 設置鏈表頭指針,只需知道頭指針就能完成對整個單鏈表的操作:

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

③ 向單鏈表增加一個節點

向單鏈表增加一個節點有三種方式:

  • 在單鏈表尾部增加一個節點
  • 在單鏈表頭部增加一個節點
  • 在單鏈表中間增加一個節點

MultiTimer中所有的結點都是定時器,每個定時器之間相互獨立,不存在先后次序關系,所以無論加到中間,還是加到尾部,還是加到頭部,最后的功能都是一樣的,但是在插入算法上有優劣性能之分。

先來看看再單鏈表尾部增加一個節點的算法:b4a1d22c-4441-11ec-b939-dac502259ad0.gif( 我會動哦 )

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

這種算法理解簡單,實現簡單,但是算法時間復雜度秒變為O(n),當n很大時,插入一個節點的時間就會非常久。

再來看看在鏈表頭部插入一個新節點的情況:

(我會動哦)

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

這里第二種頭部插入節點的算法時間復雜度依然是O(n),emmm?

其實,這里因為單鏈表節點是定時器,在插入的時候需要對整個鏈表進行判斷,避免重復添加同樣的定時器節點,所以無論任何一種算法,都需要對單鏈表進行遍歷。

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

④ 單鏈表刪除其中一個節點

刪除單鏈表的節點時,因為節點自身只保存有下一個節點的指針,并沒有指向上一個節點的指針,所以不能直接入手刪除節點,那么如何刪除單鏈表的節點呢?

方法是:設置二級指針(指向Timer類型指針的指針),通過遍歷鏈表的方式來尋找節點中next指針指向刪除節點的那個節點,代碼如下。

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;  }}

責任編輯:haq
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 軟件
    +關注

    關注

    69

    文章

    4968

    瀏覽量

    87658
  • 定時器
    +關注

    關注

    23

    文章

    3251

    瀏覽量

    114981

原文標題:MultiTimer,一款可無限擴展的軟件定時器

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    定時器的基本組成和工作模式

    定時器是計算機或電子設備中常見的個硬件或軟件組件,其主要功能是測量和控制時間的流逝。它在各種應用中起著至關重要的作用,如操作系統調度、多媒體播放、網絡通信、工業自動化控制以及家電設備的定時
    的頭像 發表于 08-19 18:28 ?1429次閱讀

    定時器的工作方式介紹

    定時器是計算機和嵌入式系統中常見的種硬件模塊,用于實現定時和計數功能。定時器的工作方式通常由組寄存
    的頭像 發表于 07-12 10:29 ?1027次閱讀

    定時器相關的寄存有哪些類型

    在微控制編程中,定時器種非常常見的功能模塊,用于實現各種定時和計數功能。定時器的工作原理是通過內部的計數
    的頭像 發表于 07-12 10:25 ?985次閱讀

    鴻蒙開發系統基礎能力:Timer定時器

    設置定時器,該定時器定時器到期后執行個函數。
    的頭像 發表于 06-28 11:33 ?1021次閱讀
    鴻蒙開發系統基礎能力:Timer<b class='flag-5'>定時器</b>

    長持續時間定時器電路圖 時間定時器的工作原理和功能

    時間定時器種用于計時和調度任務的工具。它允許我們在特定的時間間隔內執行某個任務,或者在特定的時間點執行某個操作。定時器在計算機系統中的應用非常廣泛,從操作系統的任務調度、網絡傳輸的控制到實時系統
    的頭像 發表于 06-24 17:34 ?2030次閱讀
    長持續時間<b class='flag-5'>定時器</b>電路圖 時間<b class='flag-5'>定時器</b>的工作原理和功能

    如何實現軟件定時器

    在Linux,uC/OS,FreeRTOS等操作系統中,都帶有軟件定時器,原理大同小異。典型的實現方法是:通過個硬件定時器產生固定的時鐘節拍,每次硬件
    的頭像 發表于 04-29 11:00 ?686次閱讀

    s7200定時器的五種故障介紹

    定時器或CPU故障:如果定時器本身或PLC的CPU出現故障,也可能導致定時器無法復位。此時,需要檢查定時器和CPU的工作狀態,確保其正常運行。
    的頭像 發表于 04-03 17:08 ?2544次閱讀

    ?PLC定時器介紹

    定時器是PLC中重要的編程元件,是累計時間增量的內部器件。大部分自動控制領域都需要定時器進行延時控制,靈活地使用定時器可以編制出復雜的控制程序。
    發表于 03-22 12:36 ?2468次閱讀
    ?PLC<b class='flag-5'>定時器</b>介紹

    使用555定時器的可調雙定時器電路

    定時器 IC 555 是最通用和最常用的 IC 之,因為它的應用范圍更廣,如 PWM放大器、延遲定時器、開關電路、占空比選擇、時鐘脈沖發生
    的頭像 發表于 02-25 15:16 ?2285次閱讀
    使用555<b class='flag-5'>定時器</b>的可調雙<b class='flag-5'>定時器</b>電路

    定時器原理能控制馬達嗎為什么

    定時器原理可以用于控制馬達。馬達是種將電能轉換為機械能的設備,通常由電動機和傳動裝置組成。定時器種電子設備,用來生成和計時精確而穩定的時間信號。通過將
    的頭像 發表于 01-23 15:21 ?687次閱讀

    555定時器可以構成哪三種電路 555定時器屬于時序邏輯電路嗎

    555定時器一款廣泛應用于各種電子設備中的集成電路,它能夠創建不同的電路以滿足多種定時和脈沖生成需求。在本文中,我將詳細介紹555定時器能夠構成的三種常見電路,并回答其是否屬于時序邏
    的頭像 發表于 01-22 10:21 ?3293次閱讀

    555定時器的基本功能 555定時器的工作原理及其應用

    555定時器種非常常見和常用的集成電路,它具有廣泛的應用領域,例如計時、頻率分頻、脈沖寬度調制等。本文將詳細介紹555定時器的基本功能、工作原理以及應用。 、555
    的頭像 發表于 01-18 11:12 ?1.6w次閱讀

    時間定時器開關怎樣設置時間

    時間定時器種常見的設備,用于按照設定的時間自動開關電器或進行其他指定操作。通過設定定時器的開關時間,我們可以讓電器在特定的時間自動打開或關閉,這在我們日常生活中非常常見,比如在早上設定鬧鐘來叫醒
    的頭像 發表于 01-16 16:32 ?4682次閱讀

    AWTK 開源串口屏開發(6) - 定時器的用法

    定時器是個常用的功能,AWTK串口屏提供了豐富的定時器函數,用于定時器的啟動、停止、暫停、恢復、修改和重置等功能,本文以計時的例子來介紹定時器
    的頭像 發表于 01-13 08:24 ?590次閱讀
    AWTK 開源串口屏開發(6) - <b class='flag-5'>定時器</b>的用法

    AT32 定時器配置中pr和div的作用

    AT32定時器是51系列單片機中的定時器,可以實現多種定時功能。在AT32定時器中,pr和div是兩個相關的參數,用于配置
    的頭像 發表于 01-08 10:12 ?1341次閱讀
    主站蜘蛛池模板: 国产精品人妻在线观看| 色色激情网| 欧美 日韩 亚洲 在线| 亚洲欧美精品无码一区二在线| 超级碰碰青草久热国产| 伦理片 qvod| 中国欧美日韩一区二区三区 | 最新国产在线视频| 精品无码久久久久久久久| 午夜理伦片免费| 国产a级黄色毛片| 神马伦理2019影院不卡片| 成人免费视频一区| 人妖操女人| 成 人 动漫3d 在线看| 我的美女房东未删减版免费观看| 成3d漫二区三区四区| 香蕉久久av一区二区三区| 国产精品日本无码久久一老A| 一本色道久久综合一区 | 久久精品国产eeuss| 一本之道高清在线观看免费| 欧美黑白配性xxxxx| 成人免费一级毛片在线播放视频| 掀开奶罩边躁狠狠躁软学生| 久久这里有精品| 99午夜视频| 青青久在线| 国产99久久久国产精品成人| 一区二区中文字幕在线观看| 妈妈的朋友6未删减版完整在线| 999久久久无码国产精蜜柚| 男人私gay挠脚心vk视频| AV色蜜桃一区二区三区| 小小水蜜桃视频高清在线播放| 久久这里只精品国产99re66| 国产福利秒拍weipai.ee| 亚洲精品久久久久无码AV片软件| 韩国伦理电影在线神马网| 亚洲字幕在线观看| 日本学生VIDEOVIDEOS更新|