STM32外部中断驱动按键,实现按键控制LED灯的开关

STM32F407ZE开发板外部中断驱动按键,实现按键控制LED灯的开关.

main.c部分:

#include <stm32f4xx.h> //该头文件作用和reg51.h是一样的
#include "sys.h"
#include "led.h"
#include "key.h"
#include "delay.h"


int main()
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//中断优先级分组  2分组
	
	LED_Init();										//LED灯初始化
	KEYEXTI_Init1();								//按键PA0的外部中断初始化
	
	while(1)
	{
		
	}
}

sys.h部分:

#ifndef __SYS_H
#define __SYS_H	 
#include "stm32f4xx.h" 

//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr & 0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//STM32中  对寄存器的访问  是不能单独访问寄存器的单个bit  只能以32bit地址访问寄存器
//这些位为只写形式,只能在字(word)--4byte、半字2byte 或字节模式下访问 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入


#endif

led.h部分:

#ifndef _LED_H_
#define _LED_H_

#include <stm32f4xx.h>
#include "sys.h"

void LED_Init(void);

#endif

led.c部分:

#include "led.h"

void LED_Init(void)
{
	GPIO_InitTypeDef aaa;
	
	//1、先开启对应用到的模块时钟节拍
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);//PE组时钟

	//2、可以初始化配置GPIO  F组的9号引脚
	aaa.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_10;
	aaa.GPIO_Mode  = GPIO_Mode_OUT;//输出模式
	aaa.GPIO_Speed = GPIO_Fast_Speed;//快速  点灯和引脚速度无关
	aaa.GPIO_OType = GPIO_OType_PP;//推挽输出
	aaa.GPIO_PuPd  = GPIO_PuPd_UP;//内部上拉
	GPIO_Init(GPIOF,&aaa);
	
	
	aaa.GPIO_Pin   = GPIO_Pin_13 | GPIO_Pin_14;
	GPIO_Init(GPIOE,&aaa);
	
	//初始化完成  灭掉4盏灯
	PFout(9)  = 1;
	PFout(10) = 1;
	PEout(13) = 1;
	PEout(14) = 1;

}

key.h部分:

#ifndef _KEY_H_
#define _KEY_H_

#include <stm32f4xx.h>
#include "sys.h"

void KEY_Init(void);
void KEYEXTI_Init1(void);
#endif

key.c部分:

#include "key.h"
#include "delay.h"

void KEY_Init()
{
	GPIO_InitTypeDef KEY1,KEY2;
	//先开启对应用到的模块时钟节拍PA、PE
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
	
	//初始化KEY1
	KEY1.GPIO_Pin 		= GPIO_Pin_0 ;
	KEY1.GPIO_Mode 		= GPIO_Mode_IN;
	KEY1.GPIO_Speed 	= GPIO_Fast_Speed;
	KEY1.GPIO_OType 	= GPIO_OType_PP;
	KEY1.GPIO_PuPd  	= GPIO_PuPd_UP;
	GPIO_Init(GPIOA,&KEY1);
	
	//初始化KEY2、KEY3、KEY4
	KEY2.GPIO_Pin 	= GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
	KEY2.GPIO_Mode 	= GPIO_Mode_IN;
	KEY2.GPIO_Speed = GPIO_Fast_Speed;
	KEY2.GPIO_OType = GPIO_OType_PP;
	KEY2.GPIO_PuPd  = GPIO_PuPd_UP;
	GPIO_Init(GPIOE,&KEY2);
}


