STM32F407VET6 底层驱动之定时器寄存器封装

  因为在项目中引入了操作系统,所以使用定时器的地方不多,因此这里只用了三个定时器,每个定时器可以注册十个任务。

1、定时器封装接口如下:

  a、定时器初始化:unsigned int tim_init(eTimType_t tim, unsigned short interval, unsigned char prio)

  b、定时器禁能:unsigned int tim_stop(eTimType_t tim)

  c、定时器重新开始计时:unsigned int tim_restart(eTimType_t tim)

  d、定时器任务注册:unsigned int tim_task_append(void (*pfunc)(void *), const void *parg, unsigned int interval, eTimType_t tim)

  e、定时器任务删除:unsigned int tim_task_delete(void (*pfunc)(void *), eTimType_t tim)

  f、定时器任务禁能:unsigned int tim_task_stop(void (*pfunc)(void *), eTimType_t tim)

  g、定时器任务使能:unsigned int tim_task_start(void (*pfunc)(void *), eTimType_t tim)

2、定时器模块对外开放的枚举类型如下:

// 定时器类型
typedef enum _eTimType
{
   eTIM2,
   eTIM3,
   eTIM4,
   eTIM_COUNT, // 注:这不是定时器类型,不可删除,仅用做数量统计
}eTimType_t;

#define TIM_TASK_COUNT ((unsigned char)10) // 每个定时器支持的任务个数

3、定时器模块代码实现如下:

// 定时器任务数据结构
#pragma pack(push, 1)
typedef struct _sTimTaskList
{
   bool enable; // 任务使能标志位
   unsigned int task_count; // 定时任务计数器
   unsigned int tim_interval; // 定时中断时间间隔,单位:微秒
   unsigned int task_interval; // 定时任务执行时间间隔,单位:毫秒
   void (*pCallBack)(void *); // 定时器回调函数指针
   void *parg; // 定时器回调函数形参
}sTimTaskList_t;
#pragma pack(pop)

// 定时器任务链表(STM32F407最多支持8个定时器)
static sTimTaskList_t sTimTaskList[eTIM_COUNT][TIM_TASK_COUNT] = {0};
/********************************************************
 * 函数功能:定时器中断优先级设置(组4),注意优先级不能超过设
            定的组的范围否则会有意想不到的错误。组划分如下:
       组0:0位抢占优先级,4位响应优先级
       组1:1位抢占优先级,3位响应优先级
       组2:2位抢占优先级,2位响应优先级
       组3:3位抢占优先级,1位响应优先级
       组4:4位抢占优先级,0位响应优先级
   抢占优先级和响应优先级的数值越小,优先级越高,处理器优
   先比较抢占优先级然后再看响应优先级。
 * 形    参:prio:抢占优先级(分组4的响应优先级固定为0)
    channel:中断通道
 * 返 回 值:无
 ********************************************************/
static void tim_nvic_set(unsigned char prio, unsigned char channel)
{
// unsigned int temp, temp1;
 
   // 设置分组
   unsigned char nvic_group = 4; // 0 - 4
// temp1 = (~nvic_group) & 0x07; // 取后三位
// temp1 = temp1 << 8;
// temp = SCB->AIRCR;  // 读取先前的设置
// temp &= 0x0000F8FF; // 清空先前分组
// temp |= 0x05FA0000; // 写入钥匙
// temp |= temp1;
// SCB->AIRCR = temp; // 设置分组
 
   // 设置NVIC
   unsigned int temp;
   unsigned char sub_prio = 0; // 分组4的响应优先级固定为0
 
   // 注:优先级的设置必须要大于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
   // 否则不能在中断服务函数中调用FreeRTOS相关的API函数
   if(prio <= 5)
   {
      prio = 6;
   }
   else if(prio > 15)
   {
      prio = 15;
   }
 
   temp = prio << (4 - nvic_group);
   temp |= sub_prio & (0x0F >> nvic_group);
   temp = temp & 0xF; // 取低四位
   NVIC->ISER[channel >> 5] |= 1 << (channel % 32); // 使能中断位(要清除的话,设置ICER对应位为1即可)
   NVIC->IP[channel] |= temp << 4; // 设置响应优先级和抢断优先级
}

/********************************************************
 * 函数功能:定时器初始化(初始化完成后定时器自动启动,重复初始化会将该定时器下的所有任务清空)
 * 形    参:tim:指定定时器(定时器时钟频率1MHz,递增计数模式)
             interval:定时器中断时间间隔,单位:微秒
             prio:中断优先级(范围:6 - 15,数值越小优先级越高)
 * 返 回 值:0=成功
             1=定时器类型错误
             2=定时周期错误
 ********************************************************/
