实现GPIO外部中断(基于STM32F103ZET6)

和往常一样,我会提供完成项目同时,提供小编在实践时的情况以及自己认为更好的算法心得!欢迎阅读,我的博客前面完成了几个简单的实验,相信大家对软件的配置和基本模式已经熟悉,就不再赘述!
开始
之前用while循环编写的按键识别,现在终于到了中断识别按键了,跟之前的按键实验一样(正点原子精英版),功能不变,识别原理改为了中断,我们分别用KEY0控制DS0(LED0),用KEY1控制DS1(LED1),KEY_UP控制BEEP(蜂鸣器)的状态反转!
STM32的开发板IO口都可以作为中断输入引脚,但是中断线只有16根,所以在选择时有一些局限:开发板的IO有GPIOA,B,C,D,E,F,G;每种IO有16个引脚,同一个GPIO(如A),1-16个引脚都可以同时被使用为中断,如图:
实现GPIO外部中断(基于STM32F103ZET6)_第1张图片
十六根中断线同一时间只能选择一根,所以开发板的所有IO都可以进行中断是针对不同时间的!
所以在初始化时要选择哪个IO是终端模式,这时候要用到IO选择初始化函数void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource),选择某一IO可以这样配置:GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2)
这里需要说明一下,STM32 的 IO 口外部中断函数只有 6 个,
分别为:
实现GPIO外部中断(基于STM32F103ZET6)_第2张图片
中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中断线 10-15 共用中断函数EXTI15_10_IRQHandler
在中断函数里,判断中断(可不判断)的条件,如果是判断line1发生了中断,可以这样编写EXTI_GetITStatus(EXTI_Line3)!=RESET(值为0)或者EXTI_GetITStatus(EXTI_Line3)==SET(值为1)
中断结束时,要清除中断标志位,这一步是必须的!EXTI_ClearITPendingBit(EXTI_Line1)
整个格式可以这样:
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1)!=RESET)//判断line上的中断是否发生
{
中断逻辑…
EXTI_ClearITPendingBit(EXTI_Line1); //清除line1上的中断标志位
} }

跟上面的另一种相同的写法还有另一种
void EXTI3_IRQHandler(void)
{
if(EXTI_GetFlagStatus)//判断line上的中断是否发生,参数自行补齐
{
中断逻辑…
EXTI_ClearFlag; //清除line1上的中断标志位 ,参数自行补齐
} }

下面就开始代码编写:
外部中断定义头文件exti.h

#ifndef EXTI_H
#define EXTI_H
#include "sys.h"
void exti_init(void);
#endif

很简单,没什么好解释的
外部中断源文件exti.c

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

void exti_init(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	KEY_Init();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
	EXTI_InitStructure.EXTI_Line=EXTI_Line3;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
	EXTI_InitStructure.EXTI_Line=EXTI_Line4;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel= EXTI3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel= EXTI4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel= EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;
	NVIC_Init(&NVIC_InitStructure);
}
void EXTI3_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line3)!=RESET)
	{
		static unsigned char i;
	i++;
	
		delay_ms(20);
		if(KEY1==0&&i==1)
			{
				LED1=!LED1;	
			}
		else 
		{
			i=0;
			EXTI_ClearITPendingBit(EXTI_Line3);
		}
	}
	
}
void EXTI4_IRQHandler(void)
{
	static unsigned char i;
	i++;
		delay_ms(10);
		if(KEY0==0&&i==1)
			{
					LED0=!LED0;
			}
		else 
		{
			i=0;
			EXTI_ClearITPendingBit(EXTI_Line4);
		}
}
void EXTI0_IRQHandler(void)
{
	static unsigned char i;
	i++;
		delay_ms(10);
		if(WK_UP==1&&i==1)
			{
				BEEP=!BEEP;
			}
		else
		{   
		i=0;
			EXTI_ClearITPendingBit(EXTI_Line0);
		}			
}

原文件里的KEY_Init();的顺序很重要,注意别出错,小编当时就错了!我们直接使用案件里面的程序,就直接引用,EXTI主要是初始化IO中断通道,开启中断,自然而然需要初始化中断,重点在中断函数,如果采用正点原子程序,跟我的还是有点差别的,我也不知道是不是我的开发板问题?(滑稽),控制led时不稳定,自己定义了个静态变量,来计算中断来的个数,我的逻辑就是,在接收到一次中断后下一次相同中断来到我抛弃掉第三次来的时候才响应,这样的好处是可以非常好的控制外设,按键识别的很稳定
在EXTI3中加入了中断标志位判断,其他中断函数没有加上,为了证明可加可不加!最好还是加上,养成好习惯!
外部中断主函数main.c

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "stdio.h"
#include "key.h"
#include "exti.h"
#include "beep.h"
int main(void)
{
	delay_init();	    	
	LED_Init();	
	exti_init();
	KEY_Init();
	BEEP_Init();
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 
	 while(1)
	 {
		delay_ms(1000);
	 }
}

没什么好讲的,实现都在中断函数里,主函数就一个死循环!
其他
中断优先级是我们需要了解的,大家不要忽略,我在编译的时候遇到过这样的问题,明明库函数在我的文件当中,还能找得到,却提示我有库函数缺失,这时候我在添加源文件的USER里添加了stm32f10x_exti.c解决了这一问题,在里面我没有找到此源文件的存在,所以大家经常在这里面找问题
希望能够帮助大家,如果你们还有更好的方法希望可以说出你的想法!
谢谢

你可能感兴趣的:(实现GPIO外部中断(基于STM32F103ZET6))