STM32工作笔记0057---外部中断实验

技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152

51单片机好像只有2个IO口是支持中断输入的.

但是STM32的每个IO口都是支持中断输入的.

虽然每个IO口都支持中断输入,但是STM32一共只有16个中断线

但是STM32有上百个IO口,那他是怎么实现的,让所有的IO口都支持中断的呢

来看:

这里有个外部中断和IO口的对应关系,映射关系.

因为一组IO,有16个IO口,一共有7组IO口,那么

PA0IO口的中断线用EXTI0

PB0IO口的中断线用EXTI0

PC0IO口的中断线用EXTI0

PD0IO口的中断线用EXTI0

...

PG0IO口的中断线用EXTI0

这样就对应起来了,一共16个中断线,0到15,对应每组IO口的,0到15IO口

但是注意同一个时间,其实只有一个IO口占用对应的中断线,

比如,因为 PA0---PG0这7个IO口,都用EXTI0这个中断线,所以,同一个时间只有一个IO口会占用这个中断线.

是切换使用的.

这个就是为什么,这么多IO口,可以只用16个中断线的原因.

再看一下这个中断线.

这里这个上升沿触发,就是高电平的时候触发,下降沿的时候触发,就是低电平的时候触发,边沿触发是上边沿的时候触发,

还是说可以设置,上升,下降沿都触发等.

这里不是16个中断线就可以分配16个中断服务,他是这样的

IO口外部中断,在中断向量表中只分配了7个中断向量,也就是只能用7个中断服务函数.

可以看到中断线0到中断线4,这5个中断线,都有对应的自己的中断函数.

但是中断线EXTI5到9,用一个中断服务函数,也就是这几个中断线产生中断的时候都会执行这一个中断服务函数.

中断线EXTI10到15,用一个中断服务函数,也就是这几个中断线产生中断的时候都会执行这一个中断服务函数.

这样就一共7个中断服务函数.

然后中断服务函数

首先设置IO口与中断线的映射关系,就是哪个IO口用哪个中断线

然后,初始化中断线,是上沿中断,还是下沿中断,还是边沿中断,边沿中断就是上下沿都会触发中断.

然后,判断中断标志位是不是1,也就是判断有没有发生中断.

然后,用完了以后,需要手动的把中断标志位,清零.

然后,这里看EXTI_Init函数

这个函数初始化中断线的.用来对某个中断线进行一下初始化,配置

第一个是指定要配置的中断线

第二个是选择中断模式,是中断,还是事件

第三个是指定触发方式,是上升沿,还是下降沿,还是双沿触发

第四是使能这个中断线.

下面是个例子.

外部中断配置的步骤,

第一,首先要初始化一个IO口,为输入,因为要读取输入的电平

第二,然后要开启IO口复用时钟,把IO口设置为复用,即是IO口,又是中断服务触发口.

第三,要设置IO口和中断线之间的映射,给对应的IO口配置一个中断线

第四,要初始化对应的设置的中断线,比如是设置上沿触发,下沿触发,双沿触发什么的

第五,要配置中断的分组优先级,并且使能中断,前面说过.

第六,要编写中断服务函数,并且在函数中,可以判断高低电平,并且还可以判断,比如

        当EXTI5--EXTI9共用一个中断线的时候,要判断具体是哪个中断线触发的中断

第7,使用完以后要清除对应的中断标志位.

看一下接下来的中断实验的硬件连接

可以看到这里的战舰版,KEY0,KEY1,KEY2当按键,按下的时候,比如是高电平,有个上拉电阻,拉成高电平

然后按下的过程中,是由高电平往下走的过程,然后走平以后,再往上沿走,往上沿走的时候其实就是按下的手松开了

这里就可以根据需要,比如按下的时候需要中断,就可以设置为这个中断线为下沿触发,如果需要松开的时候需要中断,

就设置对应的中断线为上沿触发.

接下来看一下,外部中断实验的代码

首先,新建中断头文件exti.h文件,里面有个初始化函数.

然后再去写exti.c文件

按照这个步骤来写.

首先要知道,官方提供的中断的库函数,都在上面这个文件和.h文件中.

首先这里要调用KEY_Init这个来实现初始化按键的功能

然后第二:来开启IO口复用时钟.

然后第三,设置IO口与中断线的映射.

可以看到,这里比如KEY0连接到了PE4那么,就要设置GPIOE

设置这个PE4IO口使用EXTI4这个中断线.

注意一定要按照文档中的说明来,也就是说PE4只能对应EXTI4,这个是有这个要求的,

