STM32入门学习之外部中断

1.STM32的IO口可以作为外部中断输入口。本文通过按键按下作为外部中断的输入,点亮LED灯。在STM32的19个外部中断中,0-15为外部IO口的中断输入口。STM32的引脚分别对应着0-15的外部中断线。比如,外部中断线0对应着GPIOA.0-GPIOG.0,以此类推就可以将所以的IO映射到0-15个外部中断线上。STM32的IO的外部中断映射图如下:

2.外部中断的配置步骤:

(1)将IO口映射到对应的外部中断线上,中断线河中断初始化。

(2)配置外部中断,即配置中断管理NVIC。

(3)重写中断服务函数,即中断回调函数。这些中断回调函数在startup_stm32f10x_xx.s中被规定好了名称,我们只需要重写对应的中断回调函数即可。

3.工程代码:

delay.h:

cpp 复制代码
#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f10x.h"

void delay_us(uint32_t us);									//ÑÓʱ΢Ãë
void delay_ms(uint32_t ms);									//ÑÓʱºÁÃë

#endif

delay.c:

cpp 复制代码
#include "delay.h"

void delay_us(uint32_t us)
{
	uint32_t i;
	
	//1.Ñ¡ÔñHCLKʱÖÓ£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµ
	SysTick_Config(72);
	
	for(i = 0;i < us;i++)
	{
		while(!((SysTick->CTRL) & (1 << 16)));		//µÈ´ý¼ÆÊýÍê³É
	}
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	//Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}

void delay_ms(uint32_t ms)
{
	uint32_t i;
	//1.Ñ¡ÔñHCLKʱÖÓÔ´£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµ
	SysTick_Config(72000);
	
	for(i = 0;i < ms;i++)
	{
		while(!((SysTick->CTRL) & (1 << 16)));		//µÈ´ý¼ÆÊýÍê³É
	}
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	//Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}

key.h:

cpp 复制代码
#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"

#define KEY_0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)			//¶ÁÈ¡°´¼üµÄ״̬
#define KEY_1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)
#define KEY_2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)

void KEY_Init(void);
void KEY_Scan(void);						//°´¼üɨÃ躯Êý

#endif

key.c:

cpp 复制代码
#include "key.h"
#include "delay.h"
#include "led.h"

void KEY_Init(void)
{
	/*1.¶¨ÒåÒý½ÅµÄ½á¹¹Ìå¡£
	  2.ʹÄÜÒý½Å¶ÔÓ¦µÄʱÖÓ¡£
	  3.ÅäÖÃÒý½ÅÐÅÏ¢*/
	
	//¶¨ÒåÒý½Å½á¹¹Ì壺
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//ʹÄÜʱÖÓ£º
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);
	
	//ÅäÖÃÒý½ÅÐÅÏ¢(KEY0)£º
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	
	//ÅäÖÃKEY1£º
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀ­ÊäÈë

	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//ÅäÖð´¼üWK_UP:
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	LED_Init();									//³õʼ>>¯LED
}

void KEY_Scan(void)
{
	static u8 key_up = 1;				//°´¼üËÉ¿ª±êÖ¾Î>>
	if(key_up && (KEY_0 == 0||  KEY_1  == 0|| KEY_1 == 1))
	{
		delay_ms(10);						  //È¥¶¶¶¯
		key_up = 0;
		if(KEY_0 == 0)
		{
			GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
			GPIO_SetBits(GPIOA,GPIO_Pin_8);
			//delay_ms(1000);
		}
		else if(KEY_1 == 0)
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			GPIO_SetBits(GPIOD,GPIO_Pin_2);
			//delay_ms(1000);
		}
		else if(KEY_2 == 1)
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
		}
	}
	else if(KEY_0==1&&KEY_1==1&&KEY_2==0)
	{
		key_up = 1;
	}
}

exti.h:

cpp 复制代码
#ifndef __EXTI_H
#define __EXTI_H

#include "stm32f10x.h"

void EXTIx_Init(void);

#endif

exti.c:

cpp 复制代码
#include "exti.h"
#include "key.h"
#include "delay.h"

