STM32
直播中

芒果冰

11年用户 920经验值
私信 关注
[问答]

如何利用STM32F407ZE开发板外部中断驱动按键去控制LED灯的开关呢

如何利用STM32F407ZE开发板外部中断驱动按键去控制LED灯的开关呢?其代码程序怎样去编写?

回帖(1)

林立

2021-10-27 09:46:48
  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的记录空间----分配问题
  40 : 4bit给抢占 0000 ~1111 0bit给响应
  31 : 3bit给抢占 1bit 给响应
  22 : 0~3:抢占 0~3:响应
  13
  04
  这个分组设置最好在我们的工程一开始就设置好,而且只要设置一次即可!!
  FunctionalState NVIC_IRQChannelCmd; //ENABLE DISABLE
  } NVIC_InitTypeDef;
举报

更多回帖

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