【星云 Orbit • STM32F4】03f. 按键玩法六:按住一个独立按键不松手的加速匀速触发

【星云 Orbit • STM32F4】03f. 按键玩法六:按住一个独立按键不松手的加速匀速触发


引言

在嵌入式系统中,按键不仅是输入设备,还可以通过检测按键的持续状态来实现复杂的控制逻辑。本文将详细介绍如何使用STM32F407的GPIO引脚检测按键的长按状态,并通过HAL库实现加速匀速触发功能。通过本教程,读者将能够掌握独立按键的长按检测方法以及加速匀速触发的实现技巧。


硬件准备

在开始编程之前,确保您已经准备好以下硬件:

  1. STM32F407开发板:板载STM32F407VGT6(Cortex-M4/168MHz)作为主控芯片。
  2. 独立按键:1个独立按键。
  3. 限流电阻:1个220Ω至330Ω的电阻,用于保护电路。
  4. 连接线:用于连接按键和开发板。

硬件连接

将独立按键连接到STM32F407的PB0引脚:

  1. 连接按键的正极

  2. 按键的正极通过电阻连接到PB0。
  3. 连接按键的负极

  4. 按键的负极连接到GND(地)。

GPIO配置

在STM32F407中,GPIO引脚可以配置为多种模式,以适应不同的应用需求。以下是一些常见的GPIO模式:

  1. 输入模式

  2. 浮空输入(Floating Input):引脚处于高阻态,适用于不需要上拉或下拉的情况。
  3. 上拉输入(Pull-Up Input):引脚内部连接上拉电阻,适用于外部信号为低电平有效的情况。
  4. 下拉输入(Pull-Down Input):引脚内部连接下拉电阻,适用于外部信号为高电平有效的情况。
  5. 输出模式

  6. 推挽输出(Push-Pull Output):引脚可以输出高电平或低电平,适用于直接驱动小电流负载,如LED灯。
  7. 开漏输出(Open-Drain Output):引脚输出低电平或高阻态,适用于需要外部上拉电阻的场合。
  8. 复用模式

  9. 用于将GPIO引脚配置为特定的外设功能,如UART、SPI等。

在本教程中,我们将使用上拉输入模式来检测按键的状态,因为这种模式可以直接检测按键的按下和释放状态。

配置GPIO时钟

在使用GPIO引脚之前,需要先使能相应的GPIO时钟。对于PB0引脚,需要使能GPIOB时钟。

// 使能GPIOB时钟
__HAL_RCC_GPIOB_CLK_ENABLE();

配置GPIO引脚

使用GPIO_InitTypeDef结构体配置GPIO引脚的模式、上下拉、速度等参数。

GPIO_InitTypeDef GPIO_InitStruct = {0};

// 配置PB0为上拉输入模式
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉输入模式
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

按键控制模块

为了实现模块化设计,我们将按键的控制功能封装到bsp/KEY目录下的bsp_key.cbsp_key.h文件中。

1. 创建KEY目录

  1. 打开文件管理器

  2. 导航到STM32F407项目目录下的Drivers/BSP文件夹。
  3. 创建新目录

  4. 右键点击空白区域,选择新建文件夹
  5. 输入目录名称KEY,并按回车键确认。

