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

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

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

3天內不再提示

單片機軟件定時器的實現方法

CHANBAEK ? 來源:固件工人 ? 作者:固件工人 ? 2023-01-17 15:14 ? 次閱讀

1.1 背景

目前市面上的單片機基本都帶有硬件定時器功能,單片機應用程序開發中也經常會用到定時器進行一些和時間相關的開發,比如延時或者周期性地執行一些操作。單片機的硬件定時器個數一般都是固定的,而且一些低端單片機的定時器個數一般都比較少,在一些有多個周期性操作的應用場合就無法滿足要求。這時,就可以基于硬件定時器派生出軟件定時器,來滿足這種多種周期性或多個單次延時操作的需求。軟件定時器的優點就是個數可以根據實際需求進行靈活配置,而且可以實現多種不同的定時周期。

1.2 測試平臺

這里使用的開發環境和相關硬件如下。

  • 操作系統:Ubuntu 20.04.2 LTS x86_64(使用uname -a命令查看)
  • 集成開發環境(IDE):Eclipse IDE for Embedded C/C++ Developers,Version: 2021-06 (4.20.0)
  • 硬件開發板:STM32F429I-DISCO
  • 本文對應的例程代碼鏈接如下。

https://download.csdn.net/download/goodrenze/85106391

1.3 軟件定時器實現方法

這里就結合開發板STM32F429I-DISCO上的STM32F429ZI的單片機來演示軟件定時器的實現方法。

一般定時器的計數方式有2種:一種是單次定時,即定時時間到了之后,自動停止定時;另一種是周期定時,定時時間到了之后,自動按照之前的定時周期重新定時。對于周期定時,可以手動進行定時器的啟動、關閉和刪除。

下面講解軟件定時器的實現步驟。

1)由于軟件定時器是基于硬件定時器的,所以需要先初始化一個硬件定時器,并啟動硬件定時器。這里使用STM32F429ZI的硬件定時器7,定時器的定時周期為10ms,即每10ms產生一次定時器中斷。初始化代碼如下。

TIM_HandleTypeDef    Tim7Handle;
uint8_t InitTim7(uint32_t period_ms)
{
  uint16_t uwPrescalerValue;


  if(0 == period_ms)
  {
    return 1;
  }


  __HAL_RCC_TIM7_CLK_ENABLE();


  HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);


  HAL_NVIC_EnableIRQ(TIM7_IRQn);


  /* Compute the prescaler value to have TIM7 counter clock equal to 10 KHz */
  uwPrescalerValue = (uint32_t) ((SystemCoreClock /2) / 10000) - 1;


  /* Set TIM7 instance */
  Tim7Handle.Instance = TIM7;
  Tim7Handle.Init.Period = period_ms * 10 - 1;
  Tim7Handle.Init.Prescaler = uwPrescalerValue;
  Tim7Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  Tim7Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
  if(HAL_TIM_Base_Init(&Tim7Handle) != HAL_OK)
  {
    return 1;
  }


  /* Start the TIM Base generation in interrupt mode */
  if(HAL_TIM_Base_Start_IT(&Tim7Handle) != HAL_OK)
  {
    return 1;
  }


  return 0;
}

2)硬件定時器定時時間到了之后,會產生中斷,所以需要實現定時器中斷處理函數。這里基于STM32的HAL進行開發,所以在定時器的中斷入口函數中直接調用HAL_TIM_IRQHandler()函數,然后實現實際的中斷處理回調函數HAL_TIM_PeriodElapsedCallback()。對應的代碼如下。其中調用的軟件定時器更新函數會在后面介紹。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim == &Tim7Handle)
  {
    SwTimerUpdateCount();
  }
}

3)設計軟件定時器對應的結構體。按照軟件定時器的實際使用特點,必須要包含定時器計數值和周期定時器的重裝載值,另外還要有定時器時間到之后需要執行的回調函數。對應的軟件定時器結構體如下所示。當結構體中的TimerCount和TimerReload都為0時,說明軟件定時器處于空閑狀態,可以分配使用;如果TimerCount非0,而TimerReload為0,說明軟件定時器是單次定時器;如果TimerCount和TimerReload都非0,說明軟件定時器是周期定時器。

typedef void (*TimerCallbackFunc)(void);


typedef struct _SwTimer_t
{
  uint32_t TimerCount;
  uint32_t TimerReload;
  TimerCallbackFunc TimerCallback;
}SwTimer_t;

