Files
menu/examples/menu_example.c
2025-12-18 22:24:25 +08:00

342 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file menu_example.c
* @brief 菜单组件完整使用示例包含Modbus映射功能演示
* @note 工业级嵌入式菜单组件 - 使用示例
*/
#include "menu.h"
#include "menu_port.h"
#include "menu_def.h"
/************************** 示例配置 **************************/
// 菜单节点ID定义
#define MENU_ROOT_ID 1 // 根节点
#define MENU_PARAM_ID 2 // 参数设置节点
#define MENU_MODBUS_ID 3 // Modbus设置节点
#define MENU_TEMP_ID 4 // 温度参数节点
#define MENU_HUMID_ID 5 // 湿度参数节点
#define MENU_PRESS_ID 6 // 压力参数节点
// 参数ID定义
#define PARAM_TEMP_ID 1 // 温度参数ID
#define PARAM_HUMID_ID 2 // 湿度参数ID
#define PARAM_PRESS_ID 3 // 压力参数ID
// Modbus寄存器地址定义
#define REG_TEMP_ADDR 40001 // 温度寄存器地址
#define REG_HUMID_ADDR 40003 // 湿度寄存器地址
#define REG_PRESS_ADDR 40005 // 压力寄存器地址
/************************** 全局变量 **************************/
// 模拟Modbus寄存器缓冲区
uint8_t g_modbus_reg_buf[256] = {0};
/************************** 菜单回调函数 **************************/
/**
* @brief 进入参数设置菜单回调
* @param node_id 菜单节点ID
* @return 错误码
*/
static MenuErrCode menu_cb_enter_param(MenuNodeId node_id)
{
MENU_DEBUG("Enter param menu: %d", node_id);
return MENU_OK;
}
/**
* @brief 退出参数设置菜单回调
* @param node_id 菜单节点ID
* @return 错误码
*/
static MenuErrCode menu_cb_exit_param(MenuNodeId node_id)
{
MENU_DEBUG("Exit param menu: %d", node_id);
return MENU_OK;
}
/**
* @brief 进入Modbus设置菜单回调
* @param node_id 菜单节点ID
* @return 错误码
*/
static MenuErrCode menu_cb_enter_modbus(MenuNodeId node_id)
{
MENU_DEBUG("Enter Modbus menu: %d", node_id);
return MENU_OK;
}
/**
* @brief 模拟Modbus通信流程
*/
static void modbus_communication_demo(void)
{
#if MENU_CONFIG_ENABLE_MODBUS_MAP
MENU_DEBUG("=== Modbus Communication Demo ===");
// 1. 模拟参数到寄存器的转换(参数修改后更新寄存器)
{
MENU_DEBUG("1. Param to Reg Demo:");
// 设置温度参数为28.5
menu_param_set_value(PARAM_TEMP_ID, 28.5f);
// 将温度参数转换到Modbus寄存器
uint8_t buf_len = 4;
uint8_t reg_buf[4] = {0};
MenuErrCode err = menu_modbus_map_param_to_reg(PARAM_TEMP_ID, reg_buf, &buf_len);
if (err == MENU_OK)
{
MENU_DEBUG(" Temp param (28.5f) to reg: [0x%02X, 0x%02X, 0x%02X, 0x%02X]",
reg_buf[0], reg_buf[1], reg_buf[2], reg_buf[3]);
}
else
{
MENU_DEBUG(" Param to reg failed: %d", err);
}
}
// 2. 模拟寄存器到参数的转换接收到Modbus写入请求后更新参数
{
MENU_DEBUG("2. Reg to Param Demo:");
// 模拟Modbus写入湿度参数65.0%
// 65.0f的二进制表示大端0x42820000对应Modbus标准字节序为0x8242 0x0000
uint8_t reg_buf[4] = {0x82, 0x42, 0x00, 0x00};
// 将Modbus寄存器数据转换为参数值
MenuErrCode err = menu_modbus_map_reg_to_param(PARAM_HUMID_ID, reg_buf, sizeof(reg_buf));
if (err == MENU_OK)
{
// 读取转换后的参数值
float humid_val;
menu_param_get_value(PARAM_HUMID_ID, &humid_val);
MENU_DEBUG(" Reg data [0x82, 0x42, 0x00, 0x00] to humid param: %.1f%%", humid_val);
}
else
{
MENU_DEBUG(" Reg to param failed: %d", err);
}
}
// 3. 模拟Modbus读取请求处理
{
MENU_DEBUG("3. Modbus Read Request Demo:");
// 模拟Modbus主机读取压力参数
uint8_t buf_len = 4;
uint8_t reg_buf[4] = {0};
// 这里应该先调用menu_modbus_map_param_to_reg将参数转换到寄存器缓冲区
MenuErrCode err = menu_modbus_map_param_to_reg(PARAM_PRESS_ID, reg_buf, &buf_len);
if (err == MENU_OK)
{
// 然后返回给Modbus主机
MENU_DEBUG(" Read pressure reg: [0x%02X, 0x%02X, 0x%02X, 0x%02X]",
reg_buf[0], reg_buf[1], reg_buf[2], reg_buf[3]);
}
else
{
MENU_DEBUG(" Read pressure failed: %d", err);
}
}
// 4. 模拟Modbus写入请求处理
{
MENU_DEBUG("4. Modbus Write Request Demo:");
// 模拟Modbus主机写入温度参数30.0°C
// 30.0f的二进制表示大端0x41F00000对应Modbus标准字节序为0xF041 0x0000
uint8_t reg_buf[4] = {0xF0, 0x41, 0x00, 0x00};
// 调用menu_modbus_map_reg_to_param将寄存器数据转换为参数值
MenuErrCode err = menu_modbus_map_reg_to_param(PARAM_TEMP_ID, reg_buf, sizeof(reg_buf));
if (err == MENU_OK)
{
// 读取转换后的参数值
float temp_val;
menu_param_get_value(PARAM_TEMP_ID, &temp_val);
MENU_DEBUG(" Write temp reg: [0xF0, 0x41, 0x00, 0x00] -> temp param: %.1f°C", temp_val);
}
else
{
MENU_DEBUG(" Write temp failed: %d", err);
}
}
MENU_DEBUG("=== Modbus Communication Demo End ===");
#endif
}
/************************** 主函数 **************************/
int main(void)
{
MENU_DEBUG("=== Menu Component Example ===");
/************************** 1. 初始化硬件 **************************/
MENU_DEBUG("1. Initialize hardware...");
// 这里应该初始化硬件如UART、LCD、SysTick等
// hal_init();
/************************** 2. 初始化菜单组件 **************************/
MENU_DEBUG("2. Initialize menu component...");
MenuErrCode err = menu_init();
if (err != MENU_OK)
{
MENU_DEBUG(" Menu init failed: %d", err);
return -1;
}
/************************** 3. 注册菜单节点 **************************/
MENU_DEBUG("3. Register menu nodes...");
// 注册根节点
err = menu_register_node(0, MENU_ROOT_ID, "主菜单", NULL, NULL);
if (err != MENU_OK)
{
MENU_DEBUG(" Register root node failed: %d", err);
return -1;
}
// 注册参数设置节点
err = menu_register_node(MENU_ROOT_ID, MENU_PARAM_ID, "参数设置", menu_cb_enter_param, menu_cb_exit_param);
if (err != MENU_OK)
{
MENU_DEBUG(" Register param node failed: %d", err);
return -1;
}
// 注册Modbus设置节点
err = menu_register_node(MENU_ROOT_ID, MENU_MODBUS_ID, "Modbus设置", menu_cb_enter_modbus, NULL);
if (err != MENU_OK)
{
MENU_DEBUG(" Register modbus node failed: %d", err);
return -1;
}
// 注册温度参数节点
err = menu_register_node(MENU_PARAM_ID, MENU_TEMP_ID, "温度设置", NULL, NULL);
if (err != MENU_OK)
{
MENU_DEBUG(" Register temp node failed: %d", err);
return -1;
}
// 注册湿度参数节点
err = menu_register_node(MENU_PARAM_ID, MENU_HUMID_ID, "湿度设置", NULL, NULL);
if (err != MENU_OK)
{
MENU_DEBUG(" Register humid node failed: %d", err);
return -1;
}
// 注册压力参数节点
err = menu_register_node(MENU_PARAM_ID, MENU_PRESS_ID, "压力设置", NULL, NULL);
if (err != MENU_OK)
{
MENU_DEBUG(" Register press node failed: %d", err);
return -1;
}
/************************** 4. 注册参数 **************************/
MENU_DEBUG("4. Register parameters...");
#if MENU_CONFIG_ENABLE_PARAM
// 注册温度参数(范围:-40.0°C ~ 120.0°C默认25.0°C精度0.1°C
err = menu_param_register(MENU_TEMP_ID, PARAM_TEMP_ID, MENU_PARAM_TYPE_FLOAT,
-40.0f, 120.0f, 25.0f, 0.1f);
if (err != MENU_OK)
{
MENU_DEBUG(" Register temp param failed: %d", err);
return -1;
}
// 注册湿度参数范围0.0% ~ 100.0%默认50.0%精度0.1%
err = menu_param_register(MENU_HUMID_ID, PARAM_HUMID_ID, MENU_PARAM_TYPE_FLOAT,
0.0f, 100.0f, 50.0f, 0.1f);
if (err != MENU_OK)
{
MENU_DEBUG(" Register humid param failed: %d", err);
return -1;
}
// 注册压力参数范围0.0kPa ~ 1000.0kPa默认101.3kPa精度0.1kPa
err = menu_param_register(MENU_PRESS_ID, PARAM_PRESS_ID, MENU_PARAM_TYPE_FLOAT,
0.0f, 1000.0f, 101.3f, 0.1f);
if (err != MENU_OK)
{
MENU_DEBUG(" Register press param failed: %d", err);
return -1;
}
#endif
/************************** 5. 注册Modbus映射 **************************/
MENU_DEBUG("5. Register Modbus mappings...");
// 注册温度参数到Modbus寄存器映射
err = menu_modbus_map_register(
PARAM_TEMP_ID, // 参数ID
MODBUS_REG_TYPE_HOLDING_REG, // 寄存器类型
REG_TEMP_ADDR, // 起始地址
2, // 寄存器数量浮点型占2个16位寄存器
MODBUS_PERM_READ_WRITE, // 读写权限
2 // 字节序Modbus标准
);
if (err != MENU_OK)
{
MENU_DEBUG(" Register temp modbus map failed: %d", err);
return -1;
}
// 注册湿度参数到Modbus寄存器映射
err = menu_modbus_map_register(
PARAM_HUMID_ID, // 参数ID
MODBUS_REG_TYPE_HOLDING_REG, // 寄存器类型
REG_HUMID_ADDR, // 起始地址
2, // 寄存器数量
MODBUS_PERM_READ_WRITE, // 读写权限
2 // 字节序Modbus标准
);
if (err != MENU_OK)
{
MENU_DEBUG(" Register humid modbus map failed: %d", err);
return -1;
}
// 注册压力参数到Modbus寄存器映射
err = menu_modbus_map_register(
PARAM_PRESS_ID, // 参数ID
MODBUS_REG_TYPE_HOLDING_REG, // 寄存器类型
REG_PRESS_ADDR, // 起始地址
2, // 寄存器数量
MODBUS_PERM_READ_WRITE, // 读写权限
2 // 字节序Modbus标准
);
if (err != MENU_OK)
{
MENU_DEBUG(" Register press modbus map failed: %d", err);
return -1;
}
/************************** 6. 运行Modbus通信演示 **************************/
MENU_DEBUG("6. Run Modbus communication demo...");
modbus_communication_demo();
/************************** 7. 进入主循环 **************************/
MENU_DEBUG("7. Enter main loop...");
while (1)
{
// 处理菜单事件和刷新显示
menu_main_loop();
// 其他业务逻辑
// ...
// 模拟延时
menu_port_delay_ms(10);
}
return 0;
}