如果PE4IO口,比如配置的中断线是EXTI5肯定是不行的.

这里这个中断线和IO口的映射配置用GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4)

这个函数,这里的参数:

第一个是,哪个IO口,这里是GPIOE,第二个是,哪个引脚,这里是第四个引脚.

然后再去

第4步,再去初始化中断线.

这里

EXTI_InitStrue.EXTI_Line=EXTI_Line4 //设置使用中断线4
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//模式有事件触发,还有中断触发,这里选择中断触发
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//因为硬件连接有个接地,所以这里我们选择下降沿触发
    EXTI_Init(&EXTI_InitStructure); // 根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

KEY0接地.可以看到.

注意对应的参数都可以去定义的部分去看.

然后5.配置中断优先级.

这里的中断优先级配置:

NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;             //1.配置这个优先级通道,中断线4这个通道.
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级2,这里设置之前需要设置优先级分组,这个分组一般都是在main函数最上面就设置的.
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;         // 子优先级2,也就是响应优先级设置为2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 // 使能这个通道,开启这个优先级通道.
NVIC_Init(&NVIC_InitStructure);

接下来第六,可以开始编写中断服务函数了.

可以在启动文件中找到.

这个外部中断服务函数,然后就开始编写中断

这里,前面说过为了防止抖动,这里首先要有10毫秒的延时,

然后根据前面的硬件连接,按下的时候,是低电平.

KEY0按下的时候是低电平,所以这里,判断

//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
    delay_ms(10);    //消抖
    if (KEY0 == 0) //
    {
         LED0 = !LED0;
        LED1 = !LED1;
    }
    EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE4上的中断标志位
}

按下KEY0的时候让LED0和LED1进行翻转就可以了.

然后再去看一下main函数

可以看到,前面都是一些初始化,然后调用中断线的初始化,然后

有个死循环,

int main(void)
{

	delay_init();									//延时函数初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);								//串口初始化为115200
	LED_Init();										//初始化与LED连接的硬件接口
	BEEP_Init();									//初始化蜂鸣器IO
	EXTIX_Init();									//初始化外部中断输入
	LED0 = 0;										//先点亮红灯
	while (1)
	{
		printf("OK\r\n");
		delay_ms(1000);
	}
}

这个死循环的意思是,当下载程序到开发版以后,

程序会一直执行,每隔1秒,打印OK到串口,当

产生下沿中断以后,就会去执行上面写的中断函数,就会引起

LED0,LED1的翻转.

接下来编译以后下载到开发版试试

 然后下载程序后,按下按键,可以看到现象.

然后,可以把按键3也添加上.修改一下代码:

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

//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK精英STM32开发板
//外部中断 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/3
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//
//外部中断0服务程序
void EXTIX_Init(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	KEY_Init(); // 按键端口初始化

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能复用功能时钟

	// GPIOE.3	  中断线以及中断初始化配置 下降沿触发 //KEY1
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);
	EXTI_InitStructure.EXTI_Line = EXTI_Line3;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure); // 根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

	// GPIOE.4	  中断线以及中断初始化配置  下降沿触发	//KEY0
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);
	EXTI_InitStructure.EXTI_Line = EXTI_Line4;
	EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

	// GPIOA.0	  中断线以及中断初始化配置 上升沿触发 PA0  WK_UP
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

	EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			 // 使能按键WK_UP所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; // 抢占优先级2,
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;		 // 子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				 // 使能外部中断通道
	NVIC_Init(&NVIC_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;			 // 使能按键KEY1所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; // 抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;		 // 子优先级1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				 // 使能外部中断通道
	NVIC_Init(&NVIC_InitStructure);								 // 根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			 // 使能按键KEY0所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; // 抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;		 // 子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				 // 使能外部中断通道
	NVIC_Init(&NVIC_InitStructure);								 // 根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}

//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
	delay_ms(10);	//消抖
	if (WK_UP == 1) //WK_UP按键
	{
		BEEP = !BEEP;
	}
	EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}

//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
	delay_ms(10);  //消抖
	if (KEY1 == 0) //按键KEY1
	{
		LED1 = !LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位
}

void EXTI4_IRQHandler(void)
{
	delay_ms(10);  //消抖
	if (KEY0 == 0) //按键KEY0
	{
		LED0 = !LED0;
		LED1 = !LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
}

这里添加上了另外的两个按键,然后添加完以后,可以再去试一试.

编译一下,去测试一下效果.

猜你喜欢

转载自blog.csdn.net/lidew521/article/details/108238537