STM32MP157实验(三)——按键扫描和中断


按键扫描

设计需求

通过按键扫描的方式实现,按下KEY_USER1(KEY1)按键,点亮LED_GREEN,再次按下熄灭LED_GREEN;按下KEY_USER2(KEY2)按键,点亮LED_YELLOW,再次按下熄灭LED_YELLOW.

基础知识

前面LED灯是控制GPIO输出,而按键则是读取GPIO电平,从而获知按键是否按下。

按键检测一般有两种:按键扫描(类似于轮询)和按键中断(中断检测)。

按键扫描:是间隔很短时间反复查询GPIO状态,从而的值是否有按键动作,这种方式简单,但是比较耗费资源。按键中断则是通过按键产生中断信号,从而实现按键的检测,这种方式需要使用到中断机制,需要对MCU有一定的了解。后面的按键中断实验将会详细介绍
按键一般占用一个GPIO口,通过检测该GPIO的电平变化得知按键操作,我们查看按键原理图如下
在这里插入图片描述通过原理图我们可以分析出,当按键没有按下的时候,3.3V的VDD通过电阻直接连在我们的GPIO口上(PG2),那么我们的MCU读取到的PG2GPIO口的电平就是高电平。当我们的按键按下,左边电路导通,那么我们的GPIO口的电平就是低电平,MCU读取到的电平就是低电平。

我们常用的按键都是机械触点式按键,机械式按键在按下或释放过程中,由于机械弹性作用的影响,会伴随着机械抖动,如下所示:
在这里插入图片描述
抖动的时长与机械开关特性相关,一般为5ms-10ms。在这个抖动过程中,会产生多次高低电平,所以为了确定电平的稳定性,我们需要截取稳定的电平断,所以我们需要进行按键的消抖。按键消抖可以硬件上处理,即在硬件旁并联电容,吸收抖动的电平。也可以软件处理,即通过延时,避开抖动。

硬件设计

在这里插入图片描述

开发板上有4个按键,其中两个是复位按键和唤醒按键,这次实验不会介绍,后面介绍。另外两个按键就是我们的上面的KEY1和KEY2.KEY1接在了MCU的PG3脚,并且并联了一个C34电容用于硬件的消抖,还并联了一个TVS二极管防静电。同理,KEY2接在了PG2上。

STM32CubeIDE设计

MX设置

在这里插入图片描述注意这里的红绿两个灯也需要配置,就像第一个实验那样

代码设计

driver_led.h

#ifndef DRIVER_LED_H_
#define DRIVER_LED_H_

#include "main.h"
#include "stm32mp1xx_hal.h"

#define  LED_GREEN_ON()      HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET)
#define  LED_GREEN_OFF()	 HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET)

#define  LED_YELLOW_ON()     HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET)
#define  LED_YELLOW_OFF()    HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_SET)

extern void DemoLedInit(void);
extern void LedBlinking(void);
#endif /* DRIVER_LED_H_ */

driver_key.h

#ifndef DRIVER_KEY_H_
#define DRIVER_KEY_H_
#include "driver_led.h"
#include "main.h"
#include "stm32mp1xx_hal.h"
#define PUSH_DOWN  GPIO_PIN_RESET
#define PUSH_UP    GPIO_PIN_SET

#define KEY1_READ   HAL_GPIO_ReadPin(KEY_USER1_GPIO_Port,KEY_USER1_Pin)
#define KEY2_READ	HAL_GPIO_ReadPin(KEY_USER2_GPIO_Port,KEY_USER2_Pin)

extern void Scan_key1(void);
extern void Scan_key2(void);
#endif /* DRIVER_KEY_H_ */

driver_key.c

#include "driver_key.h"
#include <stdbool.h>
static bool key1_flag=false;
static bool key2_flag=false;
void Scan_key1(void){
	if(KEY1_READ==PUSH_DOWN){//如果按键按下
		HAL_Delay(5);//延迟5秒,消抖
		if(KEY1_READ==PUSH_DOWN){
			key1_flag=!key1_flag;
			if(key1_flag){
				LED_GREEN_ON();//改变绿灯的状态
			}else{
				LED_GREEN_OFF();
			}
		}
	}
}

void Scan_key2(void){
	if(KEY2_READ==PUSH_DOWN){
		HAL_Delay(5);
		if(KEY2_READ==PUSH_DOWN){
			key2_flag=!key2_flag;
			if(key2_flag){
				LED_YELLOW_ON();
			}else{
				LED_YELLOW_OFF();
			}
		}
	}
}

main.c

