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