unsigned int tim_init(eTimType_t tim, unsigned short interval, unsigned char prio)
{
   if(tim >= eTIM_COUNT)
   {
      return 1;
   }
   if(interval == 0)
   {
      return 2;
   }
   // 清空该定时器下的所有任务
   for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
   {
      sTimTaskList[tim][i].parg = NULL;
      sTimTaskList[tim][i].enable = false;
      sTimTaskList[tim][i].task_count = 0;
      sTimTaskList[tim][i].pCallBack = NULL;
      sTimTaskList[tim][i].task_interval = 0;
      sTimTaskList[tim][i].tim_interval = interval;
   }
   unsigned char bit = 0;
   unsigned char IRQn = 0;
   TIM_TypeDef *TIMx = NULL;
   switch(tim)
   {
      case eTIM2: TIMx = TIM2; IRQn = TIM2_IRQn; bit = 0; break;
      case eTIM3: TIMx = TIM3; IRQn = TIM3_IRQn; bit = 1; break;
      case eTIM4: TIMx = TIM4; IRQn = TIM4_IRQn; bit = 2; break;
      default: return 1;
   }
   // 高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11的时钟来源是APB2总线
   // 通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7的时钟来源是APB1总线
   RCC->APB1ENR |= 0x1 << bit; // 定时器时钟使能
   TIMx->CNT = 0;   // 计数器清零
   TIMx->ARR = interval; // 设定计数器自动重装值
   TIMx->PSC = 84 - 1;  // 预分频器(时钟频率1MHz)
   TIMx->DIER |= 0x01;  // 使能更新中断(计数器更新)
   TIMx->CR1 |= 0x01;  // 使能计数器(递增模式)
   tim_nvic_set(prio, IRQn); // 抢占优先级10,响应优先级0,优先级分组4
   return 0;
}

/********************************************************
 * 函数功能:定时器停止计数
 * 形    参:tim:指定定时器
 * 返 回 值:0=成功
             1=定时器类型错误
 ********************************************************/
unsigned int tim_stop(eTimType_t tim)
{
   if(tim >= eTIM_COUNT)
   {
      return 1;
   }
   TIM_TypeDef *TIMx = NULL;
   switch(tim)
   {
      case eTIM2: TIMx = TIM2; break;
      case eTIM3: TIMx = TIM3; break;
      case eTIM4: TIMx = TIM4; break;
      default: return 1;
   }
   TIMx->CNT = 0;   // 计数器清零
   TIMx->DIER &= ~0x01; // 禁能更新中断(计数器更新)
   TIMx->CR1 &= ~0x01;  // 禁能计数器(递增模式)
   return 0;
}

/********************************************************
 * 函数功能:定时器重新开始计数
 * 形    参:tim:指定定时器
 * 返 回 值:0=成功
             1=定时器类型错误
 ********************************************************/
unsigned int tim_restart(eTimType_t tim)
{
   if(tim >= eTIM_COUNT)
   {
      return 1;
   }
   TIM_TypeDef *TIMx = NULL;
   switch(tim)
   {
      case eTIM2: TIMx = TIM2; break;
      case eTIM3: TIMx = TIM3; break;
      case eTIM4: TIMx = TIM4; break;
      default: return 1;
   }
   TIMx->CNT = 0;  // 计数器清零
   TIMx->DIER |= 0x01; // 使能更新中断(计数器更新)
   TIMx->CR1 |= 0x01; // 使能计数器(递增模式)
   return 0;
}

/********************************************************
 * 函数功能:定时器任务追加(任务立即进入运行状态)
 * 形    参:pfunc:任务函数指针
             parg:任务函数形参
             interval:任务执行时间间隔,单位:微秒
             tim:指定定时器
 * 返 回 值:0=成功
             1=任务链表满了,无法再追加任务
             2=任务函数指针为NULL
             3=定时器类型错误
             4=任务执行时间间隔错误
 * 开 发 者:王志超
 * 维护日期:2020年5月5日
 * 修订日志:开发
 ********************************************************/
unsigned int tim_task_append(void (*pfunc)(void *), const void *parg, unsigned int interval, eTimType_t tim)
{
   if(pfunc == NULL)
   {
      return 2;
   }
   if(tim >= eTIM_COUNT)
   {
      return 3;
   }
   if(interval == 0)
   {
      return 4;
   }
   for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
   {
      if(sTimTaskList[tim][i].enable == false)
      {
         sTimTaskList[tim][i].task_count = 0;
         sTimTaskList[tim][i].task_interval = interval; // 单位:微秒
         sTimTaskList[tim][i].parg = (void *)parg;
         sTimTaskList[tim][i].pCallBack = pfunc;
         sTimTaskList[tim][i].enable = true;
         return 0; // 任务添加成功
      }
   }
   return 1; // 任务链表满了,无法再追加任务
}