void EXTIx_Init(void)
{
	/*ÍⲿÖжϵÄÅäÖ÷½·¨£º
	  1.½<<IO¿ÚÓ³Éäµ½¶ÔÓ¦ÍⲿÖжÏÏßÉÏ
	  2.ÅäÖÃÍⲿÖжÏ
	  3.ÖØдÖжϷþÎñº¯Êý£¬¼´ÖжÏ>>ص÷º¯Êý*/
	
	//¶¨ÒåÍⲿÖжϺÍÖжϵĽṹÌ壺
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//ʹÄÜʱÖÓ£º
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//ÍⲿÖжÏÐèÒª¸´ÓÃʱÖÓ
	KEY_Init();			//³õʼ>>¯°´¼ü
	
	//GPIOC.5µÄÖжÏÏߺÍÖжϳõʼ>>¯ÅäÖãº
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);	//GPIOÓëÖжÏÏß½øÐÐÓ³Éä
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line5;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	
	EXTI_Init(&EXTI_InitStructure);//½<<ÉÏÃæÅäÖõÄÐÅϢдÈëEXTI¼Ä´æÆ÷ÖÐ
	
	//GPIOA.0µÄÖжÏÏߺÍÖжϳõʼ>>¯ÅäÖãº
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);	//GPIOÓëÖжÏÏß½øÐÐÓ³Éä
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	
	EXTI_Init(&EXTI_InitStructure);
	
	//GPIOA.15µÄÖжÏÏߺÍÖжϳõʼ>>¯ÅäÖãº
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);	//GPIOÓëÖжÏÏß½øÐÐÓ³Éä
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line15;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	
	EXTI_Init(&EXTI_InitStructure);
	
	//ÖжϹÜÀíÅäÖãº
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	
	NVIC_Init(&NVIC_InitStructure);	
}

//ÖØдÖжϷþÎñº¯Êý.
void EXTI0_IRQHandlÕâЩÖжÏ>>ص÷º¯ÊýÔÚstartup_stm32f10x_xx.sÖб>>¹æ¶¨ºÃÁËÃû³Æer(void)
{
	//¾²Ì¬±äÁ¿Ö>>>>áÔÚµÚÒ>>´ÎÔËÐÐʱ±>>³õʼ>>¯¡£ËùÒÔ£¬¿ÉÒÔÀí½âΪÕâÌõÓï¾äÖ>>Ö´ÐÐÒ>>´Î
	static u8 flag1 = 1;	
	delay_ms(10);				//Ïû¶¶
	if(KEY_2 == 1)
	{
		if(flag1)
		{
			//GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
			GPIO_SetBits(GPIOA,GPIO_Pin_8);
			flag1 = !flag1;
		}
		else
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			//GPIO_SetBits(GPIOD,GPIO_Pin_2);
			flag1 = !flag1;
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}

void EXTI9_5_IRQHandler(void)
{
	static u8 flag2 = 1;
	delay_ms(10);				//Ïû¶¶
	if(KEY_0 == 0)
	{
		if(flag2)
		{
			//GPIO_ResetBits(GPIOA,GPIO_Pin_8);
			GPIO_SetBits(GPIOD,GPIO_Pin_2);
			flag2 = !flag2;
		}
		else
		{
			//GPIO_ResetBits(GPIOA,GPIO_Pin_8);
			GPIO_ResetBits(GPIOD,GPIO_Pin_2);
			flag2 = !flag2;
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line5);
}

void EXTI15_10_IRQHandler(void)
{
	static u8 flag3 = 1;
	delay_ms(10);				//Ïû¶¶
	if(KEY_1 == 0)
	{
		if(flag3)
		{
			GPIO_ResetBits(GPIOA,GPIO_Pin_8);
			GPIO_ResetBits(GPIOD,GPIO_Pin_2);
			flag3 = !flag3;
		}
		else
		{
			GPIO_SetBits(GPIOA,GPIO_Pin_8);
			GPIO_SetBits(GPIOD,GPIO_Pin_2);
			flag3 = !flag3;
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line15);
}

main.c:

cpp 复制代码
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"

int main(void)
{
	//LED_Init();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2
	KEY_Init();
	EXTIx_Init();
	while(1)
	{
//		GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
//		GPIO_SetBits(GPIOA,GPIO_Pin_8);
//		delay_ms(1000);
//		GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
//		GPIO_SetBits(GPIOD,GPIO_Pin_2);
//		delay_ms(1000);
		//KEY_Scan();
	}
}

4.运行结果:按下key0,LED1亮,再按一下熄灭。按下key1,LED0亮,再按一下熄灭。按下key3,两个LED亮,再按一下两个LED熄灭。

5.总结:本文是通过key的外部中断来控制led的亮灭。其原理是利用STM32的IO可作为外部中断的输入口。当按下key时,对应的IO空作为输入会触发外部中断,然后系统会去调用对应的外部中断服务函数。通过中断,可以不用阻塞程序,在中断未被触发时,程序可以去执行其他的工作,提高系统的效率。

在配置外部中断的相关信息时,主要是配置相关的结构体信息、将IO映射到对应的中断线、配置中断管理NVIC。

相关推荐
一棵开花的树,枝芽无限靠近你7 分钟前
【PPTist】添加PPT模版
前端·学习·编辑器·html
VertexGeek26 分钟前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
__基本操作__1 小时前
历遍单片机下的IIC设备[ESP--0]
单片机·嵌入式硬件
二进制_博客1 小时前
Flink学习连载文章4-flink中的各种转换操作
大数据·学习·flink
codebolt1 小时前
ADS学习记录
学习
Komorebi.py2 小时前
【Linux】-学习笔记05
linux·笔记·学习
网易独家音乐人Mike Zhou7 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
PegasusYu10 小时前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
朝九晚五ฺ10 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
猫爪笔记12 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html