2. 创建bsp_key.cbsp_key.h文件

  • 确保bsp_key.cbsp_key.h文件当前位于Drivers/BSP/KEY目录下。
  • 3. 更新项目包含路径

    1. 打开Keil MDK

    2. 加载当前的STM32F407项目。
    3. 进入项目设置

    4. 右键点击工程名称,选择Options for Target
    5. 添加新的包含路径

    6. 在弹出的窗口中,选择C/C++选项卡。
    7. Include Paths字段中,添加以下路径:
      Drivers/BSP/KEY
      
    8. 确保路径正确无误,点击OK保存设置。

    4. 更新main.c文件

    1. 打开main.c文件

    2. 在Keil MDK的项目资源管理器中,找到并双击main.c文件。
    3. 包含新的头文件

    4. 在文件顶部,添加以下包含语句:
      #include "bsp_key.h"
      
    5. 确保路径正确,以便编译器能够找到该头文件。

    5. 重新编译项目

    1. 编译工程

    2. 点击工具栏中的Build按钮(或按F7键)。
    3. 确保编译过程中没有错误和警告。
    4. 处理编译错误

    5. 如果出现包含路径错误,请检查Include Paths设置是否正确。
    6. 确保bsp_key.h文件位于Drivers/BSP/KEY目录下。

    6. 更新项目分组

    1. 添加新的文件夹分组

    2. 在Keil MDK的项目资源管理器中,右键点击BSP分组,选择Add Group
    3. 输入分组名称KEY,点击OK
    4. 添加文件到分组

    5. 右键点击新的KEY分组,选择Add New Item to Group
    6. 选择Add Existing File,导航到Drivers/BSP/KEY目录,选择bsp_key.cbsp_key.h文件,点击OK
    7. 确保文件可见性

    8. 确保bsp_key.cbsp_key.h文件在KEY分组下可见,并且路径正确。

    按键控制模块实现

    bsp_key.h文件

    #ifndef __BSP_KEY_H
    #define __BSP_KEY_H
    
    #include "stm32f4xx_hal.h"
    
    #define DEBOUNCE_TIME   20      // 按键消抖延迟时间(单位:ms)
    #define SHORT_PRESS_TIME  500    // 短按时间阈值(单位:ms)
    #define LONG_PRESS_TIME   1500   // 长按时间阈值(单位:ms)
    #define ACCELERATION_STEP  100    // 加速步长(单位:ms)
    #define MIN_INTERVAL      200    // 最小触发间隔(单位:ms)
    
    /**
     * @brief 初始化按键
     */
    void KEY_Init(void);
    
    /**
     * @brief 检测按键状态
     * @return 按键状态(0:未按下,1:短按,2:长按)
     */
    uint8_t KEY_GetState(void);
    
    /**
     * @brief 处理按键状态并触发加速匀速动作
     */
    void KEY_Process(void);
    
    #endif /* __BSP_KEY_H */
    

    bsp_key.c文件

    #include "bsp_key.h"
    
    static uint32_t key_press_time = 0;
    static uint8_t key_state = 0;
    static uint32_t last_trigger_time = 0;
    static uint32_t current_interval = 0;
    
    /**
     * @brief 初始化按键
     */
    void KEY_Init(void) {
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        // 使能GPIOB时钟
        __HAL_RCC_GPIOB_CLK_ENABLE();
    
        // 配置PB0为上拉输入模式
        GPIO_InitStruct.Pin = GPIO_PIN_0;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
    
    /**
     * @brief 检测按键状态
     * @return 按键状态(0:未按下,1:短按,2:长按)
     */
    uint8_t KEY_GetState(void) {
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) {
            if (key_state == 0) {
                // 按键按下,记录时间
                key_press_time = HAL_GetTick();
                key_state = 1;
            }
        } else {
            // 按键释放,重置状态
            key_state = 0;
            return 0;
        }
    
        // 检测按键按下的时间
        if (key_state == 1) {
            uint32_t current_time = HAL_GetTick();
            uint32_t press_duration = current_time - key_press_time;
    
            if (press_duration > LONG_PRESS_TIME) {
                key_state = 2;
                return 2; // 长按
            } else if (press_duration > SHORT_PRESS_TIME) {
                key_state = 0;
                return 1; // 短按
            }
        }
    
        return 0; // 未按下
    }
    
    /**
     * @brief 处理按键状态并触发加速匀速动作
     */
    void KEY_Process(void) {
        static uint32_t last_trigger_time = 0;
        static uint32_t current_interval = 0;
    
        if (key_state == 2) { // 长按状态
            uint32_t current_time = HAL_GetTick();
            if (current_time - last_trigger_time >= current_interval) {
                // 触发步进动作
                last_trigger_time = current_time;
                // 在此处添加步进动作的处理代码,例如数值递增或控制设备
    
                // 实现加速逻辑
                if (current_interval > MIN_INTERVAL) {
                    current_interval -= ACCELERATION_STEP;
                    if (current_interval < MIN_INTERVAL) {
                        current_interval = MIN_INTERVAL;
                    }
                }
            }
        } else {
            // 重置加速逻辑
            current_interval = 0;
        }
    }
    

    主程序实现

    #include "stm32f4xx_hal.h"
    #include "bsp_key.h"
    
    int main(void) {
        // 系统初始化
        HAL_Init();
        SystemClock_Config();
    
        // 按键初始化
        KEY_Init();
    
        while (1) {
            // 检测按键状态
            uint8_t state = KEY_GetState();
    
            if (state == 1) {
                // 短按处理
                // 在此处添加短按事件的处理代码
            } else if (state == 2) {
                // 长按处理
                KEY_Process(); // 处理长按并触发加速匀速动作
            }
        }
    }
    

    测试与验证

    1. 编译与下载

    2. 将代码编译并下载到STM32F407开发板中。
    3. 观察按键状态

    4. 连接好硬件后,按下按键,观察是否能够正确检测短按和长按事件。如果按键状态没有正确检测,请检查硬件连接和代码配置是否正确。
    5. 验证加速匀速触发

    6. 长按按键,观察步进触发是否按设定的加速间隔和匀速间隔触发。如果步进触发不正常,请检查加速和匀速阶段的参数设置以及相关处理代码。

    总结

    通过本教程,您已经掌握了如何使用STM32F407的PB0引脚检测独立按键的短按和长按事件,并通过HAL库实现模块化设计。按键状态的检测是关键步骤,选择合适的消抖动和长按检测逻辑可以确保按键的稳定工作。模块化设计使代码更加清晰和易于维护,为后续的项目扩展奠定了良好的基础。希望本教程对您有所帮助,祝您在嵌入式开发的道路上取得更大的成功!

    作者:智木芯语

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【星云 Orbit • STM32F4】03f. 按键玩法六:按住一个独立按键不松手的加速匀速触发

    发表回复