EXIT外部中断详解

EXIT-外部中断详解

好肝啊,每写一篇要好几个小时,希望大家能点点关注,我的原则是,原创且精品,拒绝搬运,不过主要还是记录一下自己的学习之路,随缘吧,最近在看rtthread的源码,C的精髓都在操作系统上了,裸机寄存器只是基础,所以会更的很慢

开局一张图,上一篇,我们做了GPIO详解,大家可以很清楚的明白GPIO最基础的作用:输入输出,而在基础的作用之上,GPIO还能复用为其他功能,关于复用的基础知识概念这种在此处就不再赘述,而对于GPIO复用为外部中断引脚,算是比较难理解的一个概念,这图非常直观(白嫖的),从这图我们就能看出来,想要配置引脚为外部中断引脚,需要以下几个步骤:

  1. 使能GPIO时钟,配置GPIO引脚模式
  2. 使能AFIO时钟
  3. 配置EXIT并使能EXIT
  4. 配置NVIC并使能NVIC
  5. 重写对应中断源的中断回调函数

在这里插入图片描述

其实说是标准库源码详解,实际上,摸清套路之后就会发现,无论什么外设,还不是老样子三件套:

  1. 创建对应外设结构体,对结构体赋值
  2. 按照这个结构体的配置初始化,也就是Init函数
  3. 然后就是控制什么的,都没难度了

总结一下的话就只剩下以下两个步骤了:

typedef struct
{
  uint32_t EXTI_Line;
  //EXTI_Line0~EXTI_Line15,下面我们取一个看以下,这比较简单,就不细说了
 
  EXTIMode_TypeDef EXTI_Mode;
  //模式,可选择中断模式或者事件模式,事件模式此处不讲,学中断只说中断,实际上是因为我也没用过事件模式
    
  EXTITrigger_TypeDef EXTI_Trigger;
  //触发条件:上升沿or下降沿or都触发
    
  FunctionalState EXTI_LineCmd; 
  //使能EXIT
    
}EXTI_InitTypeDef;

typedef enum//模式枚举
{
  EXTI_Mode_Interrupt = 0x00,
  EXTI_Mode_Event = 0x04
}EXTIMode_TypeDef;

typedef enum//触发条件枚举
{
  EXTI_Trigger_Rising = 0x08,
  EXTI_Trigger_Falling = 0x0C,  
  EXTI_Trigger_Rising_Falling = 0x10
}EXTITrigger_TypeDef;
//中断线枚举,本来想偷懒,还是贴上吧
#define EXTI_Line0       ((uint32_t)0x00001)  /*!< External interrupt line 0 */
#define EXTI_Line1       ((uint32_t)0x00002)  /*!< External interrupt line 1 */
#define EXTI_Line2       ((uint32_t)0x00004)  /*!< External interrupt line 2 */
#define EXTI_Line3       ((uint32_t)0x00008)  /*!< External interrupt line 3 */
#define EXTI_Line4       ((uint32_t)0x00010)  /*!< External interrupt line 4 */
#define EXTI_Line5       ((uint32_t)0x00020)  /*!< External interrupt line 5 */
#define EXTI_Line6       ((uint32_t)0x00040)  /*!< External interrupt line 6 */
#define EXTI_Line7       ((uint32_t)0x00080)  /*!< External interrupt line 7 */
#define EXTI_Line8       ((uint32_t)0x00100)  /*!< External interrupt line 8 */
#define EXTI_Line9       ((uint32_t)0x00200)  /*!< External interrupt line 9 */
#define EXTI_Line10      ((uint32_t)0x00400)  /*!< External interrupt line 10 */
#define EXTI_Line11      ((uint32_t)0x00800)  /*!< External interrupt line 11 */
#define EXTI_Line12      ((uint32_t)0x01000)  /*!< External interrupt line 12 */
#define EXTI_Line13      ((uint32_t)0x02000)  /*!< External interrupt line 13 */
#define EXTI_Line14      ((uint32_t)0x04000)  /*!< External interrupt line 14 */
#define EXTI_Line15      ((uint32_t)0x08000)  /*!< External interrupt line 15 */
#define EXTI_Line16      ((uint32_t)0x10000)  
#define EXTI_Line17      ((uint32_t)0x20000)  
#define EXTI_Line18      ((uint32_t)0x40000)                              
#define EXTI_Line19      ((uint32_t)0x80000)  

下面就是激动人心的Init时刻了,但是在此之前,我们还有一点东西没有搞完:

使能AFIO时钟:没啥说的,太简单了,跟使能GPIO时钟用一个函数,使能GPIO的时候, | 操作一下,每个中断的PIN都需要哦

重点来了:void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

  • 这个函数非常重要,作用是选择EXIT的中断源
  • 如果是初学者,这个比较难理解,需要配合开头的那张图看的话会更加清晰明了
  • 例如:EXIT0,其实可以配置为GPIOA 的引脚0,也可以是GPIOB的引脚0,也可以是GPIOC的引脚0
  • 这个时候,我们第一个参数传入端口(GPIOAGPIOG),第二个参数传入PIN编号(GPIO_Pin_0GPIO_Pin_15)
  • 重点:这时,我们就选定了一个确定的引脚和一条确定的EXIT中断线相连
  • 问题来了,那我们没配置具体的中断线啊?注意注意!引脚是0~15,当确定引脚编号的时候,其实已经确定了中断线

好的下面就是激动人心的INIT环节了:

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
{
  uint32_t tmp = 0;
  
  tmp = (uint32_t)EXTI_BASE;
  //此处tmp赋值位EXIT的外设基地址
   
  if (EXTI_InitStruct->EXTI_LineCmd != DISABLE)
  {//判断EXIT结构体最后一个变量EXTI_LineCmd,如果使能则进入这个函数,如果没使能那还玩个锤子
    
    EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;
    //bit0~Bit19分别对应20个挂在EXIT上的中断,其他的保留
    //我们分析一下,EXIT0~19的枚举值,讲16进制化为10进制后,分别是1,2,4,8,16,32……
    //再将10进制化为二进制后,就能看出,就是将0x01每次左移1位
    //此处先取反,只有某个bit为0,其他全为1,然后进行&=操作,会将IMR的某个bit置0,其他位不会被影响
    //总结:将对应的选中的中断线置0,也就屏蔽选中线的中断请求
      
    EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;
    //这个的位操作就不赘述了,参考上面的一条,我们直接查看寄存器说结果
    //屏蔽选中的中断线上的事件请求
      
    tmp += EXTI_InitStruct->EXTI_Mode;
    //tmp=EXIT外设基地址,然后+=模式枚举,我们查看模式枚举值,我们中断模式的话,就是0

    *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;
    //重点:好的兄弟们,很迷,这波操作惊到我了,上面我们把选中的中断线对应的中断请求和事件都屏蔽了不是吗
    //注意,tmp(外设基地址)+0x00后,还是基地址,进行*取值后,指向了偏移为0的寄存器,也就是IMR
    //???所以,又通过 |= 操作,将选中的中断线的屏蔽关掉了,也就是使能了,这不是把我当猴耍吗
    
    EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;
    //这两合在一起说了,一个是上升沿选择,一个是下降沿选择
    //对中断线枚举值取反再与等后,很明显,分别是将传入参数的中断线禁止上升沿和下降沿触发,都是置0嘛
    
    if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)
    {//判断一下,如果我们配置的模式是上升下降都触发的话,就将两个寄存器的对应位都置1,也就是使能
      EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;
      EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;
    }
    else
    {//如果不是呢则进入这里
        
      tmp = (uint32_t)EXTI_BASE;
      //让tmp = EXTI外设及地址
        
      tmp += EXTI_InitStruct->EXTI_Trigger;
      //我们看一下触发条件枚举值,上升是0x08(8),下降是0x0C(12),都要的话是0x10(16)
      //此处+=之后,根据我们配置的触发条件,则+= 8/12/16之后之后,tmp指向EXTI_RTSR/EXTI_FTSR/EXTI_SWIER寄存器
	
      *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;
      //这不是跟上面一毛一样,对tmp指向的地址操作,将对应的触发选择寄存器对应位置1,也就是使能触发选择寄存器
        
    }
  }
  else
  {//否则已经使能了,进入这
      
    tmp += EXTI_InitStruct->EXTI_Mode;
    *(__IO uint32_t *) tmp &= ~EXTI_InitStruct->EXTI_Line;
    //如果已经使能过了,则会改变对应PIN的触发模式
  }
}

对于重写回调函数,这个太简单了,就不再赘述

我们依次附上用到的寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值