4)這里將軟件定時器設置成10個,可以通過宏定義來設置軟件定時器個數。使用軟件定時器結構體定義一個具有10個定時器的數組。如下代碼所示。

#define SW_TIMER_NUM    10
SwTimer_t SwTimer[SW_TIMER_NUM];

5)軟件定時器復位函數,用于實現所有軟件定時器的重置操作,重置后,所有軟件定時器都處于空閑狀態,可供分配使用。函數代碼如下。

void SwTimerReset(void)
{
  uint8_t i;


  for(i = 0; i < SW_TIMER_NUM; i++)
  {
    SwTimer[i].TimerCount = 0;
    SwTimer[i].TimerReload = 0;
    SwTimer[i].TimerCallback = 0;
  }
}

6)啟動單次定時器函數,用于實現單次定時,定時時間到了之后,執行對應回調函數,并停止定時和釋放定時器資源。函數代碼如下。如果啟動成功,函數返回定時器的索引號(該值小于定時器個數值);啟動失敗,返回的定時器索引號等于定時器的個數。

uint8_t SwTimerStartSingleTimer(uint32_t single_ms, TimerCallbackFunc TimerCallback)
{
  uint8_t i;


  single_ms /= MINI_PERIOD_MS;
  if(0 == single_ms)
  {
    single_ms = 1;
  }
  for(i = 0; i < SW_TIMER_NUM; i++)
  {
    if((SwTimer[i].TimerCount == 0) && (SwTimer[i].TimerReload == 0))
    {
      SwTimer[i].TimerCount = single_ms;
      SwTimer[i].TimerCallback = TimerCallback;
      break;
    }
  }


  return i;
}

7)添加周期定時器函數,用于添加一個新的周期定時器但不啟動定時,需要手動啟動定時器。函數代碼如下。如果添加成功,函數返回定時器的索引號(該值小于定時器個數值);添加失敗,返回的定時器索引號等于定時器的個數。

uint8_t SwTimerAddPeriodTimer(uint32_t period_ms, TimerCallbackFunc TimerCallback)
{
  uint8_t i;


  period_ms /= MINI_PERIOD_MS;
  if(0 == period_ms)
  {
    period_ms = 1;
  }
  for(i = 0; i < SW_TIMER_NUM; i++)
  {
    if((SwTimer[i].TimerCount == 0) && (SwTimer[i].TimerReload == 0))
    {
      SwTimer[i].TimerReload = period_ms;
      SwTimer[i].TimerCallback = TimerCallback;
      break;
    }
  }


  return i;
}

8)啟動周期定時器函數,用于啟動指定定時器索引號的周期定時器開始定時。函數代碼如下。如果啟動成功,函數返回定時器的索引號(該值小于定時器個數值);啟動失敗,返回的定時器索引號等于定時器的個數。

uint8_t SwTimerStartPeroidTimer(uint8_t timer_no)
{
  if(SW_TIMER_NUM <= timer_no)
  {
    return SW_TIMER_NUM;
  }
  else if((SwTimer[timer_no].TimerCount == 0) && (SwTimer[timer_no].TimerReload == 0))
  {
    return SW_TIMER_NUM;
  }
  else
  {
    SwTimer[timer_no].TimerCount = SwTimer[timer_no].TimerReload;
    return timer_no;
  }
}

9)停止定時器函數,用于結束指定定時器索引號的定時器的定時,可用于停止單次或周期定時器。函數代碼如下。如果停止成功,函數返回定時器的索引號(該值小于定時器個數值);停止失敗,返回的定時器索引號等于定時器的個數。

uint8_t SwTimerStopTimer(uint8_t timer_no)
{
  if(SW_TIMER_NUM <= timer_no)
  {
    return SW_TIMER_NUM;
  }
  else
  {
    SwTimer[timer_no].TimerCount = 0;
    return timer_no;
  }
}

10)刪除周期定時器函數,用于結束指定定時器索引號的周期定時器的定時,并釋放定時器資源。函數代碼如下。如果刪除成功,函數返回定時器的索引號(該值小于定時器個數值);刪除失敗,返回的定時器索引號等于定時器的個數。

uint8_t SwTimerDeletePeroidTimer(uint8_t timer_no)
{
  if(SW_TIMER_NUM <= timer_no)
  {
    return SW_TIMER_NUM;
  }
  else
  {
    SwTimer[timer_no].TimerCount = 0;
    SwTimer[timer_no].TimerReload = 0;
    return timer_no;
  }
}

