1.添加了必要的注释和readme文件以提高代码可读性和项目文档化。2.增加了按键按下时LCD屏幕显示功能
This commit is contained in:
@@ -1,63 +1,82 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @文件 key.c
|
||||
* @作者 阜阳师范大学物电学院
|
||||
* @版本 V0.1
|
||||
* @日期 2026-01-15
|
||||
* @简介 按键驱动 - 基于 MultiButton 的高可移植性实现
|
||||
* @说明
|
||||
*
|
||||
****
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* @file key.c
|
||||
* @brief 按键驱动模块 - 基于 MultiButton 库的高可移植性实现
|
||||
* @details 本文件实现了基于 MultiButton 库的按键驱动功能,支持多按键配置、
|
||||
* 按键状态检测、按键事件回调等功能。采用配置表方式管理按键,
|
||||
* 便于扩展和维护。支持单次点击事件检测。
|
||||
* @author 阜阳师范大学物电学院
|
||||
* @version V0.1
|
||||
* @date 2026.1.19
|
||||
* @note 依赖库: MultiButton
|
||||
* 支持按键: ENTER, UP, DOWN, LEFT, RIGHT, ESC, ADD, DEC, RESET
|
||||
* 按键模式: 输入模式,无上拉/下拉
|
||||
* 特殊处理: PB3 需要禁用 JTAG 才能作为普通 GPIO 使用
|
||||
******************************************************************************/
|
||||
|
||||
#include "key.h"
|
||||
#include "160160D.h"
|
||||
|
||||
// 按键配置结构体
|
||||
/* ============================================================================
|
||||
* 按键配置结构体定义
|
||||
* ============================================================================ */
|
||||
/**
|
||||
* @brief 按键配置结构体
|
||||
* @details 用于存储每个按键的硬件配置信息,包括 GPIO 端口、引脚和按键类型
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t pin; // GPIO引脚
|
||||
GPIO_TypeDef* port; // GPIO端口
|
||||
KEY_TYPE key_type; // 按键ID
|
||||
uint16_t pin; /**< GPIO 引脚编号(如 GPIO_PIN_12) */
|
||||
GPIO_TypeDef* port; /**< GPIO 端口(如 GPIOD) */
|
||||
KEY_TYPE key_type; /**< 按键类型标识(如 KEY_ENTER) */
|
||||
} KeyConfig_t;
|
||||
|
||||
/*
|
||||
*******************详细引脚映射*****************************
|
||||
| 按键名称 | 端口 | 引脚 | 位定义 | 功能说明 |
|
||||
|---------|------|------|--------|----------|
|
||||
| KEY_ENTER | GPIOB | PB15 | KEY_ENTER_BIT | 确认键 |
|
||||
| KEY_UP | GPIOD | PD11 | KEY_UP_BIT | 上键 |
|
||||
| KEY_DOWN | GPIOD | PD10 | KET_DOWN_BIT | 下键 |
|
||||
| KEY_LEFT | GPIOD | PD13 | KET_LEFT_BIT | 左键 |
|
||||
| KEY_RIGHT | GPIOD | PD8 | KET_RIGHT_BIT | 右键 |
|
||||
| KEY_ESC | GPIOD | PD12 | KET_ESC_BIT | 取消键 |
|
||||
| KEY_ADD | GPIOD | PD14 | KET_ADD_BIT | 加键 |
|
||||
| KEY_DEC | GPIOD | PD9 | KET_DEC_BIT | 减键 |
|
||||
| KEY_RESET | GPIOD | PD15 | KET_RESET_BIT | 复位键 |
|
||||
***************************************************************
|
||||
*/
|
||||
// 按键配置表
|
||||
/* ============================================================================
|
||||
* 按键硬件引脚映射表
|
||||
* ============================================================================ */
|
||||
/**
|
||||
* @brief 按键硬件引脚映射表
|
||||
* @details 详细引脚映射关系如下:
|
||||
* | 按键名称 | 端口 | 引脚 | 按键类型 | 功能说明 |
|
||||
* |---------|------|------|----------|----------|
|
||||
* | KEY_ENTER | GPIOD | PD12 | KEY_ENTER | 确认键 |
|
||||
* | KEY_UP | GPIOD | PD11 | KEY_UP | 上键 |
|
||||
* | KEY_DOWN | GPIOD | PD10 | KEY_DOWN | 下键 |
|
||||
* | KEY_LEFT | GPIOD | PD13 | KEY_LEFT | 左键 |
|
||||
* | KEY_RIGHT | GPIOD | PD8 | KEY_RIGHT | 右键 |
|
||||
* | KEY_ESC | GPIOB | PB15 | KEY_ESC | 取消键 |
|
||||
* | KEY_ADD | GPIOB | PB3 | KEY_ADD | 加键(需禁用 JTAG) |
|
||||
* | KEY_RESET | GPIOD | PD15 | KEY_RESET | 复位键 |
|
||||
* @note PB3 引脚默认被 JTAG 占用,需要禁用 JTAG 才能作为普通 GPIO 使用
|
||||
*/
|
||||
static const KeyConfig_t key_configs[] = {
|
||||
{GPIO_PIN_12, GPIOD, KEY_ENTER},
|
||||
{GPIO_PIN_11, GPIOD, KEY_UP},
|
||||
{GPIO_PIN_10, GPIOD, KEY_DOWN},
|
||||
{GPIO_PIN_13, GPIOD, KEY_LEFT},
|
||||
{GPIO_PIN_8, GPIOD, KEY_RIGHT},
|
||||
{GPIO_PIN_15, GPIOB, KEY_ESC},
|
||||
{GPIO_PIN_3, GPIOB, KEY_ADD},
|
||||
{GPIO_PIN_15, GPIOD, KEY_RESET},
|
||||
{GPIO_PIN_12, GPIOD, KEY_ENTER}, /**< 确认键:PD12 */
|
||||
{GPIO_PIN_11, GPIOD, KEY_UP}, /**< 上键:PD11 */
|
||||
{GPIO_PIN_10, GPIOD, KEY_DOWN}, /**< 下键:PD10 */
|
||||
{GPIO_PIN_13, GPIOD, KEY_LEFT}, /**< 左键:PD13 */
|
||||
{GPIO_PIN_8, GPIOD, KEY_RIGHT}, /**< 右键:PD8 */
|
||||
{GPIO_PIN_15, GPIOB, KEY_ESC}, /**< 取消键:PB15 */
|
||||
{GPIO_PIN_3, GPIOB, KEY_ADD}, /**< 加键:PB3(需禁用 JTAG) */
|
||||
{GPIO_PIN_15, GPIOD, KEY_RESET}, /**< 复位键:PD15 */
|
||||
};
|
||||
#define KEY_COUNT (sizeof(key_configs) / sizeof(key_configs[0]))
|
||||
|
||||
// 按键句柄数组
|
||||
static Button btn_handles[KEY_COUNT];
|
||||
// 业务逻辑回调函数指针(由main.c注册)
|
||||
static KeyCallback key_callback = NULL;
|
||||
#define KEY_COUNT (sizeof(key_configs) / sizeof(key_configs[0])) /**< 按键总数 */
|
||||
|
||||
/* ============================================================================
|
||||
* 全局变量定义
|
||||
* ============================================================================ */
|
||||
static Button btn_handles[KEY_COUNT]; /**< MultiButton 按键句柄数组 */
|
||||
static KeyCallback key_callback = NULL; /**< 业务逻辑层注册的回调函数指针 */
|
||||
|
||||
/* ============================================================================
|
||||
* 内部函数实现
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief 读取按键GPIO电平
|
||||
* @param button_id 按键ID
|
||||
* @retval 0:按下, 1:释放
|
||||
* @brief 读取按键 GPIO 电平状态
|
||||
* @param button_id 按键 ID(对应 key_configs 数组索引,0 到 KEY_COUNT-1)
|
||||
* @note 该函数由 MultiButton 库调用,用于读取按键的硬件状态
|
||||
* 返回值:0 表示按下(低电平),1 表示释放(高电平)
|
||||
* @retval 0: 按键按下(低电平)
|
||||
* @retval 1: 按键释放(高电平)
|
||||
*/
|
||||
static uint8_t button_read_level(uint8_t button_id)
|
||||
{
|
||||
@@ -66,82 +85,117 @@ static uint8_t button_read_level(uint8_t button_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 统一的按键回调函数(内部使用,调用业务逻辑回调)
|
||||
* @param btn 按键句柄指针
|
||||
* @brief 统一的按键事件回调函数(内部使用)
|
||||
* @param btn MultiButton 库的按键句柄指针
|
||||
* @note 当 MultiButton 库检测到按键事件时,会调用此函数
|
||||
* 此函数将按键事件转换为业务逻辑层的按键类型,并调用注册的回调函数
|
||||
* 处理流程:
|
||||
* 1. 检查按键句柄和回调函数是否有效
|
||||
* 2. 从按键句柄中获取 button_id
|
||||
* 3. 通过 button_id 查找对应的按键类型
|
||||
* 4. 调用业务逻辑层注册的回调函数
|
||||
* @retval 无
|
||||
*/
|
||||
static void button_callback(Button* btn)
|
||||
{
|
||||
if (btn != NULL && key_callback != NULL)
|
||||
{
|
||||
// 通过button_id获取对应的按键类型
|
||||
/* 通过 button_id 获取对应的按键类型 */
|
||||
uint8_t button_id = btn->button_id;
|
||||
if (button_id < KEY_COUNT)
|
||||
{
|
||||
// 调用业务逻辑层注册的回调函数
|
||||
/* 调用业务逻辑层注册的回调函数 */
|
||||
key_callback(key_configs[button_id].key_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册按键回调函数(供业务逻辑层调用)
|
||||
* @param callback 回调函数指针
|
||||
* @brief 使能指定 GPIO 端口的时钟
|
||||
* @param port GPIO 端口指针(如 GPIOA, GPIOB, GPIOD 等)
|
||||
* @note 使用 switch-case 结构实现,代码简洁清晰
|
||||
* 支持所有 GPIO 端口(A-G)
|
||||
* 在初始化 GPIO 之前必须使能对应的时钟
|
||||
* @retval 无
|
||||
*/
|
||||
static void KEY_GPIO_ClockEnable(GPIO_TypeDef *port)
|
||||
{
|
||||
switch ((uint32_t)port) {
|
||||
case (uint32_t)GPIOA: __HAL_RCC_GPIOA_CLK_ENABLE(); break; /**< 使能 GPIOA 时钟 */
|
||||
case (uint32_t)GPIOB: __HAL_RCC_GPIOB_CLK_ENABLE(); break; /**< 使能 GPIOB 时钟 */
|
||||
case (uint32_t)GPIOC: __HAL_RCC_GPIOC_CLK_ENABLE(); break; /**< 使能 GPIOC 时钟 */
|
||||
case (uint32_t)GPIOD: __HAL_RCC_GPIOD_CLK_ENABLE(); break; /**< 使能 GPIOD 时钟 */
|
||||
case (uint32_t)GPIOE: __HAL_RCC_GPIOE_CLK_ENABLE(); break; /**< 使能 GPIOE 时钟 */
|
||||
case (uint32_t)GPIOF: __HAL_RCC_GPIOF_CLK_ENABLE(); break; /**< 使能 GPIOF 时钟 */
|
||||
case (uint32_t)GPIOG: __HAL_RCC_GPIOG_CLK_ENABLE(); break; /**< 使能 GPIOG 时钟 */
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* 外部接口函数实现
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief 按键硬件初始化函数
|
||||
* @note 初始化流程:
|
||||
* 1. 使能 AFIO 时钟(修改 AFIO 寄存器前必须)
|
||||
* 2. 禁用 JTAG,保留 SWD(释放 PA15、PB3、PB4 作为普通 GPIO)
|
||||
* 3. 遍历按键配置表,对每个按键进行初始化:
|
||||
* a. 使能对应 GPIO 端口时钟
|
||||
* b. 配置 GPIO 为输入模式,无上拉/下拉,高速模式
|
||||
* c. 初始化 MultiButton 按键句柄
|
||||
* d. 绑定单次点击事件到回调函数
|
||||
* e. 启动按键检测
|
||||
* @note 特殊处理:由于使用了 PB3 引脚,需要禁用 JTAG 功能
|
||||
* JTAG 禁用后,PA13、PA14 仍可用于 SWD 调试
|
||||
* @retval 无
|
||||
*/
|
||||
void Key_Init(void)
|
||||
{
|
||||
/* ========== AFIO 和 JTAG 配置 ========== */
|
||||
__HAL_RCC_AFIO_CLK_ENABLE(); /**< 使能 AFIO 时钟(修改 AFIO 寄存器前必须) */
|
||||
|
||||
/* 禁用 JTAG,保留 SWD(PA13、PA14 仍可用于调试) */
|
||||
/* 这会释放 PA15、PB3、PB4 作为普通 GPIO */
|
||||
__HAL_AFIO_REMAP_SWJ_NOJTAG();
|
||||
|
||||
/* ========== GPIO 和按键初始化 ========== */
|
||||
GPIO_InitTypeDef gpio_init_struct = {0};
|
||||
|
||||
/* 批量初始化所有按键 */
|
||||
for (uint8_t button_id = 0; button_id < KEY_COUNT; button_id++)
|
||||
{
|
||||
/* 使能对应 GPIO 端口时钟 */
|
||||
KEY_GPIO_ClockEnable(key_configs[button_id].port);
|
||||
|
||||
/* 配置 GPIO 为输入模式 */
|
||||
gpio_init_struct.Pin = key_configs[button_id].pin;
|
||||
gpio_init_struct.Mode = GPIO_MODE_INPUT; /**< 输入模式 */
|
||||
gpio_init_struct.Pull = GPIO_NOPULL; /**< 无上拉/下拉(外部电路处理) */
|
||||
gpio_init_struct.Speed = GPIO_SPEED_HIGH; /**< 高速模式,提高响应速度 */
|
||||
HAL_GPIO_Init(key_configs[button_id].port, &gpio_init_struct);
|
||||
|
||||
/* 初始化 MultiButton 按键句柄 */
|
||||
button_init(&btn_handles[button_id], button_read_level, 0, button_id);
|
||||
|
||||
/* 绑定单次点击事件到回调函数 */
|
||||
button_attach(&btn_handles[button_id], BTN_SINGLE_CLICK, button_callback);
|
||||
|
||||
/* 启动按键检测 */
|
||||
button_start(&btn_handles[button_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册按键回调函数(供业务逻辑层调用)
|
||||
* @param callback 按键回调函数指针,当检测到按键事件时会调用此函数
|
||||
* @note 业务逻辑层通过此函数注册按键处理回调
|
||||
* 回调函数参数为 KEY_TYPE 类型,表示被按下的按键类型
|
||||
* 如果传入 NULL,则取消已注册的回调函数
|
||||
* @retval 无
|
||||
*/
|
||||
void Key_RegisterCallback(KeyCallback callback)
|
||||
{
|
||||
key_callback = callback;
|
||||
}
|
||||
/**
|
||||
* @brief 使能GPIO时钟
|
||||
* @param port: GPIO端口
|
||||
* @retval 无
|
||||
* @note 使用switch-case结构,代码更简洁清晰,支持所有GPIO端口(A-G)
|
||||
*/
|
||||
static void KEY_GPIO_ClockEnable(GPIO_TypeDef *port)
|
||||
{
|
||||
switch ((uint32_t)port) {
|
||||
case (uint32_t)GPIOA: __HAL_RCC_GPIOA_CLK_ENABLE(); break;
|
||||
case (uint32_t)GPIOB: __HAL_RCC_GPIOB_CLK_ENABLE(); break;
|
||||
case (uint32_t)GPIOC: __HAL_RCC_GPIOC_CLK_ENABLE(); break;
|
||||
case (uint32_t)GPIOD: __HAL_RCC_GPIOD_CLK_ENABLE(); break;
|
||||
case (uint32_t)GPIOE: __HAL_RCC_GPIOE_CLK_ENABLE(); break;
|
||||
case (uint32_t)GPIOF: __HAL_RCC_GPIOF_CLK_ENABLE(); break;
|
||||
case (uint32_t)GPIOG: __HAL_RCC_GPIOG_CLK_ENABLE(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
/**************************************************************************************
|
||||
* FunctionName : Key_Init()
|
||||
* Description : 按键硬件初始化(使用MultiButton库)
|
||||
* EntryParameter : none
|
||||
* ReturnValue : none
|
||||
**************************************************************************************/
|
||||
void Key_Init(void)
|
||||
{
|
||||
/*由于使用了 PB3 才需要特殊加的*/
|
||||
__HAL_RCC_AFIO_CLK_ENABLE(); // AFIO时钟(修改AFIO寄存器前必须)
|
||||
|
||||
/* 禁用JTAG,保留SWD(PA13、PA14仍可用于调试)*/
|
||||
/* 这会释放 PA15、PB3、PB4 作为普通GPIO */
|
||||
__HAL_AFIO_REMAP_SWJ_NOJTAG();
|
||||
|
||||
|
||||
GPIO_InitTypeDef gpio_init_struct = {0};
|
||||
// 批量初始化GPIO
|
||||
for (uint8_t button_id = 0; button_id < KEY_COUNT; button_id++)
|
||||
{
|
||||
/* 使能对应GPIO时钟 */
|
||||
KEY_GPIO_ClockEnable(key_configs[button_id].port);
|
||||
|
||||
// 配置并初始化引脚
|
||||
gpio_init_struct.Pin = key_configs[button_id].pin;
|
||||
gpio_init_struct.Mode = GPIO_MODE_INPUT;
|
||||
gpio_init_struct.Pull = GPIO_NOPULL;
|
||||
gpio_init_struct.Speed = GPIO_SPEED_HIGH;
|
||||
HAL_GPIO_Init(key_configs[button_id].port, &gpio_init_struct);
|
||||
|
||||
button_init(&btn_handles[button_id], button_read_level, 0, button_id);
|
||||
button_attach(&btn_handles[button_id], BTN_SINGLE_CLICK, button_callback);
|
||||
button_start(&btn_handles[button_id]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,86 @@
|
||||
/******************************************************************************
|
||||
* @file key.h
|
||||
* @brief 按键驱动模块头文件
|
||||
* @details 本文件定义了按键驱动的接口和数据结构,包括按键类型枚举、
|
||||
* 按键回调函数类型定义以及外部接口函数声明。
|
||||
* @author 阜阳师范大学物电学院
|
||||
* @version V0.1
|
||||
* @date 2026.1.19
|
||||
* @note 依赖库: MultiButton
|
||||
* 使用方式:
|
||||
* 1. 调用 Key_Init() 初始化按键硬件
|
||||
* 2. 调用 Key_RegisterCallback() 注册按键回调函数
|
||||
* 3. 在定时器中调用 Button_Ticks() 进行按键扫描
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __KEY_H__
|
||||
#define __KEY_H__
|
||||
|
||||
|
||||
|
||||
#include "./SYSTEM/sys/sys.h"
|
||||
#include "MultiButton.h"
|
||||
|
||||
/* ============================================================================
|
||||
* 按键类型枚举定义
|
||||
* ============================================================================ */
|
||||
/**
|
||||
* @brief 按键类型枚举
|
||||
* @details 定义了系统中所有支持的按键类型
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
KEY_NONE = 0, // 没有按键
|
||||
|
||||
KEY_ENTER, // 确认
|
||||
KEY_UP, // 向上
|
||||
KEY_DOWN, // 向下
|
||||
KEY_ESC, //取消
|
||||
KEY_ADD, //加
|
||||
KEY_DEC, //减
|
||||
KEY_LEFT, //左
|
||||
KEY_RIGHT, //右
|
||||
KEY_RESET, //复位
|
||||
KEY_FACTORY, //工厂
|
||||
KEY_NONE = 0, /**< 无按键按下 */
|
||||
KEY_ENTER, /**< 确认键 */
|
||||
KEY_UP, /**< 向上键 */
|
||||
KEY_DOWN, /**< 向下键 */
|
||||
KEY_ESC, /**< 取消键 */
|
||||
KEY_ADD, /**< 加键 */
|
||||
KEY_DEC, /**< 减键 */
|
||||
KEY_LEFT, /**< 向左键 */
|
||||
KEY_RIGHT, /**< 向右键 */
|
||||
KEY_RESET, /**< 复位键 */
|
||||
KEY_FACTORY, /**< 工厂模式键 */
|
||||
} KEY_TYPE;
|
||||
|
||||
// 按键回调函数类型定义(业务逻辑层使用)
|
||||
// 参数: key_type - 按键类型
|
||||
/* ============================================================================
|
||||
* 回调函数类型定义
|
||||
* ============================================================================ */
|
||||
/**
|
||||
* @brief 按键回调函数类型定义
|
||||
* @param key_type 按键类型(KEY_TYPE 枚举值)
|
||||
* @note 业务逻辑层需要实现此类型的回调函数,用于处理按键事件
|
||||
* 当检测到按键按下时,会调用注册的回调函数
|
||||
* @retval 无
|
||||
*/
|
||||
typedef void (*KeyCallback)(KEY_TYPE key_type);
|
||||
|
||||
/* ============================================================================
|
||||
* 外部接口函数声明
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief 按键硬件初始化函数
|
||||
* @note 初始化所有按键的 GPIO 配置和 MultiButton 库
|
||||
* 特殊处理:禁用 JTAG 以释放 PB3 等引脚
|
||||
* 必须在系统初始化时调用一次
|
||||
* @retval 无
|
||||
*/
|
||||
void Key_Init(void);
|
||||
|
||||
// 按键驱动函数(在key.c中实现,使用MultiButton库)
|
||||
void Key_Init(void); // 按键初始化
|
||||
void Key_RegisterCallback(KeyCallback callback); // 注册按键回调函数(业务逻辑层调用)
|
||||
#define Button_Ticks() button_ticks()
|
||||
#endif
|
||||
/**
|
||||
* @brief 注册按键回调函数(供业务逻辑层调用)
|
||||
* @param callback 按键回调函数指针,当检测到按键事件时会调用此函数
|
||||
* @note 业务逻辑层通过此函数注册按键处理回调
|
||||
* 如果传入 NULL,则取消已注册的回调函数
|
||||
* @retval 无
|
||||
*/
|
||||
void Key_RegisterCallback(KeyCallback callback);
|
||||
|
||||
/**
|
||||
* @brief MultiButton 库的按键扫描函数宏定义
|
||||
* @note 需要在定时器中周期性调用此函数(建议 5-10ms 调用一次)
|
||||
* 用于 MultiButton 库进行按键状态扫描和事件检测
|
||||
* @retval 无
|
||||
*/
|
||||
#define Button_Ticks() button_ticks()
|
||||
|
||||
#endif /* __KEY_H__ */
|
||||
|
||||
Reference in New Issue
Block a user