按键切换LED模式及中断函数

Goal

LED四种模式:

  • LED0亮,LED1灭
  • LED0灭,LED1亮
  • LED0和LED1同时亮
  • LED0亮,LED1灭,200ms后,LED0灭,LED1亮,如此循环 

1. KEY0按键第一次按下时,LED按模式一显示,第二次按下时,LED模式+1,如此循环

2. KEY1按键按下时,取消KEY0的功能,LED0和LED1灯都灭

Background

嵌套向量中断控制器(NVIC)

外部中断/事件控制器(EXTI)

外部中断/事件控制器包含多达23个用于产生事件/中断请求的边沿检测器。每根输入线都可单独进行配置,以选择类型(中断或事件)和相应的触发事件(上升沿触发、下降沿触发或边沿触发)。简而言之,中断的作用为,当原程序执行时,按下中断按键,程序去执行中断后需执行的任务,执行完后回到原程序接着执行原本内容。

【注意:在中断函数中不可使用HAL_Delay();该语句会讲程序的时钟系统打乱。】

图 1 外部中断/事件控制器框图 

Experiment Steps

  • 配置IDE中用于生成代码的参数

按照实验1:点亮LED中步骤(上一篇文章),分别配置好寄存器。

在STM32F4ZG核心板原理图中,找到用户自定义按键,如图2。

图2 用户自定义按键

实验目标1要求使用PB9(KEY0)为输入端口控制LED模式切换,由图2可得设置GPIO_Input模式,图中显示并无上拉、下拉电阻,则端口配置为No pull-up and no pull-down(也可以配置为上拉)。

图3 PB9输入端口配置参数

实验目标2要求使用PB8(KEY1)为中断端口,由图2得当开关断开时PB8标识处为高电平,当开关闭合电路导通而PB8标识处接地为低电平,高电平变为低电平为下降沿触发,因此该中断端口选择External Interrupt Mode with Falling edge trigger detection并且因为没有上、下拉电阻,端口也配置为无上下拉电阻。还需在嵌套向量中断控制器中勾选EXTI line[9:5] interrupts使其启用。对PB8中断端口的配置如图4。

图4 PB8中断端口皮配置参数

  • 实验①:按键切换LED闪烁模式

【在上次写的LED实验报告基础上完成该实验】

编程思维:

每按下一次KEY0按键,程序分别进入0,1,2,3,4四种LED闪烁的模式,用flag和!flag标识每次进入while(1)循环一次,并在按键按下后改变用于标记处于第几个LED闪烁模式的变量b。

编程代码:

首先在main.h中加入typedef enum {FALSE = 0,TRUE = 1} bool;以激活布尔函数的使用。

其次在main.c中设置全局变量b并且在int main(void){ }中进行编程如下(其他部分不改变):

【注意:将代码写在/* USER CODE BEGIN */和/* USER CODE END*/之间不会被重新generate code的时候覆盖掉】

#include "main.h"
#include "gpio.h"
void SystemClock_Config(void);
int b = 0; 
int main(void)
{
  bool flag = FALSE;
  
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  
  while (1)
  {
	  if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET){
		  if(!flag){
			  if(b == 4){
				  b = 1;
			  }
			  else{
				  b++;
			  }
			  flag = TRUE;
		  }
	  }
	  else{
		  if(flag){
			  flag = FALSE;
		  }
	  }
	  if(b == 0){
		  HAL_GPIO_WritePin(led0_GPIO_Port, led0_Pin, GPIO_PIN_SET);
		  HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_SET);
	  }
	  else if(b == 1){
		  HAL_GPIO_WritePin(led0_GPIO_Port, led0_Pin, GPIO_PIN_RESET);
		  HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_SET);
	  }
	  else if(b == 2){
		  HAL_GPIO_WritePin(led0_GPIO_Port, led0_Pin, GPIO_PIN_SET);
		  HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_RESET);
	  }
	  else if(b == 3){
		  HAL_GPIO_WritePin(led0_GPIO_Port, led0_Pin, GPIO_PIN_RESET);
		  HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_RESET);
	  }
	  else if(b == 4){
		  HAL_GPIO_WritePin(led0_GPIO_Port, led0_Pin, GPIO_PIN_RESET);
		  HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_SET);
		  HAL_Delay(200);
		  HAL_GPIO_WritePin(led0_GPIO_Port,led0_Pin,GPIO_PIN_SET);
		  HAL_GPIO_WritePin(led1_GPIO_Port,led1_Pin,GPIO_PIN_RESET);
		  HAL_Delay(200);
	  }
  }
}
  • 实验②:设置中断函数实验报告

编程思维:

需要再KEY1按键按下后,取消KEY0功能,让led0和led1同时灭。

在stm32f4xx_hal_gpio.c中看到函数void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin),其中有HAL_GPIO_EXTI_Callback(GPIO_Pin);(还看到IQRHandler中有一句__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);作用为执行后清空中断);而紧接着看到函数__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin),函数前有个__weak,__weak的意思是这个函数为弱函数,我们只需要在main.c中写一个void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin),便可覆盖弱函数,弱函数只在没有自己写入的强函数下执行。

编程代码:

在以上代码中int b = 0;和int main(void)中的位置加入以下函数即可。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == KEY1_Pin){
    	b=0;
    }
}

Result

实验①:

随着KEY0的按下,D1作为LED0D2作为LED1。在不按下时,LED0LED1同时灭;在按下第一次时,LED0亮,LED1灭;在按下第二次时,LED0灭,LED1亮;在按下第三次时,LED0和LED1同时亮;在按下第四次时,LED0亮,LED1灭,200ms后,LED0灭,LED1亮,如此循环。在随着按键的按下,这四种模式也一直循环。(图5只选取了前三种模式,第四种模式为动态闪烁不方便截图)

实验②:

KEY1按下,中断原程序运行,回到b = 0模式,也即LED0和LED1同时灭。只有当KEY0再按下便再从b = 0模式重新执行实验①内容。

图5 实验①的三种模式闪烁情况

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GiaG*

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值