按键驱动程序

按键驱动程序

image-20260508102503647

#ifndef __KEY_H
#define __KEY_H

#include "stm32f1xx_hal.h"  // HAL 库头文件

// 按键引脚定义
#define KEY1_GPIO_Port GPIOA
#define KEY1_Pin GPIO_PIN_0

#define KEY2_GPIO_Port GPIOA
#define KEY2_Pin GPIO_PIN_1

#define KEY3_GPIO_Port GPIOA
#define KEY3_Pin GPIO_PIN_2

#define KEY4_GPIO_Port GPIOA
#define KEY4_Pin GPIO_PIN_3

// 按键状态
#define KEY_IDLE    0
#define KEY_DOWN    1
#define KEY_UP      2
#define KEY_LONG    3

// 按键结构体
typedef struct {
    uint8_t state;
    uint8_t cnt;
    uint8_t long_cnt;
} Key_t;

// 外部声明
extern Key_t Key1, Key2, Key3, Key4;

// 函数声明
void Key_Init(void);
uint8_t Key_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, Key_t *key);
void Key_Process(void);

#endif

#include "key.h"

Key_t Key1 = {0};
Key_t Key2 = {0};
Key_t Key3 = {0};
Key_t Key4 = {0};

/**
  * @brief  按键初始化(在 CubeMX 里把 PA0~3 配置为上拉输入即可)
  */
void Key_Init(void)
{
    // 引脚已在 CubeMX 配置为 GPIO 上拉输入,这里无需重复初始化
}

/**
  * @brief  按键扫描(消抖 + 长短按,HAL 版本)
  */
uint8_t Key_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, Key_t *key)
{
    uint8_t now_state = HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);

    switch(key->state)
    {
        case KEY_IDLE:
            if(now_state == 0)  // 按下(上拉输入,低电平有效)
            {
                key->cnt = 0;
                key->state = KEY_DOWN;
            }
            break;

        case KEY_DOWN:
            if(now_state == 0)
            {
                key->cnt++;
                if(key->cnt >= 20)  // 消抖 20ms
                {
                    key->state = KEY_LONG;
                    key->long_cnt = 0;
                    return KEY_DOWN;
                }
            }
            else
            {
                key->state = KEY_IDLE;
            }
            break;

        case KEY_LONG:
            if(now_state == 0)
            {
                key->long_cnt++;
                if(key->long_cnt >= 1000)
                {
                    key->long_cnt = 0;
                    return KEY_LONG;
                }
            }
            else
            {
                key->state = KEY_UP;
                key->cnt = 0;
            }
            break;

        case KEY_UP:
            if(now_state == 1)
            {
                key->cnt++;
                if(key->cnt >= 20)
                {
                    key->state = KEY_IDLE;
                    return KEY_UP;
                }
            }
            else
            {
                key->state = KEY_DOWN;
            }
            break;
    }
    return KEY_IDLE;
}

/**
  * @brief  按键总处理(必须 1ms 调用一次)
  */
void Key_Process(void)
{
    uint8_t res;

    // KEY1
    res = Key_Scan(KEY1_GPIO_Port, KEY1_Pin, &Key1);
    if(res == KEY_DOWN)
    {
        // 按键1 短按按下
    }
    if(res == KEY_LONG)
    {
        // 按键1 长按
    }
    if(res == KEY_UP)
    {
        // 按键1 松开
    }

    // KEY2
    res = Key_Scan(KEY2_GPIO_Port, KEY2_Pin, &Key2);
    if(res == KEY_DOWN) {}
    if(res == KEY_LONG) {}
    if(res == KEY_UP)   {}

    // KEY3
    res = Key_Scan(KEY3_GPIO_Port, KEY3_Pin, &Key3);
    if(res == KEY_DOWN) {}
    if(res == KEY_LONG) {}
    if(res == KEY_UP)   {}

    // KEY4
    res = Key_Scan(KEY4_GPIO_Port, KEY4_Pin, &Key4);
    if(res == KEY_DOWN) {}
    if(res == KEY_LONG) {}
    if(res == KEY_UP)   {}
}

如何使用?

main.c 示例

#include "main.h"
#include "stm32f1xx_hal.h"
#include "key.h"  

/* 函数声明 */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);

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

  /* 系统时钟配置 */
  SystemClock_Config();

  /* GPIO 初始化(CubeMX 生成) */
  MX_GPIO_Init();

  /* 按键初始化 */
  Key_Init();

  /* 主循环 */
  while (1)
  {
    /* 1ms 扫描一次按键 */
    Key_Process();
    HAL_Delay(1);
  }
}

/* ==============================
   下面是 CubeMX 自动生成的代码
============================== */
void SystemClock_Config(void)
{
  // 系统时钟配置(CubeMX 生成)
}

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

  __HAL_RCC_GPIOA_CLK_ENABLE();

  // PA0 ~ PA3 配置为上拉输入
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

打开 key.c,在 Key_Process() 里直接写你要的功能,例如:

void Key_Process(void)
{
    uint8_t res;

    // ================= KEY1 =================
    res = Key_Scan(KEY1_GPIO_Port, KEY1_Pin, &Key1);
    if(res == KEY_DOWN)
    {
        // 按键1 短按按下
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 举个例子:翻转LED
    }
    if(res == KEY_LONG)
    {
        // 按键1 长按
    }
    if(res == KEY_UP)
    {
        // 按键1 松开
    }

    // ================= KEY2 =================
    res = Key_Scan(KEY2_GPIO_Port, KEY2_Pin, &Key2);
    if(res == KEY_DOWN)
    {
        // 按键2 按下
    }

    // ================= KEY3 =================
    res = Key_Scan(KEY3_GPIO_Port, KEY3_Pin, &Key3);
    if(res == KEY_DOWN)
    {
        // 按键3 按下
    }

    // ================= KEY4 =================
    res = Key_Scan(KEY4_GPIO_Port, KEY4_Pin, &Key4);
    if(res == KEY_DOWN)
    {
        // 按键4 按下
    }
}
posted @ 2026-05-08 10:31  Q&25  阅读(19)  评论(1)    收藏  举报