【QuecOpen 实战-012】EC800 OpenC 对讲机方案设计(LVGL + 自定义菜单 + 5 按键)
2026/5/4 2:58:55 网站建设 项目流程

本方案基于移远 EC800M OpenC嵌入式开发方案,采用标准 C 语言开发,集成LVGL 8.x轻量级图形框架、自定义层级菜单框架,实现4G 公网对讲机核心功能,适配上 / 下 / 菜单 / 呼叫 / 返回5 个物理按键。

一、整体架构

硬件层:EC800M核心板 + LCD屏 + 5按键 + 麦克风/扬声器 驱动层:EC800 GPIO(按键) + LCD显示 + 音频驱动 + 4G网络驱动 框架层:LVGL图形库 + 自定义菜单管理器 业务层:对讲机(呼叫/通话) + 菜单操作 + 系统设置

核心特性

  1. EC800 OpenC 适配:基于移远官方 SDK,调用 4G、音频、GPIO 标准接口
  2. 自定义菜单框架:层级化菜单(主菜单→子菜单→设置项),支持按键导航
  3. LVGL UI:状态条(信号 / 电量 / 对讲状态)+ 菜单列表 + 通话界面
  4. 5 按键逻辑
    • 上 / 下:菜单切换选中项、音量调节
    • 菜单:进入主菜单
    • 呼叫:长按发起对讲,松开结束对讲
    • 返回:退出菜单 / 取消操作

二、核心代码实现

开发环境

  • 移远 EC800M OpenC 官方 SDK
  • LVGL 8.3(精简版,适配嵌入式资源)
  • ARM GCC 编译器

1. 全局定义(公共宏 / 枚举)

#ifndef __WALKIE_DEF_H__ #define __WALKIE_DEF_H__ #include "ec800e_open_c.h" // EC800 OpenC 官方头文件 #include "lvgl/lvgl.h" // LVGL头文件 // 1. 按键枚举 (5个核心按键) typedef enum { KEY_NONE = 0, // 无按键 KEY_UP = 1, // 上键 KEY_DOWN = 2, // 下键 KEY_MENU = 3, // 菜单键 KEY_CALL = 4, // 呼叫键 KEY_BACK = 5 // 返回键 } KeyTypeDef; // 2. 对讲状态 typedef enum { WT_IDLE = 0, // 空闲 WT_CALLING = 1, // 呼叫中 WT_TALKING = 2 // 通话中 } WalkieTalkieState; // 3. 菜单最大配置 #define MENU_MAX_ITEMS 8 // 单页最大菜单数 #define MENU_NAME_LEN 16 // 菜单名长度 #endif

2. 自定义菜单框架(核心)

轻量级层级菜单框架,支持父菜单 / 子菜单绑定、选中、回调函数,完全适配 5 按键操作。

