按键驱动程序
按键驱动程序

#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 按下
}
}
浙公网安备 33010602011771号