11 KiB
11 KiB
工业级嵌入式菜单组件
1. 项目概述
本项目是一个基于C语言开发的工业级嵌入式菜单组件,设计用于资源受限的嵌入式系统,具有高可移植性、模块化、可裁剪、低资源占用和事件驱动解耦等核心特点。
1.1 核心特性
- 分层架构设计:核心层 + 功能扩展层 + 硬件端口层,彻底解耦硬件与业务逻辑
- 事件驱动机制:基于事件队列的异步处理,提高系统响应性
- 静态内存管理:完全使用静态数组,避免内存碎片,适合资源受限系统
- 高度可配置:通过宏开关实现功能裁剪,可根据项目需求定制功能
- 工业级鲁棒性:完善的边界检查、错误处理和断言机制
- Modbus映射支持:内置参数与Modbus寄存器双向映射功能
2. 目录结构
menu/
├── api/ # 对外API层(用户唯一需要引用的头文件)
│ ├── menu.h # 主接口头文件
│ └── menu_config.h # 配置文件(功能开关、资源大小)
├── internal/ # 内部头文件层(用户无需关心)
│ ├── menu_core.h # 核心类型定义
│ ├── menu_data.h # 共享全局变量声明
│ ├── menu_def.h # 内部宏和辅助函数
│ └── menu_modbus.h # Modbus映射内部定义
├── port/ # 硬件端口层(用户需适配)
│ ├── menu_port.c # 硬件接口实现(示例)
│ └── menu_port.h # 硬件接口声明
├── src/ # 源码层
│ ├── core/ # 核心逻辑
│ │ └── menu_core.c # 导航、栈管理、主循环
│ ├── features/ # 功能扩展
│ │ └── menu_modbus.c # Modbus映射功能
│ ├── lang/ # 多语言支持
│ │ └── menu_lang.c # 语言切换、字符串管理
│ ├── param/ # 参数管理
│ │ └── menu_param.c # 参数注册、读写、范围检查
│ └── utils/ # 工具函数
│ └── menu_utils.c # 调试打印、断言、系统滴答
└── examples/ # 示例代码
└── menu_example.c # 菜单组件使用示例
3. 核心功能说明
3.1 菜单导航
- 支持多级菜单导航(上下键切换,确认键进入,返回键退出)
- 环形导航(到达边界自动循环)
- 菜单栈管理,支持深度导航
3.2 参数管理
- 支持多种参数类型(int8/uint8/int16/uint16/int32/uint32/float)
- 自动范围检查和边界处理
- 参数与菜单节点绑定,支持菜单直接调整参数
- 默认值恢复功能
3.3 多语言支持
- 支持多种语言切换
- 字符串ID映射机制
- 自动回退到默认语言
3.4 Modbus映射
- 参数与Modbus寄存器双向映射
- 支持多种Modbus寄存器类型(线圈、离散输入、保持寄存器、输入寄存器)
- 灵活的读写权限控制
- 支持多种字节序(小端、大端、Modbus标准)
- 自动类型转换和边界检查
4. 快速开始
4.1 配置组件
在menu_config.h中根据项目需求配置功能开关和资源大小:
// 核心配置
#define MENU_CONFIG_MAX_NODES 32 // 最大菜单节点数
#define MENU_CONFIG_STACK_DEPTH 8 // 菜单栈深度
#define MENU_CONFIG_EVENT_QUEUE_LEN 16 // 事件队列长度
// 功能扩展配置
#define MENU_CONFIG_ENABLE_PARAM 1 // 启用参数管理功能
#define MENU_CONFIG_ENABLE_LANG 1 // 启用多语言功能
#define MENU_CONFIG_ENABLE_MODBUS_MAP 1 // 启用Modbus映射功能
// Modbus映射配置
#define MENU_CONFIG_MAX_MODBUS_MAPS 16 // 最大Modbus映射数量
#define MENU_CONFIG_MODBUS_BYTE_ORDER 2 // 默认Modbus字节序
4.2 适配硬件端口
在port/menu_port.c中实现硬件相关接口:
// 禁用/启用全局中断
void menu_port_irq_disable(void) {
// 实现禁用中断的逻辑
}
void menu_port_irq_enable(void) {
// 实现启用中断的逻辑
}
// 获取系统滴答时间(ms)
uint32_t menu_port_get_tick(void) {
// 实现获取系统时间的逻辑
return HAL_GetTick(); // 示例:STM32 HAL库
}
// 调试打印接口
void menu_port_printf(const char* fmt, va_list args) {
// 实现打印逻辑,如通过UART输出
vprintf(fmt, args);
}
4.3 基本使用示例
#include "menu.h"
#include "menu_port.h"
// 菜单回调函数
static MenuErrCode menu_cb_enter_param(MenuNodeId node_id) {
MENU_DEBUG("Enter param menu: %d", node_id);
return MENU_OK;
}
int main(void) {
// 1. 初始化硬件(UART、LCD、SysTick等)
hal_init();
// 2. 初始化菜单组件
menu_init();
// 3. 注册菜单节点
menu_register_node(0, 1, "主菜单", NULL, NULL); // 根节点
menu_register_node(1, 2, "参数设置", menu_cb_enter_param, NULL); // 子节点
menu_register_node(1, 3, "系统信息", NULL, NULL); // 子节点
menu_register_node(2, 4, "温度设置", NULL, NULL); // 孙节点
// 4. 注册参数(可选)
#if MENU_CONFIG_ENABLE_PARAM
menu_param_register(4, 1, MENU_PARAM_TYPE_FLOAT, 0.0f, 100.0f, 25.0f, 1.0f);
#endif
// 5. 注册Modbus映射(可选)
#if MENU_CONFIG_ENABLE_MODBUS_MAP
menu_modbus_map_register(1, MODBUS_REG_TYPE_HOLDING_REG, 40001, 2, MODBUS_PERM_READ_WRITE, 2);
#endif
// 6. 主循环
while (1) {
// 扫描硬件按键
menu_port_key_scan();
// 处理菜单事件和刷新显示
menu_main_loop();
// 其他业务逻辑
// ...
}
}
5. Modbus映射功能详解
5.1 核心概念
Modbus映射功能实现了菜单参数与Modbus寄存器的双向数据转换,支持:
- 参数到寄存器:将菜单参数值转换为Modbus寄存器数据
- 寄存器到参数:将Modbus寄存器数据转换为菜单参数值
- 自动类型转换:支持不同数据类型之间的自动转换
- 字节序适配:支持多种字节序,兼容不同Modbus设备
5.2 寄存器类型支持
| 寄存器类型 | 地址范围 | 读写特性 | 支持的参数类型 |
|---|---|---|---|
| 线圈 | 00001-09999 | 读写 | INT8、UINT8 |
| 离散输入 | 10001-19999 | 只读 | INT8、UINT8 |
| 输入寄存器 | 30001-39999 | 只读 | 所有类型 |
| 保持寄存器 | 40001-49999 | 读写 | 所有类型 |
5.3 字节序支持
| 字节序类型 | 值 | 描述 |
|---|---|---|
| 小端 | 0 | 低字节在前,高字节在后(x86架构默认) |
| 大端 | 1 | 高字节在前,低字节在后 |
| Modbus标准 | 2 | 字小端,字节大端(Modbus协议默认) |
5.4 Modbus映射使用示例
// 1. 注册参数(必须在映射之前完成)
menu_param_register(menu_node_id, param_id, MENU_PARAM_TYPE_FLOAT, 0.0f, 100.0f, 25.0f, 1.0f);
// 2. 注册Modbus映射
menu_modbus_map_register(
param_id, // 参数ID
MODBUS_REG_TYPE_HOLDING_REG, // 寄存器类型
40001, // 起始地址
2, // 寄存器数量(浮点型占2个16位寄存器)
MODBUS_PERM_READ_WRITE, // 读写权限
2 // 字节序(Modbus标准)
);
// 3. 参数到寄存器转换
uint8_t reg_buf[4] = {0};
uint8_t buf_len = sizeof(reg_buf);
menu_modbus_map_param_to_reg(param_id, reg_buf, &buf_len);
// 4. 寄存器到参数转换
const uint8_t reg_data[4] = {0x00, 0x00, 0x4B, 0x40}; // 25.0f的二进制表示
menu_modbus_map_reg_to_param(param_id, reg_data, sizeof(reg_data));
6. 配置说明
6.1 核心配置项
| 配置项 | 说明 | 默认值 |
|---|---|---|
| MENU_CONFIG_MAX_NODES | 最大菜单节点数 | 32 |
| MENU_CONFIG_STACK_DEPTH | 菜单栈深度 | 8 |
| MENU_CONFIG_EVENT_QUEUE_LEN | 事件队列长度 | 16 |
| MENU_CONFIG_ENABLE_ASSERT | 是否启用断言 | 1 |
| MENU_CONFIG_ENABLE_DEBUG | 是否启用调试打印 | 1 |
6.2 功能扩展配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
| MENU_CONFIG_ENABLE_PARAM | 是否启用参数管理 | 1 |
| MENU_CONFIG_ENABLE_LANG | 是否启用多语言支持 | 1 |
| MENU_CONFIG_ENABLE_MODBUS_MAP | 是否启用Modbus映射 | 1 |
6.3 Modbus映射配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
| MENU_CONFIG_MAX_MODBUS_MAPS | 最大Modbus映射数量 | 16 |
| MENU_CONFIG_MODBUS_MAX_ADDR | Modbus寄存器地址最大值 | 0xFFFF |
| MENU_CONFIG_MODBUS_BYTE_ORDER | 默认Modbus字节序 | 2(Modbus标准) |
| MENU_CONFIG_MODBUS_PERMISSION | 是否启用权限校验 | 1 |
7. 移植指南
7.1 硬件端口层适配
用户只需适配port/menu_port.c中的以下接口:
- 中断管理:
menu_port_irq_disable()、menu_port_irq_enable() - 系统时间:
menu_port_get_tick() - 调试打印:
menu_port_printf() - 错误处理:
menu_port_error_handler() - 按键扫描:
menu_port_key_scan()(可选,用户也可以在外部实现) - 显示接口:
menu_port_display()(可选)
7.2 编译配置
- 将
menu/api目录添加到Include路径 - 根据项目需求配置
menu_config.h - 编译时包含所有必要的源文件
8. 性能与资源占用
8.1 内存占用
- Flash占用:约5-15KB(取决于启用的功能)
- RAM占用:约1-3KB(取决于配置的节点数、参数数和Modbus映射数)
8.2 执行效率
- 事件处理:单次事件处理时间 < 10μs
- 菜单刷新:单次刷新时间 < 5μs
- 参数转换:单次转换时间 < 2μs
- Modbus映射:单次映射转换时间 < 5μs
9. 工业级设计考量
- 无动态内存分配:完全使用静态数组,避免内存碎片
- 事件驱动设计:硬件与软件解耦,提高系统响应性
- 完善的错误处理:每个函数都有明确的错误码返回
- 边界检查:所有数组访问都有边界检查,防止越界
- 断言机制:关键函数入口有断言检查,便于调试
- 可配置裁剪:通过宏开关可以裁剪不需要的功能
- 模块化设计:各功能模块独立,便于维护和扩展
10. 应用场景
- 工业控制器
- 智能家居设备
- 仪器仪表
- 医疗设备
- 嵌入式人机界面
- Modbus从站设备
11. 许可证
本项目采用MIT许可证,可自由用于商业和非商业项目。
12. 联系方式
如有问题或建议,欢迎提交Issue或Pull Request。
版本信息:v1.0.0 最后更新:2025-12-18 适用平台:所有支持C语言的嵌入式系统