11)軟件定時器計數值更新函數,用于更新每個已經啟動定時的軟件定時器的計數值,該函數必須在硬件定時器的中斷處理函數中調用。函數的實現思路是:遍歷所有的軟件定時器,如果遍歷到的定時器的計數值非0,則進行減1操作。如果減1后計數值為0,如果定時器的重裝載值非0,說明是周期定時器,需要將計數值更新成對應的重裝載值以便重新定時,同時執行對應的回調函數;如果定時器的重裝載值是0,說明是單次定時器,執行完回調函數后自動停止定時并釋放定時器資源。如果減1后計數值不為0,繼續遍歷更新后續的定時器,直到所有定時器都遍歷完畢。函數流程圖和對應代碼如下。

圖1 軟件定時器計數值更新函數

void SwTimerUpdateCount(void)
{
  uint8_t i;


  for(i = 0; i < SW_TIMER_NUM; i++)
  {
    if(SwTimer[i].TimerCount != 0)
    {
      SwTimer[i].TimerCount -= 1;
      if(SwTimer[i].TimerCount == 0)
      {
        if(SwTimer[i].TimerReload != 0)
        {
          SwTimer[i].TimerCount = SwTimer[i].TimerReload;
        }
        if(SwTimer[i].TimerCallback != 0)
        {
          SwTimer[i].TimerCallback();
        }
      }
    }
  }
}

12)軟件定時器的實際使用示例。代碼如下。

