4.STM32CubeIDE按键实验


前言

使用STM32CubeIDE实现按键实验。
硬件:STM32F103C8T6最小系统板 + 自制扩展板
软件:STM32CubeIDE


一、实验目的

实现扩展板上的KEY1控制LED1翻转,KEY2控制LED2翻转,KEY3控制蜂鸣器响停,KEY4控制跑马灯的开关。

二、学习内容

  1. 学习GPIO的输入使用
  2. 学习按键(KEY)控制

三、实践操作

1.硬件介绍

硬件:STM32F103C8T6最小系统板 + 自制扩展板

自制扩展板中有一个蜂鸣器、LED灯与按键,LED1为蓝灯,LED2为橙灯;
蜂鸣器的IO为PA15,LED1的IO为PB3,LED2的IO为PB4,KEY1的IO为PB0,KEY2的IO为PB1,KEY3的IO为PB8,KEY4的IO为PB9
蜂鸣器为高电平有效,LED1为低电平有效,KEY1~4均为检测低电平
无外部上拉/下拉电阻(最好在硬件上进行上下拉操作),需在软件中进行弱上拉/下拉

原理图如下图所示(仅介绍按键,其他外设在上一篇文章中有介绍):原理图
由上图可以看出,当按键按下时,IO口读取到低电平;上图中的C1~4为滤波电容,滤除机械开关噪声,避免一次按键被误读多次(防抖)。

实物图如下图所示:
实物图

2.软件介绍

首先新建工程并进行初始化配置:

在此不进行赘述,详细步骤可移步至之前文章:2.STM32CubeIDE跑马灯实验
与上一篇文章不同的是,需要配置PB0、PB1、PB8、PB9,如下图所示:配置IO
由上图可以看到,需要将按键IO配置为输入模式配置弱上拉进行引脚重命名(用户标签)

接下来进行按键实验的代码编程

  1. 为了使代码更加简洁,同样采用新建文件夹的方式存放key.h与key.c文件,并且用宏定义的方式读取按键的状态,详细步骤可移步至之前文章:2.STM32CubeIDE跑马灯实验
    其中key.h文件代码如下:
#ifndef BSP_KEY_KEY_H_
#define BSP_KEY_KEY_H_

#include "main.h"

#define Read_KEY1			HAL_GPIO_ReadPin(GPIOB,KEY1_Pin)		/* 读取KEY1引脚 */
#define Read_KEY2			HAL_GPIO_ReadPin(GPIOB,KEY2_Pin)		/* 读取KEY2引脚 */
#define Read_KEY3			HAL_GPIO_ReadPin(GPIOB,KEY3_Pin)		/* 读取KEY3引脚 */
#define Read_KEY4			HAL_GPIO_ReadPin(GPIOB,KEY4_Pin)		/* 读取KEY4引脚 */

#define KEY1_PRES			1										/* KEY1按下 */
#define KEY2_PRES			2										/* KEY2按下 */
#define KEY3_PRES			3										/* KEY3按下 */
#define KEY4_PRES			4										/* KEY4按下 */

uint8_t key_scan(uint8_t mode);     /* 按键扫描函数 */

#endif /* BSP_KEY_KEY_H_ */

为了使代码进一步简洁,用宏定义的方式实现LED与蜂鸣器的状态翻转。
led.h中新增代码:

/* led.h */
#define LED1_TOGGLE()			HAL_GPIO_TogglePin(GPIOB, LED1_Pin)
#define LED2_TOGGLE()			HAL_GPIO_TogglePin(GPIOB, LED2_Pin)

beep.h中新增代码:

/* beep.h */
#define BEEP_TOGGLE()			HAL_GPIO_TogglePin(GPIOA, Buzzer_Pin)

其中HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)为HAL库的翻转IO状态的函数,第一个参数为IO的组(例如GPIOA),第二个参数为IO的引脚(例如GPIO_PIN_0);用户对引脚重命名后,可在main.c中查看具体的GPIO相关的宏定义,例如:

/* main.h */
#define KEY1_Pin GPIO_PIN_0
#define KEY1_GPIO_Port GPIOB
#define KEY2_Pin GPIO_PIN_1
#define KEY2_GPIO_Port GPIOB
#define Buzzer_Pin GPIO_PIN_15
#define Buzzer_GPIO_Port GPIOA
#define LED1_Pin GPIO_PIN_3
#define LED1_GPIO_Port GPIOB
#define LED2_Pin GPIO_PIN_4
#define LED2_GPIO_Port GPIOB
#define KEY3_Pin GPIO_PIN_8
#define KEY3_GPIO_Port GPIOB
#define KEY4_Pin GPIO_PIN_9
#define KEY4_GPIO_Port GPIOB
  1. 编写跑马灯函数
    之前实现跑马灯是在main.c中完成的,我们可以将其封装为一个函数,之后只需要在main.c中调用即可,函数定义需要写在.c文件中,函数声明需要写在.h文件中
/* led.h */
void LED_Marquee();
/* led.c */
void LED_Marquee()
{
		LED1(0);
		LED2(1);
		HAL_Delay(500);
		LED1(1);
		LED2(0);
		HAL_Delay(500);
}
  1. 编写按键程序
    轻触按键在按下时,会产生机械抖动,我们在硬件上可以通过增加滤波电容对其进行消除,也可以通过软件实现,当然两个都存在更好;
    轻触按键在按下时,如果不松开,IO口会持续读取到低电平,将其称为连按状态,在该状态下,如果不松手,则会一直执行按键的功能,有些时候我们是不希望这样的;
    当有多个按键存在时,可以通过函数实现对按键检测代码进行封装,通过返回不同的值来确定是哪个按键按下,从而进一步实现代码的简洁。
    具体代码如下(参考正点原子按键实验代码):