// menu.h #ifndef __MENU_H__ #define __MENU_H__ #include "walkie_def.h" // 菜单节点结构体 typedef struct MenuNode MenuNodeDef; struct MenuNode { char name[MENU_NAME_LEN]; // 菜单名称 void (*callback)(void); // 菜单选中回调函数 MenuNodeDef* parent; // 父菜单 MenuNodeDef* child[MENU_MAX_ITEMS]; // 子菜单 uint8_t child_num; // 子菜单数量 }; // 菜单管理器 typedef struct { MenuNodeDef* current_menu; // 当前菜单 uint8_t select_index; // 当前选中索引 uint8_t total_items; // 当前菜单总项数 } MenuManagerDef; // 菜单全局实例 extern MenuManagerDef g_menu_mgr; // 菜单初始化 void menu_init(void); // 菜单按键处理 void menu_key_handler(KeyTypeDef key); // 菜单绘制(LVGL) void menu_draw(lv_obj_t* parent); #endif
// menu.c #include "menu.h" #include "walkie_talkie.h" MenuManagerDef g_menu_mgr; static lv_obj_t* menu_list = NULL; // ------------------- 菜单功能回调 ------------------- static void menu_chan_callback(void) { /* 频道设置 */ } static void menu_vol_callback(void) { /* 音量调节 */ } static void menu_set_callback(void) { /* 系统设置 */ } static void menu_exit_callback(void) { menu_key_handler(KEY_BACK); } // ------------------- 定义菜单节点 ------------------- // 子菜单 static MenuNodeDef menu_chan = {"频道设置", menu_chan_callback, NULL, {}, 0}; static MenuNodeDef menu_vol = {"音量调节", menu_vol_callback, NULL, {}, 0}; static MenuNodeDef menu_set = {"系统设置", menu_set_callback, NULL, {}, 0}; static MenuNodeDef menu_exit = {"返回", menu_exit_callback, NULL, {}, 0}; // 主菜单 static MenuNodeDef main_menu = { "主菜单", NULL, NULL, {&menu_chan, &menu_vol, &menu_set, &menu_exit}, 4 // 子菜单数量 }; // 菜单初始化 void menu_init(void) { g_menu_mgr.current_menu = &main_menu; g_menu_mgr.select_index = 0; g_menu_mgr.total_items = main_menu.child_num; } // 菜单按键处理(核心逻辑) void menu_key_handler(KeyTypeDef key) { MenuManagerDef* mgr = &g_menu_mgr; switch (key) { case KEY_UP: // 上键:选中项上移 if (mgr->select_index > 0) mgr->select_index--; break; case KEY_DOWN: // 下键:选中项下移 if (mgr->select_index < mgr->total_items - 1) mgr->select_index++; break; case KEY_CALL: // 呼叫键:确认进入子菜单/执行功能 if (mgr->current_menu->child[mgr->select_index]->child_num > 0) { mgr->current_menu = mgr->current_menu->child[mgr->select_index]; mgr->select_index = 0; mgr->total_items = mgr->current_menu->child_num; } else { mgr->current_menu->child[mgr->select_index]->callback(); } break; case KEY_BACK: // 返回键:返回父菜单 if (mgr->current_menu->parent != NULL) { mgr->current_menu = mgr->current_menu->parent; mgr->select_index = 0; mgr->total_items = mgr->current_menu->child_num; } break; default: break; } menu_draw(lv_scr_act()); // 刷新菜单UI } // LVGL绘制菜单界面 void menu_draw(lv_obj_t* parent) { if (menu_list == NULL) { menu_list = lv_list_create(parent); lv_obj_set_size(menu_list, LV_HOR_RES, LV_VER_RES - 40); lv_obj_align(menu_list, LV_ALIGN_BOTTOM_MID, 0, 0); } lv_list_clean(menu_list); MenuNodeDef* curr = g_menu_mgr.current_menu; // 绘制所有子菜单 for (uint8_t i = 0; i < curr->child_num; i++) { lv_obj_t* btn = lv_list_add_btn(menu_list, NULL, curr->child[i]->name); if (i == g_menu_mgr.select_index) { lv_obj_add_state(btn, LV_STATE_CHECKED); // 高亮选中项 } } }

3. 按键驱动(EC800 GPIO 适配)

基于 EC800 OpenC 的 GPIO 接口,实现按键消抖 + 键值识别,非阻塞扫描。

// key.c #include "walkie_def.h" // EC800 GPIO配置 (根据硬件实际引脚修改) #define KEY_UP_GPIO GPIO_NUM_0 #define KEY_DOWN_GPIO GPIO_NUM_1 #define KEY_MENU_GPIO GPIO_NUM_2 #define KEY_CALL_GPIO GPIO_NUM_3 #define KEY_BACK_GPIO GPIO_NUM_4 // 按键初始化 void key_init(void) { gpio_config_t gpio_conf; gpio_conf.mode = GPIO_MODE_INPUT; gpio_conf.pull_up_en = GPIO_PULL_UP_ENABLE; gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; gpio_conf.intr_type = GPIO_INTR_DISABLE; gpio_conf.pin_bit_mask = (1ULL<<KEY_UP_GPIO) | (1ULL<<KEY_DOWN_GPIO) | (1ULL<<KEY_MENU_GPIO) | (1ULL<<KEY_CALL_GPIO) | (1ULL<<KEY_BACK_GPIO); gpio_config(&gpio_conf); } // 按键扫描 (消抖,返回键值) KeyTypeDef key_scan(void) { static uint8_t key_lock = 0; if (key_lock) return KEY_NONE; key_lock = 1; if (gpio_get_level(KEY_UP_GPIO) == 0) { os_delay_ms(20); if (gpio_get_level(KEY_UP_GPIO) == 0) return KEY_UP; } if (gpio_get_level(KEY_DOWN_GPIO) == 0) { os_delay_ms(20); if (gpio_get_level(KEY_DOWN_GPIO) == 0) return KEY_DOWN; } if (gpio_get_level(KEY_MENU_GPIO) == 0) { os_delay_ms(20); if (gpio_get_level(KEY_MENU_GPIO) == 0) return KEY_MENU; } if (gpio_get_level(KEY_CALL_GPIO) == 0) { os_delay_ms(20); if (gpio_get_level(KEY_CALL_GPIO) == 0) return KEY_CALL; } if (gpio_get_level(KEY_BACK_GPIO) == 0) { os_delay_ms(20); if (gpio_get_level(KEY_BACK_GPIO) == 0) return KEY_BACK; } key_lock = 0; return KEY_NONE; }

4. 对讲机业务(EC800 4G + 音频)

