跳转至

03.外部中断

实验说明

本系列实验都是基于STM32F1的单片机进行的编程实验。

实验简介

这里使用单片机的PB5口来实现单片机的外部中断。

中断简介

先简单介绍一下中断的概念,在 STM32 中,对信号的处理可以分为轮询方式和中断方式,轮询方式就是不断去访问一个信号的端口,看看有没有信号进入,有则进行处理,中断方式则是当输入产生的时候,产生一个触发信号告诉 STM32 有输入信号进入,需要进行处理。

中断的流程就是,先初始化一个条件,这个条件可以是引脚检测到下降沿,可以是你定的一个倒计时,或者其他条件,你的程序正在顺序执行中,一旦这个条件满足了,他就会暂停当前执行的程序,去执行中断服务函数里面的程序,当中断服务函数的程序执行完了后,又返回之前正在执行的程序。

代码实现

我们这里的中断,他的中断条件就是引脚发生了边沿变换,就像下面

上升沿中断:当 GPIO 的电平从低电平跳变成高电平时,引发外部中断。

下降沿中断:当 GPIO 的电平从高电平跳变成低电平时,引发外部中断。

外部中断的配置流程为 初始化引脚 ->打开复用时钟->初始化外部中断条件->初始化中断优先级

void bsp_exti_init()
{
    //打开时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    //引脚初始化
    {
        GPIO_InitTypeDef GPIO_InitStruct;

        GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_5;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;

        GPIO_Init(GPIOB,&GPIO_InitStruct);
    }
    //中断线初始化
    {
        EXTI_InitTypeDef EXTI_InitStructure;

        EXTI_InitStructure.EXTI_Line    = EXTI_Line5;
        EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;

        EXTI_Init(&EXTI_InitStructure);

        //初始化中断线
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);
    }
    //NVIC初始化
    {
        NVIC_InitTypeDef NVIC_InitStructure;

        NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;          //使能外部中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占优先级2,
        NVIC_InitStructure.NVIC_IRQChannelSubPriority =        3;   //子优先级0
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //使能外部中断通道

        NVIC_Init(&NVIC_InitStructure);
    }
}

中断线初始化中,初始化了这个中断触发的条件,比如按键WK_UP,他是PA0,对应的中断线就是0,然后因为他按下按键是由低到高,所以就是上升沿触发中断EXTI_Trigger_Rising,最后,再使用GPIO_EXTILineConfig函数将对应的引脚,和中断线对起来,一根线只能有一个中断源,EXTI_Line0只能和PA0,PB0,PC0,PD0等0号引脚相连,当他和PA0相映射后,就不能和PB0相映射了,其他的引脚同理。

NVIC初始化,是在初始化这个中断的优先级,当两个条件同时满足的时候,中断优先级高的执行,关于中断通道EXTI04有自己独立的,59共用一个,10~15共用一个,优先级先比较抢占优先级,再比较子优先级,数字越小优先级越高,关于等级大小有5种分配,如下

配置方式 抢占优先级 子优先级
NVIC_PriorityGroup_0 0 0~15
NVIC_PriorityGroup_1 0~1 0~7
NVIC_PriorityGroup_2 0~3 0~3
NVIC_PriorityGroup_3 0~7 0~1
NVIC_PriorityGroup_4 0~15 0

这个分配,一般在main函数最前方,通过NVIC_PriorityGroupConfig函数初始化。

关于中断通道,0、1、2、3、4有自己的单独的中断通道,EXTI0_IRQnEXTI1_IRQnEXTI2_IRQnEXTI3_IRQnEXTI4_IRQn,然后59公用一个中断通道EXTI9_5_IRQn,1015公用一个中断通道EXTI15_10_IRQn

中断初始化配置完成后,就要写中断服务函数了,中断服务函数,可以写在工程任何位置,但是该函数各个中断通道都各自只能有一个,而且函数名固定。

0、1、2、3、4有自己的单独的中断服务函数,EXTI0_IRQHandlerEXTI1_IRQHandlerEXTI2_IRQHandlerEXTI3_IRQHandlerEXTI4_IRQHandler,然后59公用一个中断服务函数EXTI9_5_IRQHandler,1015公用一个中断服务函数EXTI15_10_IRQHandler

void EXTI9_5_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line5) == SET)
    {
        led0_on();
    }
    EXTI_ClearITPendingBit(EXTI_Line5); 
}

当对应通道的中断源触发的时候,就会进入对应的通道服务函数,记得在退出中断服务函数的时候要清除中断标志位,不清除就可能一直进入中断。

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请附上原文出处链接及本声明。

原文链接: https://snqx-lqh.gitee.io/wiki/