/********************************************************
 * 函数功能:定时器任务删除
 * 形    参:pfunc:任务函数指针
             tim:指定定时器
 * 返 回 值:0=成功
             1=未找到与之匹配的任务
             2=任务函数指针为NULL
             3=定时器类型错误
 ********************************************************/
unsigned int tim_task_delete(void (*pfunc)(void *), eTimType_t tim)
{
   if(pfunc == NULL)
   {
      return 2;
   }
   if(tim >= eTIM_COUNT)
   {
      return 3;
   }
   for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
   {
      if(sTimTaskList[tim][i].pCallBack == pfunc)
      {
         sTimTaskList[tim][i].enable = false;
         sTimTaskList[tim][i].parg = NULL;
         sTimTaskList[tim][i].task_count = 0;
         sTimTaskList[tim][i].tim_interval = 0;
         sTimTaskList[tim][i].task_interval = 0;
         sTimTaskList[tim][i].pCallBack = NULL;
         return 0;
      }
   }
   return 1; // 未找到与之匹配的任务
}

/********************************************************
 * 函数功能:定时器任务停止运行
 * 形    参:pfunc:任务函数指针
             tim:指定定时器
 * 返 回 值:0=成功
             1=未找到与之匹配的任务
             2=任务函数指针为NULL
             3=定时器类型错误
 ********************************************************/
unsigned int tim_task_stop(void (*pfunc)(void *), eTimType_t tim)
{
   if(pfunc == NULL)
   {
      return 2;
   }
   if(tim >= eTIM_COUNT)
   {
      return 3;
   }
   for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
   {
      if(sTimTaskList[tim][i].pCallBack == pfunc)
      {
         sTimTaskList[tim][i].enable = false;
         return 0; // 任务停止成功
      }
   }
   return 1; // 未找到与之匹配的任务
}

/********************************************************
 * 函数功能:定时器任务启动运行(从上次的停止时的状态继续运行)
 * 形    参:pfunc:任务函数指针
             tim:指定定时器
 * 返 回 值:0=成功
             1=未找到与之匹配的任务
             2=任务函数指针为NULL
             3=定时器类型错误
 ********************************************************/
unsigned int tim_task_start(void (*pfunc)(void *), eTimType_t tim)
{
   if(pfunc == NULL)
   {
      return 2;
   }
   if(tim >= eTIM_COUNT)
   {
      return 3;
   }
   for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
   {
      if(sTimTaskList[tim][i].pCallBack == pfunc)
      {
         sTimTaskList[tim][i].enable = true;
         return 0; // 任务启动成功
      }
   }
   return 1; // 未找到与之匹配的任务
}

/********************************************************
 * 函数功能:定时器中断任务处理函数(中断专用)
 * 形    参:无
 * 返 回 值:无
 ********************************************************/
static void tim_isr_callback(TIM_TypeDef *TIMx, eTimType_t tim)
{
   if((TIMx->SR & 0x0001) == 0x0001) // 溢出中断
   {
      TIMx->SR &= ~(0x0001);//清除中断标志位
  
      // 执行定时器任务
      for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
      {
         if(sTimTaskList[tim][i].enable == true)
         {
            sTimTaskList[tim][i].task_count += sTimTaskList[tim][i].tim_interval; // 单位:微秒
            if(sTimTaskList[tim][i].task_count >= sTimTaskList[tim][i].task_interval)
            {
               sTimTaskList[tim][i].task_count = 0;
               if(sTimTaskList[tim][i].pCallBack != NULL)
               {
                  sTimTaskList[tim][i].pCallBack(sTimTaskList[tim][i].parg); // 执行任务
               }
               else
               {
                  // 任务函数为NULL,无需做任何操作
               }
            }
            else
            {
               // 任务执行时间未到达,无需做任何操作
            }
         }
         else
         {
            // 任务处于暂停或停止状态,无需做任何操作
         }
      }
   }
}

/********************************************************
 * 函数功能:定时器2中断服务函数(中断时间间隔请查看初始化时的设置)
 * 形    参:无
 * 返 回 值:无
 ********************************************************/
void TIM2_IRQHandler(void)
{
   tim_isr_callback(TIM2, eTIM2);
}

/********************************************************
 * 函数功能:定时器3中断服务函数(中断时间间隔请查看初始化时的设置)
 * 形    参:无
 * 返 回 值:无
 ********************************************************/
void TIM3_IRQHandler(void)
{
   tim_isr_callback(TIM3, eTIM3);
}

/********************************************************
 * 函数功能:定时器4中断服务函数(中断时间间隔请查看初始化时的设置)
 * 形    参:无
 * 返 回 值:无
 ********************************************************/
void TIM4_IRQHandler(void)
{
   tim_isr_callback(TIM4, eTIM4);
}

原文地址:https://www.cnblogs.com/icode-wzc/p/12910488.html