int main(void)
{
  /* USER CODE BEGIN 1 */
	static uint32_t sys_freq=0;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  if(IS_ENGINEERING_BOOT_MODE())
  {
    /* Configure the system clock */
    SystemClock_Config();
  }

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
  sys_freq=HAL_RCC_GetSystemCoreClockFreq();
  if(!sys_freq){
	  return -1;
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  Scan_key1();
	  Scan_key2();

  }
  /* USER CODE END 3 */
}

实验结果

按下和松开KEY2,黄灯进行熄灭。同理KEY1

按键中断

设计需求

通过按键中断的方式实现,按下KEY2,点亮黄灯,再次按下,熄灭黄灯。同理按下KEY1,控制绿灯

基础知识

  • 中断的基本概念
    正常情况下,微处理器根据代码内容,按顺序执行指令。执行过程中,如果遇到其他紧急的事件需要处理,则先暂定当前任务,执行紧急事件,待紧急事件处理完后,再恢复到刚才暂定的地方继续执行。这个紧急事件就叫做中断。中断的执行流程如下图
    在这里插入图片描述

  • 中断的分类
    CPU在执行指令时,检测到非法指令,比如除0,地址越界访问等,会产生中断,这种中断属于内部中断,也叫系统异常。由CPU外部设备引起的外部事件,比如GPIO中断,USART中断等,这属于外部中断。
    ARM CM4内核可以支持256个中断(2^8=256,说明是用一个8至少8位的寄存器来表示中断)16个内部中断和240个外部中断。**对于stm32mp157的M4,没有用到CM4内核的所有资源,只是用到了一部分,只有10个内部中断和150个外部中断,总计160个中断。**如下图
    在这里插入图片描述

  • 中断优先级
    M4拥有这么多中断,当这些中断同时发生时,CPU应该怎么来处理呢?因此就有了中断优先级的概念。中断优先级数越小,优先级越高。
    抢占优先级:M4支持嵌套中断,所以当CPU在进行一个中断的时候,如果来了一个优先级更高的中断,CPU就立马取执行优先级更高的中断
    响应优先级:响应优先级就是当优先级相同的中断同时发生,谁的响应优先级更高,就先执行谁,另一个则等待上一个执行完了在被执行。

  • 中断优先级的分组
    在这里插入图片描述这是需要我们根据实际情况进行设计的

  • GPIO的中断
    STM32MP157有PA-PI、PZ共10组GPIO,每组GPIO又有0~15共16个GPIO口。数字编号相同的GPIO(PA0,PB0.PC0…)共享一个中断源。如下图
    在这里插入图片描述

硬件设计

就是按键的原理图,同上面的扫描实验

STM32CubeIDE设计

MX设置

在这里插入图片描述

在这里插入图片描述

代码设计

GPIO_init.c

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOG_CLK_ENABLE();//时钟使能
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET);//初始化绿灯

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : KEY_USER3_Pin KEY_USER2_Pin */
  GPIO_InitStruct.Pin = KEY_USER3_Pin|KEY_USER2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//上升沿触发中断
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /*Configure GPIO pin : LED_GREEN_Pin */
  GPIO_InitStruct.Pin = LED_GREEN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(LED_GREEN_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : LED_YELLOW_Pin */
  GPIO_InitStruct.Pin = LED_YELLOW_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(LED_YELLOW_GPIO_Port, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(EXTI2_IRQn);

  HAL_NVIC_SetPriority(EXTI3_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(EXTI3_IRQn);

}

在这里插入图片描述
头文件

/*
 * driver_key_int.h
 *
 *  Created on: Jan 1, 2022
 *      Author: lenovo
 */

#ifndef DRIVER_KEY_INT_H_
#define DRIVER_KEY_INT_H_

#include "main.h"
#include "stm32mp1xx_hal.h"

#define LED_GREEN_ON()      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_RESET);
#define LED_GREEN_OFF()	  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_SET);

#define LED_YELLOW_ON()     HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,GPIO_PIN_RESET);
#define LED_YELLOW_OFF()    HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,GPIO_PIN_SET);

void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin);
#endif /* DRIVER_KEY_INT_H_ */

.c文件

/*
 * driver_key_int.c
 *
 *  Created on: Jan 1, 2022
 *      Author: lenovo
 */

#include "driver_key_int.h"
#include <stdbool.h>
static bool key1_flag=false;
static bool key2_flag=false;

void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin){
	switch(GPIO_Pin){
	case KEY_USER1_Pin:
	{
		key1_flag=!key1_flag;
		if(key1_flag){
			LED_GREEN_ON();
		}else{
			LED_GREEN_OFF();
		}
		break;
	}

	case KEY_USER2_Pin:
	{
		key2_flag=!key2_flag;
		if(key2_flag){
			LED_YELLOW_ON();
		}else{
			LED_YELLOW_OFF();
		}
		break;
	}
	break;
	}
}

总结

加油

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>