int main(void)
{
  uint8_t no;


  HAL_Init();


  /* Configure the system clock to 168 MHz */
  SystemClock_Config();


  BSP_LED_Init(LED3);
  BSP_LED_Init(LED4);
  InitTim7(MINI_PERIOD_MS);
  SwTimerReset();
  no = SwTimerAddPeriodTimer(500, ToggleLed3);
  if(no < SW_TIMER_NUM)
  {
    SwTimerStartPeroidTimer(no);
  }
#if 1
  no = SwTimerAddPeriodTimer(1000, ToggleLed4);
  if(no < SW_TIMER_NUM)
  {
    SwTimerStartPeroidTimer(no);
  }
#else
  no = SwTimerStartSingleTimer(5000, ToggleLed4);
#endif


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

    關注

    6037

    文章

    44561

    瀏覽量

    635584
  • STM32
    +關注

    關注

    2270

    文章

    10901

    瀏覽量

    356195
  • 軟件定時器
    +關注

    關注

    0

    文章

    18

    瀏覽量

    6760
  • 定時器
    +關注

    關注

    23

    文章

    3250

    瀏覽量

    114865
  • 函數
    +關注

    關注

    3

    文章

    4332

    瀏覽量

    62653
收藏 人收藏

    評論

    相關推薦

    單片機定時器的用法

    本章以CW32通用定時器為例介紹單片機定時器的用法。
    的頭像 發表于 01-04 10:37 ?1426次閱讀
    <b class='flag-5'>單片機</b><b class='flag-5'>定時器</b>的用法

    Winbond 51單片機定時器初值計算(工具軟件)

    Winbond 51單片機定時器初值計算(工具軟件)
    發表于 06-14 07:53 ?237次下載

    單片機視頻教程06:使用定時器方法

    《手把手教你學單片機單片機視頻教程06:使用定時器方法 單片機視頻教程06:使用定時器
    發表于 08-21 09:33 ?1.7w次閱讀
    <b class='flag-5'>單片機</b>視頻教程06:使用<b class='flag-5'>定時器</b>的<b class='flag-5'>方法</b>

    51單片機定時器計算軟件

    電子發燒友網站提供《51單片機定時器計算軟件.zip》資料免費下載
    發表于 08-10 12:48 ?1次下載

    基于51單片機定時器2的操作與實現

    基于51單片機定時器2的操作與實現,51單片機定時器2的使用!
    發表于 02-22 17:53 ?14次下載

    52單片機有幾個定時器?52單片機定時器1和52單片機定時器2程序對比

    52單片機有幾個定時器?STC89C52RC其實是有三個定時器單片機,STC89C52RC共有3個定時器,分別是T0、T1、T2。而51
    發表于 11-10 14:30 ?3.5w次閱讀

    如何基于51單片機利用定時器實現PWM的方法詳細概述

    51單片機是可以輸出PWM的,比較的麻煩。此時需要用到內部定時器實現,可用兩個定時器實現,也可以用一個
    的頭像 發表于 06-12 20:01 ?3.3w次閱讀

    ESP8266的管腳的控制和軟件定時器的使用

    先說定時器,ESP8266內部的定時器分為軟件定時器和硬件定時器。手冊中指出硬件定時器其實就跟
    的頭像 發表于 07-29 14:57 ?9521次閱讀
    ESP8266的管腳的控制和<b class='flag-5'>軟件</b><b class='flag-5'>定時器</b>的使用

    使用單片機實現定時器的程序免費下載

      本文檔的主要內容詳細介紹的是使用單片機實現定時器的程序免費下載。
    發表于 06-05 17:35 ?6次下載
    使用<b class='flag-5'>單片機</b><b class='flag-5'>實現</b><b class='flag-5'>定時器</b>的程序免費下載

    基于單片機定時器的設計方法

    單片機實現一個定時器只要對單片機里的特殊寄存進行設置就可以實現了,下面我與朋友們說說這個0到
    的頭像 發表于 11-02 16:58 ?1w次閱讀
    基于<b class='flag-5'>單片機</b>的<b class='flag-5'>定時器</b>的設計<b class='flag-5'>方法</b>

    基于51單片機定時器

    設計思路。這樣自己拿到任何型號的51單片機,只要有原理圖,都可以自主設計。博主剛接觸單片機,才疏學淺,可能會出現設計不足和錯誤,歡迎大家評論區交流。^ _ ^/********************************************************
    發表于 11-04 21:06 ?35次下載
    基于51<b class='flag-5'>單片機</b>的<b class='flag-5'>定時器</b>

    51單片機——定時器

    51單片機——定時器為什么使用定時器定時器原理?定時器設置中斷配置源代碼為什么使用定時器?之前
    發表于 11-11 16:36 ?40次下載
    51<b class='flag-5'>單片機</b>——<b class='flag-5'>定時器</b>

    51單片機定時器中斷

    定時器介紹:51單片機定時器屬于單片機的內部資源,其電路連接和運轉均在單片機的內部完成定時器
    發表于 11-11 19:36 ?7次下載
    51<b class='flag-5'>單片機</b><b class='flag-5'>定時器</b>中斷

    51單片機定時器/計數

    CPU的參與。3、51單片機中的 定時器/計數 是根據 機器內部的時鐘 或者是 外部的脈沖信號 對寄存中的數據加1。4、有了 定時器/計
    發表于 11-20 20:06 ?47次下載
    51<b class='flag-5'>單片機</b><b class='flag-5'>定時器</b>/計數<b class='flag-5'>器</b>

    51單片機定時器中斷

    定時器介紹:51單片機定時器屬于單片機的內部資源,其電路連接和運轉均在單片機的內部完成定時器
    發表于 11-20 20:36 ?15次下載
    51<b class='flag-5'>單片機</b><b class='flag-5'>定時器</b>中斷
    主站蜘蛛池模板: 亚洲欧美日本久久综合网站| 少妇高潮惨叫久久久久久电影| 嗯啊插的好深啊使劲抽视频| 亚洲伊人色| 国产全肉乱妇杂乱视频| 色琪琪无码成人AV视频| 超碰高清熟女一区二区| 人驴交f ee欧美| 边做边爱免费视频| 青柠在线观看免费播放电影| china chinese中国人玩| 男人J进入女人P免费狂躁| 2019香蕉在线观看直播视频| 久久婷婷色一区二区三区| 在线播放av欧美无码碰| 久久爽狠狠添AV激情五月| 伊人22222| 麻豆精品乱码WWW久久密| 最近中文字幕MV高清在线视频| 久久秋霞理伦片| 99re6久久热在线视频| 牛牛在线(正)精品视频| chinese情侣自拍啪hd| 日本全彩黄漫无遮挡| 国产精品99久久久精品无码 | 国产99在线视频| 午夜黄视频| 狠狠狠狠狠狠干| 123成人站| 日韩欧美 亚洲视频| 国产精品视频第一区二区三区| 亚洲高清在线视频| 久久综合色一综合色88中文| china年轻小帅脸直播飞机| 日操夜操天天操| 好嗨哟在线看片免费| 1级午夜影院费免区| 青春草国产成人精品久久| 国产精品成人影院| 在线 中文字幕| 日本视频中文字幕一区二区|