第3章 按键输入实验

第三章 按键输入实验

1. STM32F4 IO口简介

STM32F4 的 IO 口在上两章已经有了比较详细的介绍,这里我们不再多说。 STM32F4 的 IO口做输入使用的时候,是通过调用函数 GPIO_ReadInputDataBit() 来读取 IO 口的状态的。

2. 硬件设计

本实验用的的硬件资源有:

  1. 指示灯DS0、DS1

  2. 蜂鸣器

  3. 4个按键:KEY0、KEY1、KEY2和KEY_UP

DS0、 DS1 以及蜂鸣器和 STM32F4 的连接在上两章都已经分别介绍了,在探索者 STM32F4开发板上的按键 KEY0 连接在 PE4 上、 KEY1 连接在 PE3 上、 KEY2 连接在 PE2 上、 KEY_UP连接在 PA0 上。

屏幕截图 2024 09 08 174410

这里需要注意的是: KEY0、 KEY1 和 KEY2 是低电平有效的,而 KEY_UP 是高电平有效的, 并且外部都没有上下拉电阻,所以,需要在 STM32F4 内部设置上下拉。

3. 软件设计

3.1 key宏定义

// 各按键引脚宏定义
#define KEY0_GPIO GPIOE
#define KEY0_PIN GPIO_PIN_4
#define KEY1_GPIO GPIOE
#define KEY1_PIN GPIO_PIN_3
#define KEY2_GPIO GPIOE
#define KEY2_PIN GPIO_PIN_2
#define KEY_UP_GPIO GPIOA
#define KEY_UP_PIN GPIO_PIN_0

// 读取IO电平状态
#define KEY0_GET HAL_GPIO_ReadPin(KEY0_GPIO, KEY0_PIN)
#define KEY1_GET HAL_GPIO_ReadPin(KEY1_GPIO, KEY1_PIN)
#define KEY2_GET HAL_GPIO_ReadPin(KEY2_GPIO, KEY2_PIN)
#define KEY_UP_GET HAL_GPIO_ReadPin(KEY_UP_GPIO, KEY_UP_PIN)

// 宏定义按键值
#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3
#define KEY_UP_PRES 4

3.2 key初始化函数

void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    // 首先就是开启时钟啦
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    // 接下来配置GPIO
    GPIO_InitStructure.Pin = KEY_UP_PIN;            // key_up引脚
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;      // s输入模式
    GPIO_InitStructure.Pull = GPIO_PULLDOWN;        // 下拉
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;     // 高速
    HAL_GPIO_Init(KEY_UP_GPIO, &GPIO_InitStructure);// 初始化GPIO
    GPIO_InitStructure.Pin = KEY0_PIN|KEY1_PIN|KEY2_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.Pull = GPIO_PULLUP;           // 上拉
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
}

3.3 按键扫描函数

// 按键扫描函数说明
/*
    功能:扫描按键,返回按键值
    函数参数mode:0表示只扫描一次,1表示一直扫描
    返回值:0,没有任何按键按下;1,KEY_UP按下
    响应优先级:KEY0 > KEY1 > KEY2 > KEY_UP
*/
uint8_t KEY_Scan(uint8_t mode)
{
    static uint8_t key_flag = 1; // 按键松开标志位
    if(mode == 1)
       key_flag = 1;
    // 判断是否有按键按下
    if(key_flag && (KEY0_GET == 0 || KEY1_GET == 0 || KEY2_GET == 0 || KEY_UP_GET == 1)) // 不要忘记了KEY_UP是高电平有效   
    {
        delay_ms(10);
        key_flag = 0; // 按键按下标志位
        if(KEY0_GET == 0) return KEY0_PRES;
        else if(KEY1_GET == 0) return KEY1_PRES;
        else if(KEY2_GET == 0) return KEY2_PRES;
        else if(KEY_UP_GET == 1) return KEY_UP_PRES;
    }
    else if(KEY0_GET == 1 && KEY1_GET == 1 && KEY2_GET == 1 && KEY_UP_GET == 0)
    {
        key_flag = 1; // 按键松开
        return 0;
    }
    return 0;
}    
  • 如果按键按下,防抖延时后会检查是哪一个按键被按下,并返回相应的按键值(KEY0_PRESKEY1_PRES 等)。
  • 如果没有按键按下,返回 0

3.4 主函数

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"

int main(void)
{
	uint8_t key_value;
	HAL_Init();
	Stm32_Clock_Init(336,8,2,7);
	delay_init(168);
	LED_Init();
	KEY_Init();
	while(1)
	{
		key_value = KEY_Scan(0);
		switch(key_value)
		{
			case KEY_UP_PRES: // LED0,LED1互斥
				LED1 = !LED1;
				LED0 = !LED1;
				break;
			case KEY0_PRES: // LED0,LED1同时翻转
				LED0 = !LED0;
				LED1 = !LED1;
				break;
			case KEY1_PRES:
				LED1 = !LED1;
				break;
			case KEY2_PRES:
				LED0 = !LED0;
				break;
		}
	}
}

根据不同的按键值产生不同的效果

4. 小结

前面我们都是将GPIO的基本输出,这一章本章其实就是检测GPIO输入,怎么输入的?通过按键,不同的按键值产生不同的效果,一个新的hal库函数我们需要掌握:

4.1 函数原型

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

4.2 参数

  1. GPIOx: 指向 GPIO 外设的基地址。例如,GPIOAGPIOBGPIOC 等。
  2. GPIO_Pin: 需要读取状态的 GPIO 引脚的编号。例如,GPIO_PIN_0GPIO_PIN_1 等。

4.3 返回值

  • GPIO_PIN_RESET: 引脚的状态为低电平(逻辑 0)。
  • GPIO_PIN_SET: 引脚的状态为高电平(逻辑 1)。

4.4 示例代码

下面是一个使用 HAL_GPIO_ReadPin() 函数读取 GPIO 引脚状态的示例。假设我们要读取 GPIOA 端口上的 GPIO_PIN_0 引脚的状态。

#include "stm32f4xx_hal.h"

// 假设已经初始化了 HAL 库和 GPIO

int main(void)
{
    // HAL 库初始化
    HAL_Init();

    // GPIO 初始化配置
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 启用 GPIOA 时钟

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 配置 GPIOA 的引脚 0 作为输入模式
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 不使用上拉或下拉电阻
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    while (1)
    {
        // 读取 GPIOA 的引脚 0 的状态
        GPIO_PinState pinState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

        if (pinState == GPIO_PIN_SET)
        {
            // 引脚状态为高电平
            // 执行相应的操作
        }
        else
        {
            // 引脚状态为低电平
            // 执行相应的操作
        }

        // 延时
        HAL_Delay(100); // 延时 100ms
    }
}

2024.9.27 第一次修订,后期不再维护

2024.12.20 丰富内容,优化代码

posted @ 2024-09-27 15:37  hazy1k  阅读(57)  评论(0编辑  收藏  举报