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

  • 相关阅读:
    LockFree的栈实现及与加锁实现的性能对比
    redis源码笔记-redis.conf
    【ASP.NET】应用程序、页面和控件的生命周期
    【ASP.NET】HTTP客户请求的数据格式说明
    【ASP.NET】页面间传值
    【ASP.NET】Page.IsPostBack 属性
    【ASP.NET】互联网HTTP连接等出错代码大全
    【经验分享】抽象类、虚函数、接口、多态 概念与关系的理解
    【架构设计】需求分析
    【经验分享】常用正则表达式收集
  • 原文地址:https://www.cnblogs.com/icode-wzc/p/12910488.html
Copyright © 2020-2023  润新知