zoukankan      html  css  js  c++  java
  • STM32F407VET6 底层驱动之外中断寄存器封装

    外中断模块中实现了所有中断线的中断,使用的时候需要将与中断线对应的回调函数注册到模块中就行了,所有与单片机相关的操作均在模块内部完成。

    1、外中断封装接口如下:

      a、外中断使能配置:unsigned int exti_enable(eGpioType_t gpio, ePinType_t pin, eExtiType_t trim, unsigned char prio, void (*pCallBack)(void * const parg), void const *parg)

      b、外中断禁能配置:void exti_disable(eGpioType_t gpio, ePinType_t pin)

    2、外中断对外开放的枚举类型如下:

    // GPIO外中断触发类型
    typedef enum _eExtiType
    {
       eEXTI_BOTH_EDGE, // 任意电平触发
       eEXTI_RISING_EDGE,  // 上升沿触发
       eEXTI_FALLING_EDGE, // 下降沿触发
    }eExtiType_t;

    3、外中断代码实现如下:

    // GPIO外中断线类型
    typedef enum _eExtiLineType
    {
       eEXTI0,
       eEXTI1,
       eEXTI2,
       eEXTI3,
       eEXTI4,
       eEXTI5,
       eEXTI6,
       eEXTI7,
       eEXTI8,
       eEXTI9,
       eEXTI10,
       eEXTI11,
       eEXTI12,
       eEXTI13,
       eEXTI14,
       eEXTI15,
       eEXTI_COUNT, // 注:这不是中断线类型,不可删除,仅用做数量统计
    }eExtiLineType_t;

    // 外中断回调函数数据结构
    #pragma pack(push, 1)
    typedef struct _sExtiDev
    {
       void *parg;
       void (*pCallBack)(void * const parg);
    }sExtiDev_t;
    #pragma pack(pop)

    sExtiDev_t sExtiDev[eEXTI_COUNT] = {NULL};

    /********************************************************
     * 函数功能:外中断优先级设置(组4),注意优先级不能超过设
                定的组的范围否则会有意想不到的错误。组划分如下:
           组0:0位抢占优先级,4位响应优先级
           组1:1位抢占优先级,3位响应优先级
           组2:2位抢占优先级,2位响应优先级
           组3:3位抢占优先级,1位响应优先级
           组4:4位抢占优先级,0位响应优先级
       抢占优先级和响应优先级的数值越小,优先级越高,处理器优
       先比较抢占优先级然后再看响应优先级。
     * 形    参:prio:抢占优先级(分组4的响应优先级固定为0)
        channel:中断通道
     * 返 回 值:无
     ********************************************************/
    static void exti_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; // 设置响应优先级和抢断优先级
    }
    /********************************************************
     * 函数功能:外部中断配置函数,每次只能配置一个引脚(配置外中断前需先配置GPIO为输入模式)
                (只针对通用IO,配置完立即使能中断,配置之后需重新注册回调函数)
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
                 trim:中断触发模式
                 prio:中断优先级(范围:6 - 15,数值越小优先级越高)
                 pCallBack:回调函数指针
                 parg:回调函数的参数
     * 返 回 值:0=成功
                 1=回调函数指针为NULL
                 2=GPIO引脚错误
     ********************************************************/
    unsigned int exti_enable(eGpioType_t gpio, ePinType_t pin, eExtiType_t trim, unsigned char prio, void (*pCallBack)(void * const parg), void const *parg)
    {
       unsigned char exti_line = 31U - __CLZ(pin);
       unsigned char exti_offset = (exti_line % 4) << 2;
     
       if(pCallBack == NULL)
       {
          return 1;
       }
     
       // 引脚初始化
       if(trim == eEXTI_FALLING_EDGE)
       {
          gpio_config(gpio, pin, eGPIO_IN_UP, 1); // 下降沿触发就将引脚上拉,默认输出高电平
       }
       else if(trim == eEXTI_RISING_EDGE)
       {
          gpio_config(gpio, pin, eGPIO_IN_DP, 0); // 上升沿触发就将引脚下拉,默认输出低电平
       }
       else
       {
          gpio_config(gpio, pin, eGPIO_IN_NP, 0); // 上升和下降沿都触发就将引脚设置无上下拉,默认输出低电平
       }
     
       RCC->APB2ENR |= 0x1 << 14; // 使能SYSCFG时钟
       SYSCFG->EXTICR[exti_line >> 2] &= ~(0x000F << exti_offset); // 清除原来设置
       SYSCFG->EXTICR[exti_line >> 2] |= gpio << exti_offset; // EXTI.BITx映射到GPIOx.BITx
       EXTI->IMR |= pin; // 开启指定引脚上的中断(如果要禁止中断,则反操作即可)
       if(trim == eEXTI_FALLING_EDGE)
       {
          EXTI->FTSR |= pin; // 下降沿触发
       }
       else if(trim == eEXTI_RISING_EDGE)
       {
          EXTI->RTSR |= pin; // 上升沿触发
       }
       else if(trim == eEXTI_BOTH_EDGE)
       {
          EXTI->FTSR |= pin; // 下降沿触发
          EXTI->RTSR |= pin; // 上升沿触发
       }
     
       unsigned char IRQn = 0;
       switch(exti_line)
       {
          case eEXTI0: IRQn = EXTI0_IRQn; break;
          case eEXTI1: IRQn = EXTI1_IRQn; break;
          case eEXTI2: IRQn = EXTI2_IRQn; break;
          case eEXTI3: IRQn = EXTI3_IRQn; break;
          case eEXTI4: IRQn = EXTI4_IRQn; break;
          case eEXTI5:
          case eEXTI6:
          case eEXTI7:
          case eEXTI8:
          case eEXTI9: IRQn = EXTI9_5_IRQn; break;
          case eEXTI10:
          case eEXTI11:
          case eEXTI12:
          case eEXTI13:
          case eEXTI14:
          case eEXTI15: IRQn = EXTI15_10_IRQn; break;
          default : return 2;
       }
     
       sExtiDev[exti_line].parg = (void *)parg;
       sExtiDev[exti_line].pCallBack = pCallBack;
       exti_nvic_set(prio, IRQn); // 设置中断优先级
       return 0;
    }
    /********************************************************
     * 函数功能:外部中断配置函数(只针对通用IO)
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
                 trim:中断触发模式
     * 返 回 值:无
     ********************************************************/
    void exti_disable(eGpioType_t gpio, ePinType_t pin)
    {
       unsigned char exti_line = 31U - __CLZ(pin);
       unsigned char exti_offset = (exti_line % 4) << 2;
     
       SYSCFG->EXTICR[exti_line >> 2] &= ~(0x000F << exti_offset); // 清除原来设置
       SYSCFG->EXTICR[exti_line >> 2] |= gpio << exti_offset; // EXTI.BITx映射到GPIOx.BITx
       EXTI->IMR |= ~pin; // 关闭指定引脚上的中断(如果要使能中断,则反操作即可)
    }
    /********************************************************
     * 函数功能:外部中断回调函数(中断专用)
     * 形    参:line:指定的外中断线
     * 返 回 值:无
     ********************************************************/
    static void exti_isr_callback(eExtiLineType_t line)
    {
       if(sExtiDev[line].pCallBack != NULL)
       {
          // 执行中断回调函数
          sExtiDev[line].pCallBack(sExtiDev[line].parg);
       }
       EXTI->PR = 0x1UL << line; // 清除中断标志位
    }
    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI0_IRQHandler(void)
    {
       exti_isr_callback(eEXTI0);
    }

    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI1_IRQHandler(void)
    {
       exti_isr_callback(eEXTI1);
    }

    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI2_IRQHandler(void)
    {
       exti_isr_callback(eEXTI2);
    }

    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI3_IRQHandler(void)
    {
       exti_isr_callback(eEXTI3);
    }

    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI4_IRQHandler(void)
    {
       exti_isr_callback(eEXTI4);
    }

    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI9_5_IRQHandler(void)
    {
       unsigned int pr = EXTI->PR;
       if(pr & (0x1UL << eEXTI5))
       {
          exti_isr_callback(eEXTI5);
       }
       else if(pr & (0x1UL << eEXTI6))
       {
          exti_isr_callback(eEXTI6);
       }
       else if(pr & (0x1UL << eEXTI7))
       {
          exti_isr_callback(eEXTI7);
       }
       else if(pr & (0x1UL << eEXTI8))
       {
          exti_isr_callback(eEXTI8);
       }
       else if(pr & (0x1UL << eEXTI9))
       {
          exti_isr_callback(eEXTI9);
       }
       else
       {
          // 未知中断线,不可能会发生
       }
    }

    /********************************************************
     * 函数功能:外部中断服务函数
     * 形    参:无
     * 返 回 值:无
     ********************************************************/
    void EXTI15_10_IRQHandler(void)
    {
       unsigned int pr = EXTI->PR;
       if(pr & (0x1UL << eEXTI10))
       {
          exti_isr_callback(eEXTI10);
       }
       else if(pr & (0x1UL << eEXTI11))
       {
          exti_isr_callback(eEXTI11);
       }
       else if(pr & (0x1UL << eEXTI12))
       {
          exti_isr_callback(eEXTI12);
       }
       else if(pr & (0x1UL << eEXTI13))
       {
          exti_isr_callback(eEXTI13);
       }
       else if(pr & (0x1UL << eEXTI14))
       {
          exti_isr_callback(eEXTI14);
       }
       else if(pr & (0x1UL << eEXTI15))
       {
          exti_isr_callback(eEXTI15);
       }
       else
       {
          // 未知中断线,不可能会发生
       }
    }

  • 相关阅读:
    poj-3580-SuperMemo-splay
    JS 添加到事件的多个对象
    1.9 效率高,安排约会
    我展示了视频采集前端vfe和camera,decode等交互驱动的体系结构
    2013年7月27日杂记
    深入JS系列学习4
    深入JS系列学习3
    深入JS系列学习2
    高质量JavaScript代码书写基本要点学习
    给硬件复兴把脉 硬件创新最有机会的十个方向
  • 原文地址:https://www.cnblogs.com/icode-wzc/p/12910321.html
Copyright © 2011-2022 走看看