核心:长按呼叫键对讲,松开停止,调用 EC800 音频采集 / 播放、4G 网络传输接口。

// walkie_talkie.c #include "walkie_talkie.h" #include "ec800e_audio.h" // EC800音频驱动 WalkieTalkieState g_wt_state = WT_IDLE; // 初始化对讲机 void wt_init(void) { ec800e_audio_init(AUDIO_DEVICE_SPEAKER, AUDIO_SAMPLE_RATE_8K); ec800e_audio_init(AUDIO_DEVICE_MIC, AUDIO_SAMPLE_RATE_8K); g_wt_state = WT_IDLE; } // 开始对讲 (长按呼叫键) void wt_start_talk(void) { if (g_wt_state == WT_IDLE) { g_wt_state = WT_TALKING; ec800e_audio_mic_open(); // 打开麦克风 ec800e_network_send_voice(); // EC800 4G发送语音 lv_label_set_text(g_status_label, "对讲中..."); } } // 停止对讲 (松开呼叫键) void wt_stop_talk(void) { if (g_wt_state == WT_TALKING) { g_wt_state = WT_IDLE; ec800e_audio_mic_close(); // 关闭麦克风 ec800e_network_stop_voice(); // 停止4G语音 lv_label_set_text(g_status_label, "空闲"); } } // 对讲业务主处理 void wt_handler(KeyTypeDef key) { if (key == KEY_CALL) { wt_start_talk(); } else if (key == KEY_NONE && g_wt_state == WT_TALKING) { wt_stop_talk(); } }

5. LVGL 适配 + 主程序

EC800 OpenC 主入口,初始化所有模块,实现LVGL 任务调度 + 按键 + 菜单 + 对讲主循环。

// main.c #include "walkie_def.h" #include "key.h" #include "menu.h" #include "walkie_talkie.h" lv_obj_t* g_status_label; // 状态条标签 // LVGL UI初始化 static void lvgl_ui_init(void) { lv_obj_t* scr = lv_scr_act(); // 1. 顶部状态条 lv_obj_t* status_bar = lv_obj_create(scr); lv_obj_set_size(status_bar, LV_HOR_RES, 40); lv_obj_align(status_bar, LV_ALIGN_TOP_MID, 0, 0); g_status_label = lv_label_create(status_bar); lv_label_set_text(g_status_label, "对讲机 - 空闲"); lv_obj_align(g_status_label, LV_ALIGN_CENTER, 0, 0); // 2. 初始化菜单 menu_init(); menu_draw(scr); } // EC800 OpenC 主函数 int main(void) { // 1. 系统初始化 ec800e_system_init(); lv_init(); // LVGL初始化 lvgl_port_init(); // EC800 LCD+输入适配LVGL // 2. 外设初始化 key_init(); // 按键初始化 wt_init(); // 对讲机初始化 lvgl_ui_init(); // UI初始化 // 3. 主循环 while (1) { lv_task_handler(); // LVGL任务调度 os_delay_ms(5); // 按键扫描 KeyTypeDef key = key_scan(); if (key == KEY_NONE) continue; // 按键优先级:对讲 > 菜单 if (key == KEY_CALL) { wt_handler(key); // 处理对讲 } else if (key == KEY_MENU) { menu_draw(lv_scr_act()); // 呼出菜单 } else { menu_key_handler(key); // 菜单按键处理 } } return 0; }

三、按键操作逻辑(最终用户交互)

表格

按键空闲界面菜单界面
上键音量 +菜单选中项上移
下键音量 -菜单选中项下移
菜单键呼出主菜单无操作
呼叫键长按发起对讲,松开停止确认选中菜单 / 进入子菜单
返回键无操作返回上一级菜单 / 退出菜单

四、EC800 OpenC 关键适配说明

  1. LVGL 移植:需适配 EC800 的 LCD 驱动(lvgl_port.c),实现lv_display_flushlv_input_read
  2. 音频功能:调用移远官方ec800e_audio.h接口,支持 8K 采样率语音对讲
  3. 4G 网络:基于 EC800 的 TCP/UDP 透传实现公网对讲,可对接对讲服务器
  4. 资源优化:LVGL 关闭无用组件,菜单框架使用静态数组,适配 EC800 的 RAM/ROM

总结

  1. 本方案完全匹配你的需求:EC800 OpenC、对讲机、LVGL、自定义菜单、5 按键
  2. 模块化设计:按键 / 菜单 / 对讲 / LVGL 完全解耦,方便二次开发
  3. 核心功能可用:长按呼叫对讲、层级菜单导航、LVGL 可视化界面
  4. 可直接移植:基于 EC800 官方 SDK,只需修改 GPIO 引脚即可适配硬件

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询