STM32系列—並行定時函數(軟件定時器)實現


  文章標題雖然是STM32系列,其實這個思路適用於所有MCU。

  在上一篇文章STM32系列(HAL庫)—Delay函數重寫中,對Delay延時函數進行了重寫,文章中也有提到,延時函數是串行的思維,MCU將會等在那個地方,沒辦法執行其他任務。因此,本文會提供一種思路來實現並行的定時函數。

  首先,要實現定時函數,那么首先可肯定需要定時器,我相信市面上可以看到是MCU,定時器基本上都是標配,以STM32為例,我們選擇其中一個定時器作為一個基准定時。

  然后,需要設計一個軟件定時器,包含定時器名稱,定時器周期,定時器計數,然后就是回調函數,如下面代碼所示:

  typedef uint8_t timer_id_t; //定時器名稱

  typedef void (*timer_cb_t)(timer_id_t time_name);//定時器回調函數格式

  typedef struct

  {

  timer_id_t timer_name;

  uint16_t count;

  uint16_t period;

  timer_cb_t timer_cb;

  }system_timer_t; //軟件定時器結構體

  #define SYSTEM_TIMER_NUM 32//軟件定時器總數,該數目可以增加,會消耗RAM資源

  static system_timer_t system_timer[SYSTEM_TIMER_NUM];//定義軟件定時器

  然后,我這邊的思路如下:system_timer中的32個定時器中timer_name都初始化為一個確定一個值,作為一個無效值,當要啟動軟件定時器時,首先要個某一個軟件定時器確定一個timer_name。當STM32的硬件定時器1ms中斷出現時,查詢一下哪一個軟件定時器的timer_name不是無效值,那么它對應的count值會加1,當count值和period值相同時,如果有回調函數時,調用timer_cb的回調函數,如果沒有就釋放軟件定時器資源。

  那么先對軟件定時器進行初始化:

  #define TIMER_INDEX_INVALID SYSTEM_TIMER_NUM //無效的定時器索引值

  #define TIMER_ID_INVALID 0xFF//無效的軟件定時器Name

  void system_timer_init()

  {

  uint8_t temp;

  //將所有軟件定時器的Timer_name初始化為無效值

  for(temp=0;temp<SYSTEM_TIMER_NUM;temp++)

  {

  system_timer[temp].timer_name=TIMER_ID_INVALID;

  }

  system_timer_status.timer_current_num=0;

  }

  void system_timer_enable()

  {

  //使能硬件定時器

  HAL_TIM_Base_Start_IT(&htim2);

  }

  void system_timer_disable()

  {

  //停止硬件定時器

  HAL_TIM_Base_Stop_IT(&htim2);

  }

  最后對軟件定時器的操作如下:

  //根據定時器名稱,反向定位軟件定時器數組index

  unsigned char get_timer_index(timer_id_t timer_name)

  {

  unsigned char index;

  for(index=0;index<SYSTEM_TIMER_NUM;index++)

  {

  //查詢軟件定時器數組是否有相應的定時器名稱

  if(system_timer[index].timer_name==timer_name)

  {

  break;

  }

  }

  return index;//返回相應的軟件定時器索引

  }

  //啟動軟件定時器

  //timer_name:定時器名稱,period:定時器周期,timer_cb:回調函數

  //返回值:status:0x01表示啟動成功,0x00表示啟動失敗,軟件定時器已滿

  unsigned char timer_start(timer_id_t timer_name, uint16_t period, timer_cb_t timer_cb)

  {

  unsigned char status=0x00;

  uint8_t index;

  if((timer_name!=TIMER_ID_INVALID)&&(period >0)&&(get_timer_index(timer_name)>=TIMER_INDEX_INVALID))

  {

  for(index=0;index < SYSTEM_TIMER_NUM;index++)

  {

  //找到空閑軟件定時器資源

  if(system_timer[index].timer_name==TIMER_ID_INVALID)

  {

  system_timer[index].count=0;//清空定時器計數位

  system_timer[index].period=period;//記錄定時器設定周期

  system_timer[index].timer_cb=timer_cb;//記錄回調函數位置

  system_timer[index].timer_name=timer_name;//記錄軟件定時器名稱,占據軟件定時器的一個資源

  status=0x01;

  break;

  }

  }

  }

  return status;

  }

  //停止軟件定時器,釋放定時器資源

  //timer_name:定時器名稱

  void timer_stop(timer_id_t timer_name)

  {

  uint8_t index=get_timer_index(timer_name);//查看是否有該定時器名稱的定時器

  if(index<TIMER_INDEX_INVALID)

  {

  system_timer[index].timer_name=TIMER_ID_INVALID;//釋放軟件定時器資源

  system_timer[index].count=0;

  system_timer[index].timer_cb=NULL;

  }

  }

  //查看軟件定時器是否已經在運行

  unsigned char timer_is_running(timer_id_t timer_name)

  {

  unsigned char status=0x00;

  if(get_timer_index(timer_name)!=TIMER_INDEX_INVALID)

  {

  status=0x01;

  }

  return status;

  }

  //硬件定時器中斷處理函數

  //htim:硬件定時器句柄

  void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

  {

  uint8_t index;

  if(htim->Instance==TIM2)//確定是硬件定時器2產生的中斷

  {

  //查詢是否有軟件定時器在使用

  for(index=0;index<SYSTEM_TIMER_NUM;index++)

  {

  if(system_timer[index].timer_name!=TIMER_ID_INVALID)

  {

  system_timer[index].count++;

  if(system_timer[index].count >=system_timer[index].period)//定時結束

  {

  //看是否有回調函數,如果有回調函數,那么就執行

  if(system_timer[index].timer_cb!=NULL)

  {

  system_timer[index].timer_cb(system_timer[index].timer_name);//執行回調函數

  }

  //釋放定時器資源

  system_timer[index].count=0;

  system_timer[index].timer_cb=NULL;

  system_timer[index].timer_name=TIMER_ID_INVALID;

  }

  }

  }

  }

  以上就是軟件定時器的實現思路,因為有回調函數的存在,可以放心大膽的並行執行其他任務,當定時結束,將會自動回調到相應的函數位置。

  下一篇文章,我會大概講述一下,這個軟件定時器的使用示例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM