STM32库函数 外部中断(或事件)部分代码细究

本文详细介绍了STM32库函数中关于外部中断的使用,包括EXTI初始化、中断状态获取与清除、中断处理函数等。通过示例代码展示了如何配置中断线、检测中断状态并清除标志位。同时,强调了在同一中断服务函数中如何区分不同中断线,并指出同一中断线不能配置多个中断。最后,讨论了中断处理函数在工程文件中的位置。
摘要由CSDN通过智能技术生成

STM32库函数 外部中断(或事件)部分代码细究

一、外部中断相关函数

外部中断部分相对简单,库函数也相对较少,以下,根据函数名字基本可以看出其作用。

void EXTI_DeInit(void);
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
void EXTI_ClearFlag(uint32_t EXTI_Line);
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

二、ST外部中断知识

对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它
产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲
或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏
蔽。挂起寄存器保持着状态线的中断请求。

EXTI控制器的主要特性如下:
● 每个中断/事件都有独立的触发和屏蔽
● 每个中断线都有专用的状态位
● 支持多达20个软件的中断/事件请求
● 检测脉冲宽度低于APB2时钟宽度的外部信号。

外部中断/事件控制器框图, 如下所示
在这里插入图片描述中断屏蔽寄存器(EXTI_IMR)
0:屏蔽
1:开放

在这里插入图片描述
事件屏蔽寄存器(EXTI_EMR)
0:屏蔽
1:开放

在这里插入图片描述上升沿触发选择寄存器(EXTI_RTSR)
0:禁止上升沿触发
1:允许上升沿触发

在这里插入图片描述
下降沿触发选择寄存器(EXTI_FTSR)
0:禁止下降沿触发
1:允许下降沿触发

在这里插入图片描述软件中断事件寄存器(EXTI_SWIER)
在这里插入图片描述挂起寄存器(EXTI_PR)
0:没有中断产生
1:有中断产生

在这里插入图片描述

外部中断通用I/O映像
在这里插入图片描述
● EXTI线16连接到PVD输出
● EXTI线17连接到RTC闹钟事件
● EXTI线18连接到USB唤醒事件
● EXTI线19连接到以太网唤醒事件(只适用于互联型产品)

外部中断/事件寄存器映像
在这里插入图片描述

三、示例代码1

中断初始化函数

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
{
  uint32_t tmp = 0;

  /* Check the parameters */
  assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode));
  assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger));
  assert_param(IS_EXTI_LINE(EXTI_InitStruct->EXTI_Line));  
  assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd));

  tmp = (uint32_t)EXTI_BASE;
     
  if (EXTI_InitStruct->EXTI_LineCmd != DISABLE)
  {
    /* Clear EXTI line configuration */
    EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;
    
    tmp += EXTI_InitStruct->EXTI_Mode;

    *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;

    /* Clear Rising Falling edge configuration */
    EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;
    
    /* Select the trigger for the selected external interrupts */
    if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)
    {
      /* Rising Falling edge */
      EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;
      EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;
    }
    else
    {
      tmp = (uint32_t)EXTI_BASE;
      tmp += EXTI_InitStruct->EXTI_Trigger;

      *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;
    }
  }
  else
  {
    tmp += EXTI_InitStruct->EXTI_Mode;

    /* Disable the selected external lines */
    *(__IO uint32_t *) tmp &= ~EXTI_InitStruct->EXTI_Line;
  }
}

EXTI_InitTypeDef
在这里插入图片描述
EXTI_Line
在这里插入图片描述EXTI_Mode
在这里插入图片描述EXTI_Trigger
在这里插入图片描述EXTI_LineCmd
在这里插入图片描述初始化示例

	EXTI_InitTypeDef EXTI_InitStructure;   //EXTI_InitStructure 结构体定义
 
	EXTI_InitStructure.EXTI_Line = EXTI_Line3;  // 中断线3
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;   //中断线使能
	//以上理解为:依次为EXTI_InitStructure 结构体中的成员赋值
	EXTI_Init(&EXTI_InitStructure);   //调用中断初始化函数 (参数:结构体指针)

四、示例代码2

获取中断标志位

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;
  /* Check the parameters */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));
  
  enablestatus =  EXTI->IMR & EXTI_Line;  //检查中断是否被屏蔽,即中断是否使能:0屏蔽,1:开放。
  if (((EXTI->PR & EXTI_Line) != (uint32_t)RESET) && (enablestatus != (uint32_t)RESET))
  //EXTI->PR & EXTI_Line  中断线上是否产生了中断        
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

清除中断标志位

void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
{
  /* Check the parameters */
  assert_param(IS_EXTI_LINE(EXTI_Line));
  
  EXTI->PR = EXTI_Line;
}

以上两个函数成对使用,用例如下

void EXTI3_IRQHandler(void)
{
     if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生
     {
       中断逻辑…
      EXTI_ClearITPendingBit(EXTI_Line3); //清除 LINE 上的中断标志位
     }
}

EXTI_TypeDef
在这里插入图片描述在这里需要说明一下,
1、固件库还提供了两个函数用来判断外部中断状态以及清除外部状态标志位的函数 EXTI_GetFlagStatus 和 EXTI_ClearFlag,他们的作用和前面两个函数的作用类似。

2、只是在 EXTI_GetITStatus 函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而EXTI_GetFlagStatus 直接用来判断状态标志位。

EXTI_GetFlagStatus

FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line)
{
  FlagStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));
  
  if ((EXTI->PR & EXTI_Line) != (uint32_t)RESET)   //没有判断中断是否使能
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

五、中断函数

外部中断线有20个,可是中断函数却只有7个,分别是:
1、EXTI0_IRQHandler
2、EXTI1_IRQHandler
3、EXTI2_IRQHandler
4、 EXTI3_IRQHandler
5、EXTI4_IRQHandler
6、EXTI9_5_IRQHandler
7、EXTI15_10_IRQHandler
中断线 0-4 每个中断线对应一个中断函数, 中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中
断线 10-15 共用中断函数 EXTI15_10_IRQHandler。

1、同一个中断函数中 如何判断是哪个中断线上的中断
在同一个中断处理函数中,有多条中断线时常用到以下两个函数:
1、ITStatus EXTI_GetITStatus(uint32_t EXTI_Line) ;
中断服务函数的开头判断中断是否发生

2、void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
清除某个中断线上的中断标志位

举例:

void EXTI9_5_IRQHandler(void)
{
     //中断线5
     if(EXTI_GetITStatus(EXTI_Line5)!=RESET)//判断中断线5上的中断是否发生
     {
       中断逻辑…
      EXTI_ClearITPendingBit(EXTI_Line5); //清除 LINE5 上的中断标志位
     }


      //中断线6
     if(EXTI_GetITStatus(EXTI_Line6)!=RESET)//判断中断线6上的中断是否发生
     {
       中断逻辑…
      EXTI_ClearITPendingBit(EXTI_Line6); //清除 LINE6 上的中断标志位
     }

        //中断线7
     if(EXTI_GetITStatus(EXTI_Line7)!=RESET)//判断中断线7上的中断是否发生
     {
       中断逻辑…
      EXTI_ClearITPendingBit(EXTI_Line7); //清除 LINE7 上的中断标志位
     }
                 .
                 .
                 .
                 .
   
}

2、同一个中断线,可以配置多个中断么?
答案:不可以
以中断线0为例
中断线0 有 A、B、C、D、E、F、G 7个端口,每个端口的0号管脚构成了一条中断线,可以看出来,这是一个多路选择器,7路输入,1路输出,意味着同一时刻这7个管脚只有一个能在中断线0上
在这里插入图片描述总结:

1.同一pin口不可同时配置外部中断

2.不同pin口可以同时配置外部中断

3.共用中断服务函数,以中断标志位区分

4.外部中断的本质是某中断线得到信号触发,进入对应的中断服务函数的过程。

5.某一路中断线只能同时跟一个pin口搭上

六、中断处理函数应该放在工程文件的什么位置

stm32f10x_it.c 里面是用来编写中断服务函数,但是中断服务函数也可以随意编写在工程
里面的任意一个文件里面。
在这里插入图片描述

下面是基于STM32F103RCT6的按键使用外部中断控制LED的代码: ``` #include "stm32f10x.h" void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) != RESET) { GPIO_WriteBit(GPIOB, GPIO_Pin_12, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12))); EXTI_ClearITPendingBit(EXTI_Line0); } } void initGPIO() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } int main(void) { initGPIO(); while (1) { // Loop } } ``` 该代码的作用是,将按键连接到PA0引脚,将LED连接到PB12引脚。按下按键时,LED将切换状态。在代码中使用外部中断来检测按键的状态,并在触发中断时切换LED的状态。在初始化中,使用GPIO_Init函数来配置PB12为推挽输出模式,PA0为下拉输入模式。使用EXTI_Init函数来配置外部中断,以便在检测到按键状态变化时触发中断。在中断处理函数中,使用GPIO_WriteBit函数来切换LED的状态,并使用EXTI_ClearITPendingBit函数清除中断标志位。整个程序将被放在一个无限循环中,以便在触发中断后继续运行。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值