/* key.h */
#ifndef BSP_KEY_KEY_H_
#define BSP_KEY_KEY_H_

#include "main.h"

#define Read_KEY1			HAL_GPIO_ReadPin(GPIOB,KEY1_Pin)		/* 读取KEY1引脚 */
#define Read_KEY2			HAL_GPIO_ReadPin(GPIOB,KEY2_Pin)		/* 读取KEY2引脚 */
#define Read_KEY3			HAL_GPIO_ReadPin(GPIOB,KEY3_Pin)		/* 读取KEY3引脚 */
#define Read_KEY4			HAL_GPIO_ReadPin(GPIOB,KEY4_Pin)		/* 读取KEY4引脚 */

#define KEY1_PRES			1										/* KEY1按下 */
#define KEY2_PRES			2										/* KEY2按下 */
#define KEY3_PRES			3										/* KEY3按下 */
#define KEY4_PRES			4										/* KEY4按下 */

uint8_t key_scan(uint8_t mode);     /* 按键扫描函数 */

#endif /* BSP_KEY_KEY_H_ */
/* key.c */
#include "key.h"

/**
 * @brief       按键扫描函数
 * @note        该函数有响应优先级(同时按下多个按键): KEY1 > KEY2 > KEY3 > KEY4!!
 * @param       mode:0 / 1, 具体含义如下:
 *   @arg       0,  不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,
 *                  必须松开以后, 再次按下才会返回其他键值)
 *   @arg       1,  支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)
 * @retval      键值, 定义如下:
 *              KEY1_PRES, 1, KEY1按下
 *              KEY2_PRES, 2, KEY2按下
 *              KEY3_PRES, 3, KEY3按下
 *              KEY4_PRES, 4, KEY4按下
 */
uint8_t key_scan(uint8_t mode)
{
    static uint8_t key_up = 1;  /* 按键松开标志 */
    uint8_t keyval = 0;

    if (mode) key_up = 1;       /* 支持连按 */

    if (key_up && ((Read_KEY1 == 0) || (Read_KEY2 == 0) || (Read_KEY3 == 0) || (Read_KEY4 == 0) ))  /* 按键松开标志为1, 且有任意一个按键按下了 */
    {
        HAL_Delay(10);       	/* 去抖动,延时后再一次判断是否按下 */
        key_up = 0;				/* 按键松开标志置0 */

        if (Read_KEY1 == 0)  keyval = KEY1_PRES;

        if (Read_KEY2 == 0)  keyval = KEY2_PRES;

        if (Read_KEY3 == 0)  keyval = KEY3_PRES;

        if (Read_KEY4 == 0)  keyval = KEY4_PRES;
    }
    else if ((Read_KEY1 == 1) && (Read_KEY2 == 1) && (Read_KEY3 == 1) && (Read_KEY4 == 1)) /* 没有任何按键按下, 标记按键松开 */
    {
        key_up = 1;
    }

    return keyval;              /* 返回键值 */
}
  1. 编写main.c,首先需要包含key.h头文件,可采用相对路径或绝对路径,具体区别与方法移步至之前文章:2.STM32CubeIDE跑马灯实验
    接下来就是编写控制逻辑代码,根据实验目的,具体代码如下:
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t key = 0;
	uint8_t Marquee = 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 */

  /* 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 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  key = key_scan(0);								/* 不支持连按 */

	  switch (key)
	  {
		case KEY1_PRES:									/* 按下KEY1 */
			LED1_TOGGLE();
			break;
		case KEY2_PRES:									/* 按下KEY2 */
			LED2_TOGGLE();
			break;
		case KEY3_PRES:									/* 按下KEY3 */
			BEEP_TOGGLE();
			break;
		case KEY4_PRES:									/* 按下KEY4 */
			Marquee = 1;								/* 跑马灯标志位 */
			while(Marquee)
			{
				LED_Marquee();							/* 跑马灯函数 */
				if(key_scan(0) != (0 && KEY4_PRES))		/* 检测是否按下其他按钮 */
				{
					Marquee = 0;						/* 按下其他按键,跑马灯标志位置0 */
				}
			}
		default:
			break;
	}

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

通过按键扫描函数返回的值来判断是哪个按键按下;通过判断是否按下其他按键来跳出跑马灯的while循环.

具体现象:按下KEY1,翻转LED1;按下KEY2,翻转LED2;按下KEY3,翻转蜂鸣器状态(响与不响);按下KEY4,实现跑马灯。

但该程序有一定瑕疵,存在于跑马灯函数中,由于在跑马灯函数中采用的是HAL_Delay(500)的方式实现延时,因此在按下按键的时候,如果程序刚好在HAL_Delay(500)中,则会出现无法识别到这次按键按下,就会出现按下按键但反应的情况,后续可以通过其他进行优化,拭目以待。

由此就可以实现扩展板上的KEY1控制LED1翻转,KEY2控制LED2翻转,KEY3控制蜂鸣器响停,KEY4控制跑马灯开关的效果啦!


总结

本篇介绍了如何实现一个按键实验,分别从硬件方面与软件方面阐述,在硬件方面主要介绍了硬件组成与原理图分析,在软件方面主要介绍了key.c、key.h与main.c文件的代码编写。完美完成本文开篇提到的学习任务与功能!

对于实验复现,无需限制在本文使用的IO,了解原理之后,可以做出更有趣的功能!

  • 33
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值