void KEYEXTI_Init1(void)
{
	EXTI_InitTypeDef Keyexti_Struct1;
	NVIC_InitTypeDef Keynvic_Struct1;
	
	//0、使能SYSCFG  EXTI相关时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
	//1、先初始化按键引脚
	KEY_Init();

	//2、将PA0、PE2、PE3、PE4引脚用作为外部中断引脚
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);
	
	//3、初始化EXTI(设置对应的中断线0,2,3,4)
	Keyexti_Struct1.EXTI_Line 		= EXTI_Line0 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
	Keyexti_Struct1.EXTI_Mode 		= EXTI_Mode_Interrupt;		//中断模式
	Keyexti_Struct1.EXTI_Trigger 	= EXTI_Trigger_Falling;		//上升沿--按键松开触发
	Keyexti_Struct1.EXTI_LineCmd 	= ENABLE;					//外部中断开启使能设置
	EXTI_Init(&Keyexti_Struct1);
	
	//4、NVIC初始化
	Keynvic_Struct1.NVIC_IRQChannel = EXTI0_IRQn;				//中断线0对应的函数
	Keynvic_Struct1.NVIC_IRQChannelPreemptionPriority = 0;		//抢占优先级设置
	Keynvic_Struct1.NVIC_IRQChannelSubPriority = 0;				//响应优先级
	Keynvic_Struct1.NVIC_IRQChannelCmd   = ENABLE;				//开启NVIC管理
	NVIC_Init(&Keynvic_Struct1);
	
	Keynvic_Struct1.NVIC_IRQChannel = EXTI2_IRQn;				//中断线2对应的函数
	NVIC_Init(&Keynvic_Struct1);
	
	Keynvic_Struct1.NVIC_IRQChannel = EXTI3_IRQn;				//中断线3对应的函数
	NVIC_Init(&Keynvic_Struct1);
	
	Keynvic_Struct1.NVIC_IRQChannel = EXTI4_IRQn;				//中断线4对应的函数
	NVIC_Init(&Keynvic_Struct1);
}

void EXTI0_IRQHandler(void)
{
	delay(80);													//延时消抖
	PFout(9) = !PFout(9);										//LED1置位取反
	
	EXTI_ClearITPendingBit(EXTI_Line0);							//标志位清除
}

void EXTI2_IRQHandler(void)
{
	delay(80);													//延时消抖
	PFout(10) = !PFout(10);										//LED2置位取反
	
	EXTI_ClearITPendingBit(EXTI_Line2);							//标志位清除
}

void EXTI3_IRQHandler(void)
{	
	delay(80);													//延时消抖
	PEout(13) = !PEout(13);										//LED3置位取反
	
	EXTI_ClearITPendingBit(EXTI_Line3);							//标志位清除
}

void EXTI4_IRQHandler(void)
{
	delay(80);													//延时消抖
	PEout(14) = !PEout(14);										//LED4置位取反
	
	EXTI_ClearITPendingBit(EXTI_Line4);							//标志位清除
}

delay.h部分:

#ifndef _DELAY_H_
#define _DELAY_H_


void delay(int tim);

#endif

delay.c部分:

#include "delay.h"

void delay(int tim)
{
	int i;
	while(tim--)
	{
		for(i =38400;i>0;i--);
	}
}

----------------------------------------------------------分割线----------------------------------------------------------
设置外部中断,主要由下面函数设定:

void KEYEXTI_Init1(void)
{
	EXTI_InitTypeDef Keyexti_Struct1;
	NVIC_InitTypeDef Keynvic_Struct1;
	
	//0、使能SYSCFG  EXTI相关时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
	//1、先初始化按键引脚
	KEY_Init();

	//2、将PA0、PE2、PE3、PE4引脚用作为外部中断引脚
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);
	
	//3、初始化EXTI(设置对应的中断线0,2,3,4)
	Keyexti_Struct1.EXTI_Line 		= EXTI_Line0 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
	Keyexti_Struct1.EXTI_Mode 		= EXTI_Mode_Interrupt;		//中断模式
	Keyexti_Struct1.EXTI_Trigger 	= EXTI_Trigger_Falling;		//上升沿--按键松开触发
	Keyexti_Struct1.EXTI_LineCmd 	= ENABLE;					//外部中断开启使能设置
	EXTI_Init(&Keyexti_Struct1);
	
	//4、NVIC初始化
	Keynvic_Struct1.NVIC_IRQChannel = EXTI0_IRQn;				//中断线0对应的函数
	Keynvic_Struct1.NVIC_IRQChannelPreemptionPriority = 0;		//抢占优先级设置
	Keynvic_Struct1.NVIC_IRQChannelSubPriority = 0;				//响应优先级
	Keynvic_Struct1.NVIC_IRQChannelCmd   = ENABLE;				//开启NVIC管理
	NVIC_Init(&Keynvic_Struct1);
	
	Keynvic_Struct1.NVIC_IRQChannel = EXTI2_IRQn;				//中断线2对应的函数
	NVIC_Init(&Keynvic_Struct1);
	
	Keynvic_Struct1.NVIC_IRQChannel = EXTI3_IRQn;				//中断线3对应的函数
	NVIC_Init(&Keynvic_Struct1);
	
	Keynvic_Struct1.NVIC_IRQChannel = EXTI4_IRQn;				//中断线4对应的函数
	NVIC_Init(&Keynvic_Struct1);
}
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
参数1:EXTI_InitStruct
typedef struct
{
  uint32_t EXTI_Line;  				// EXTI_Line0          
  EXTIMode_TypeDef EXTI_Mode;   	// EXTI_Mode_Interrupt   
  EXTITrigger_TypeDef EXTI_Trigger; 
  FunctionalState EXTI_LineCmd;  
}EXTI_InitTypeDef;
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
参数1:NVIC_InitStruct
typedef struct
{
	uint8_t NVIC_IRQChannel;   					//选择你要配置的中断的全局中断编号             
             									//EXTI_Line0   该编号去stm32f4xx.h头文件
           										//查找  Line176  EXTI0_IRQn   6号
	uint8_t NVIC_IRQChannelPreemptionPriority;  //抢占优先级(第一)0~15
  
	uint8_t NVIC_IRQChannelSubPriority;    		//响应优先级  (第二)0~15
                             					//数字越小 优先级越高
	规则1:当两个中断的抢占优先级不同时  响应优先级不考虑
	        	 ①如果两个中断同时出发   限制性高抢占的
	       		 ②如果高抢占先触发  低抢占后触发 低抢占只能排队等待高抢占的处理完  再做低抢占
	         	 ③当低抢占先触发 并先被CPU响应了 ,但高抢占后触发 ,就会出现高抢占把低抢占的处理过程抢占了(中断嵌套)
	规则2:当两个中断的抢占优先级相同    则去考虑响应优先级规则和上面一样 ,但是不能发生抢占
	规则3: 关于设置这两个优先级的问题:	
	           		关于某个中断的优先级设置 ,只给记录优先级的数值提供了4bit的记录空间----分配问题
		            404bit给抢占 0000 ~1111  0bit给响应
		            313bit给抢占    1bit 给响应
		            220~3:抢占    0~3:响应
		            13
		            04
	              这个分组设置最好在我们的工程一开始就设置好,而且只要设置一次即可!!

	FunctionalState NVIC_IRQChannelCmd;      	//ENABLE  DISABLE   

} NVIC_InitTypeDef;
  • 4
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,这是一个很常见的任务,我可以为您提供一些代码示例来实现这个功能。 首先,您需要连接一个按键和一个LED到您的STM32开发板上。假设您将按键连接到引脚PA0,将LED连接到引脚PB0。 接下来,您需要在代码中初始化这些引脚。这可以通过以下方式完成: ```c GPIO_InitTypeDef GPIO_InitStruct; // 初始化PA0引脚为输入模式 GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化PB0引脚为输出模式 GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); ``` 在这个例子中,我们将PA0引脚初始化为输入模式,并启用上拉电阻。这意味着当按键没有按下时,PA0引脚将被拉高。当按键按下时,PA0引脚将会被拉低。我们将PB0引脚初始化为输出模式,这意味着我们可以通过在代码中设置它的状态来控制LED的亮度。 接下来,您需要配置外部中断外部中断是一种特殊的中断,可以在引脚状态发生变化时触发。在这个例子中,我们将使用外部中断来检测按键是否被按下。这可以通过以下方式完成: ```c EXTI_HandleTypeDef EXTI_InitStruct; // 配置外部中断 EXTI_InitStruct.Pin = GPIO_PIN_0; EXTI_InitStruct.Mode = EXTI_MODE_INTERRUPT; EXTI_InitStruct.Trigger = EXTI_TRIGGER_FALLING; HAL_EXTI_SetConfigLine(&EXTI_InitStruct, EXTI_LINE_0); ``` 在这个例子中,我们将外部中断配置为检测PA0引脚的下降沿。这意味着当按键被按下时,外部中断将会触发。 最后,您需要实现中断处理函数,以便在按键被按下时切换LED的状态。这可以通过以下方式完成: ```c void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { // 切换LED的状态 HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } } ``` 在这个例子中,我们实现了一个名为`HAL_GPIO_EXTI_Callback`的中断处理函数。当外部中断被触发时,这个函数将被调用。在这个函数中,我们检查触发中断的引脚是否为PA0引脚。如果是,我们将使用`HAL_GPIO_TogglePin`函数来切换LED的状态。 以上就是使用stm32外部中断实现按键控制LED的示例代码。希望这能帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佳佳鸽

若文章帮到你,能不能请我喝杯茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值