STM32
直播中

石飞鹏

7年用户 965经验值
私信 关注
[问答]

如何利用外部中断来实现按键控制LED灯的亮灭?

如何利用外部中断来实现按键控制LED灯的亮灭?

回帖(1)

吴键洪

2021-11-24 10:51:54
利用外部中断来实现按键控制LED灯的亮灭。
实验工具:MDK5,STM32F103ZET6开发板
使用固件库编程
LED灯引脚PD13,按键PE0
首先了解一下32的外部中断

STM32 的每个 IO 都可以作为外部中断的中断输入口,STM32F103 的中断控制器支持 19 个外部中断/事件请求。每个中断设有状位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F103的 19 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。
所以这次要用到的就是线 0~15
下图是IO口语中断线的一一映射关系





以线 0 为例:它对应了 GPIOA.0、 GPIOB.0、 GPIOC.0、GPIOD.0、GPIOE.0、 GPIOF.0、 GPIOG.0
使用外部中断的配置过程







在此之前先写一个LED与按键KEY的程序
led.c


#include "led.h"


void LED_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStrtuct;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
       
        GPIO_InitStrtuct.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStrtuct.GPIO_Pin = GPIO_Pin_13;
        GPIO_InitStrtuct.GPIO_Speed  = GPIO_Speed_50MHz;
        GPIO_Init(GPIOD,&GPIO_InitStrtuct);
       
}


key.c


#include "key.h"


void KEY_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStrtucter;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
       
        GPIO_InitStrtucter.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStrtucter.GPIO_Pin = GPIO_Pin_0;
        GPIO_Init(GPIOE,&GPIO_InitStrtucter);
}


uint8_t Key_scan(void)
{
       
        if (KEY == 1)
        {
                //松手检测
                while(KEY == 1)
                        return 1;                       
        }
        else
                return 0;
}


然后就可以根据上面的步骤一步步配置中断了


#include "exti.h"
#include "key.h"
#include "delay.h"
#include "led.h"


void EXTIX_Init(void)
{
        EXTI_InitTypeDef  EXTI_InitStruct;
    NVIC_InitTypeDef  NVIC_InitStructer;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
        KEY_Init();//初始化按键
       
        //中断线的映射以及中断初始化配置
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource0);//中断线映射函数
       
        EXTI_InitStruct.EXTI_Line = EXTI_Line0;
        EXTI_InitStruct.EXTI_LineCmd = ENABLE;
        EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;  // 模式为interrupt
        EXTI_InitStruct.EXTI_Trigger  = EXTI_Trigger_Rising; //上升沿触发
        EXTI_Init(&EXTI_InitStruct);
       
        //配置中断分组并使能中断
    NVIC_InitStructer.NVIC_IRQChannel =  EXTI0_IRQn; //使能按键所在的外部中断通道
        NVIC_InitStructer.NVIC_IRQChannelCmd  = ENABLE;           //使能外部中断通道
        NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
        NVIC_InitStructer.NVIC_IRQChannelSubPriority = 0x02;          //子优先级1
    NVIC_Init(&NVIC_InitStructer);
       
}
//中断服务函数
void EXTI0_IRQHandler()
{
         delay_ms(10);    //消抖
        if(KEY==1)
        {          
                LED=!LED;
        }
        EXTI_ClearITPendingBit(EXTI_Line0);  //清除EXTI0线路标志位
}




说明一下

NVIC_InitStructer.NVIC_IRQChannel = EXTI0_IRQn;
它的配置是在stm32f10x.h里面,
PxN管脚共用外部中断线EXTIN和外部中断向量EXTIN_IRQn和中断服务程序入口EXTIN_IRQHandler,但是需要注意[9…5]共用EXTI9_5_IRQn和EXTI9_5_IRQHandler、[15…10]共用EXTI15_10_IRQn和EXTI15_10_IRQHandler。
而中断服务函数void EXTI0_IRQHandler()是在 startup_stm32f10x_hd.s 里面
有关中断分组

具体的分配关系如表 所示:





抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
这里需要注意两点:
第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级
中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
结合实例说明一下:
假定设置中断优先级组为 2,然后设置中断 3(RTC 中断)的抢占优先级为 2,响应优先级为 1。中断 6(外部中断 0)的抢占优先级为 3,响应优先级为 0。中断 7(外部中断 1)的抢占优先级为 2,响应优先级为 0。
那么这 3 个中断的优先级顺序为:中断 7>中断 3>中断 6。
上面例子中的中断 3 和中断 7 都可以打断中断 6 的中断。而中断 7 和中断 3 却不可以相互打断!

结论:
1.抢占优先级越小,优先级越高;相同抢占优先级的中断不能相互打断;
2.相同抢占优先级N个中断发生时,响应优先级越小的中断首先执行,如果响应优先级也均相同,则根据各中断对应向量表的位置来确定,向量表中越靠前的中断先响应。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分