# AI对话 + 电子吧唧 双模式适配说明 > 更新日期:2026-02-27 > 硬件平台:movecall-moji-esp32s3 (ESP32-S3-N16R8) > ESP-IDF版本:5.4.2 > LVGL版本:8.3.11 --- ## 一、项目现状 ### 1.1 主项目 (Baji_Rtc_Toy) 基于 AI小智 开源项目改造,当前已集成功能: - 火山引擎 RTC 语音对话(WiFi 连接) - BLE 配网(Bluedroid,Service 0xABF0) - 音频编解码(ES8311 + Opus) - 唤醒词检测(esp-sr AFE) - **LVGL 8.3.11 LCD 显示**(Phase 1 已完成,开机显示 ScreenHome) - ST77916 QSPI 360×360 LCD + CST816S 触摸(已初始化) ### 1.2 dzbj 子项目 (电子吧唧) 独立的 ESP32-S3 LVGL 项目,位于 `/dzbj/` 目录,功能: - 360×360 ST77916 QSPI LCD + CST816S 触摸 - LVGL 8.3.11 三屏界面(ScreenHome/ScreenImg/ScreenSet) - BLE GATT 图片传输服务(Service 0x0B00) - GIF 播放、JPEG 解码、SPIFFS 图片管理 - 低功耗休眠/唤醒管理(10s 超时熄屏) - PWM 背光控制 ### 1.3 实施进度 | 阶段 | 状态 | 说明 | |------|------|------| | Phase 1: 点亮屏幕 | **已完成** | LCD + LVGL + ScreenHome 显示 | | Phase 2+4: 完整模式 + 切换 | **实施中** | 移植 dzbj 全模块 + 双模式切换 | | Phase 3: AI 聊天 UI | 待定 | 基于 LVGL 的 emoji + 聊天气泡 | --- ## 二、双模式架构设计 ### 2.1 架构概览 ``` ┌─────────────────────────────────────────────────┐ │ LVGL 8.3.11 + LCD │ │ (常驻,两个模式共享显示硬件) │ ├────────────────────┬────────────────────────────┤ │ AI 对话模式 │ 电子吧唧模式 │ │ (mode=0, 默认) │ (mode=1) │ │ │ │ │ WiFi + RTC 协议 │ BLE GATT Server │ │ ScreenHome (仅显示) │ ScreenHome/Img/Set │ │ 音频编解码 + 唤醒词 │ BLE 图片传输 (0x0B00) │ │ PowerSaveTimer │ sleep_mgr (10s熄屏) │ │ IMU 传感器 │ battery 电池监测 │ │ 电量检测 (板级) │ SPIFFS 图片管理 │ ├────────────────────┴────────────────────────────┤ │ BOOT 双击 切换(写NVS + 重启) │ └─────────────────────────────────────────────────┘ ``` ### 2.2 模式定义 **AI 对话模式** (device_mode=0, 默认): - 网络:WiFi 连接 - 协议:火山引擎 RTC 实时对话 - 音频:唤醒词检测 + Opus 编解码 + I2S 输出 - 显示:ScreenHome(仅显示,无触摸交互) - BLE:**关闭**(仅配网时启动) **电子吧唧模式** (device_mode=1): - 网络:**WiFi 关闭** - BLE:GATT Server(图片传输服务 0x0B00) - 显示:ScreenHome → ScreenImg(图片浏览)→ ScreenSet(设置) - 功能:JPEG 解码、GIF 播放、SPIFFS 图片管理、低功耗、电池监测 ### 2.3 模式切换方案 **方案:重启切换(NVS 标志)** ``` BOOT 双击 → 读取 NVS device_mode → 切换 0↔1 → 写入 NVS → esp_restart() ``` 切换时间约 3-4 秒(重启时间),NVS 擦写寿命 10-100万次,无限次切换。 **选择重启而非热切换的原因**: 1. WiFi + BLE Bluedroid 同时运行内部 SRAM 不足(约需 280KB,可用 ~334KB) 2. 热切换需处理大量资源释放/重建(协议、音频管道、FreeRTOS 任务),复杂度极高 3. Application 单例内部状态(event_group, opus 编解码器, background_task)难以干净重置 4. 重启方式简单可靠,避免内存泄漏和碎片化风险 --- ## 三、内存预算分析 ### 3.1 硬件规格 - **内部 SRAM**:~334KB DIRAM(可用) - **PSRAM**:8MB OCT-SPI 80MHz - **Flash**:16MB ### 3.2 各模式内存占用 | 场景 | 估算占用 | 剩余 | 可行性 | |------|----------|------|--------| | AI 对话模式(WiFi+RTC+音频+LVGL) | ~212-237KB | ~97-122KB | **可行**(偏紧) | | 电子吧唧模式(BLE+LVGL+SPIFFS) | ~190KB | ~144KB | **可行**(充裕) | | 两模式同时运行 | ~274-345KB | 不足 | **不可行** | ### 3.3 关键验证数据 - Phase 1 测试:WiFi + BLE 同时运行导致 `assert failed: vQueueDelete queue.c:2355`(FreeRTOS 信号量分配失败) - BLE 配网成功后 `xTaskCreate` 分配 2048 栈失败(已改用 `esp_timer` 解决) - 确认两模式必须互斥运行 --- ## 四、启动流程 ### 4.1 双模式启动序列 ``` 开机 │ ├── 板级构造函数(通用) │ ├── PowerSaveTimer 初始化 │ ├── InitializeButtons()(主项目 Button 类,双击注册在此) │ ├── InitializeCodecI2c() │ ├── dzbj_display_init() ← LCD + LVGL 始终初始化 │ │ │ ├── if device_mode == BADGE (吧唧模式) │ │ └── InitializeBadgeMode() │ │ ├── fatfs_init() // SPIFFS 文件系统 │ │ ├── init_spiffs_image_list() // 扫描图片 │ │ ├── dzbj_button_init() // ISR按键 │ │ ├── battery_init() // 电池检测 │ │ ├── dzbj_ble_init() // BLE 图传 │ │ └── sleep_mgr_init() // 低功耗管理 │ │ │ └── else (AI模式, 默认) │ ├── InitializeIot() │ ├── InitializeBatteryMonitor() │ ├── InitializeImuSensor() │ └── PowerSaveTimer 启用 │ ├── Application::Start() │ ├── if device_mode == BADGE │ │ └── SetDeviceState(Idle); return; // 不启动WiFi/协议/音频 │ │ │ └── else (AI模式) │ ├── Opus 编解码器初始化 │ ├── 音频管道启动 │ ├── board.StartNetwork() // WiFi 连接 │ ├── RTC 协议初始化 │ └── MainLoop + AudioLoop 启动 ``` ### 4.2 BOOT 按键行为 | 事件 | AI模式 | 吧唧模式 | 配网模式 | |------|--------|---------|---------| | 单击 | Idle↔Listening 切换 | 待定(返回 ScreenHome?) | 显示 MAC 地址 | | 双击 | **切换到吧唧模式** | **切换到AI模式** | 无响应 | | 长按5s | 无响应 | 无响应 | 进入生产测试 | --- ## 五、模块移植清单 ### 5.1 从 dzbj 移植的模块 | 模块 | 源文件 | 目标文件 | 适配要点 | |------|--------|---------|---------| | fatfs | `dzbj/main/fatfs/` | `main/dzbj/fatfs.c/h` | `gpio.h` → `dzbj_gpio.h` | | pages | `dzbj/main/pages/pages.c` | `main/dzbj/pages.c` | 移除 `wifi.h`,PWM 去重 | | BLE图传 | `dzbj/main/ble/ble.c` | `main/dzbj/dzbj_ble.c/h` | **新增 deinit 函数** | | sleep_mgr | `dzbj/main/sleep_mgr/` | `main/dzbj/sleep_mgr.c` | 按键回调适配 | | button | `dzbj/main/button/` | `main/dzbj/dzbj_button.c/h` | ISR+队列+去抖 | | battery | `dzbj/main/battery/` | `main/dzbj/battery.c/h` | ADC 校准 + UI 更新 | ### 5.2 新建模块 | 模块 | 文件 | 功能 | |------|------|------| | device_mode | `main/dzbj/device_mode.c/h` | NVS 模式读写 + 重启切换 | ### 5.3 修改的现有文件 | 文件 | 修改内容 | |------|---------| | `movecall_moji_esp32s3.cc` | 模式分支 + InitializeBadgeMode() + BOOT 双击回调 | | `application.cc` | Start() 模式分支(吧唧模式早返回) | | `main/CMakeLists.txt` | 添加新源文件 | | `main/idf_component.yml` | 添加 esp_jpeg 依赖 | | `main/sleep_mgr/include/sleep_mgr.h` | stub 改为真实函数声明 | ### 5.4 删除的文件 | 文件 | 原因 | |------|------| | `main/pages/pages_stub.c` | 被 `main/dzbj/pages.c` 真实实现替代 | --- ## 六、GPIO 引脚分配(已解决) Phase 1 已完成的 GPIO 冲突解决: | GPIO | 主项目原用途 | dzbj用途 | 解决方案 | |------|------------|---------|---------| | 21 | BUILTIN_LED | LCD D3 | LED 改为 GPIO_NUM_NC | | 1 | Touch1 (电容触摸) | LCD 背光 EN | Touch1 改为 GPIO_NUM_NC | | 7 | Touch4 (电容触摸) | LCD RST | Touch4 改为 GPIO_NUM_NC | | 6 | Battery ADC | Touch RST | Battery ADC 改为 GPIO 3 | | 17/18 | I2C_NUM_1 (音频) | I2C_NUM_0 (触摸) | 统一为 I2C_NUM_1 共享 | --- ## 七、风险评估 ### 7.1 重启切换方案(已选定) | 风险 | 等级 | 说明 | |------|------|------| | 内存泄漏 | **无** | 每次重启全新初始化,无残留 | | 内存碎片化 | **无** | 重启清除所有堆分配 | | WiFi/BLE deinit 不可靠 | **无** | 无需 deinit,重启自然释放 | | NVS 擦写寿命 | **极低** | 10-100万次,日常使用完全足够 | | 切换体验 | **低** | ~3-4秒重启时间,可加转场动画优化 | ### 7.2 其他风险 | 风险 | 等级 | 缓解方案 | |------|------|---------| | 符号冲突(pages_stub vs pages.c) | 中 | 删除 stub,真实实现始终编译 | | button 模块冲突(C++ Button vs C ISR) | 中 | 条件初始化,两模式用不同实现 | | SPIFFS 分区未配置 | 中 | 检查分区表是否有 spiffs 分区 | | Flash 空间 | 低 | 当前 app 分区 5MB,固件 ~3.5MB,剩余充足 | --- ## 八、分区表 当前分区表: ```csv # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x4000, otadata, data, ota, 0xd000, 0x2000, phy_init, data, phy, 0xf000, 0x1000, model, data, spiffs, 0x10000, 0x300000, ota_0, app, ota_0, 0x310000, 5M, ota_1, app, ota_1, 0x820000, 5M, ``` dzbj 图片浏览功能需要 SPIFFS 存储。`model` 分区(3MB, spiffs 类型)可复用,或需新增 storage 分区。 --- ## 九、验证计划 ### 9.1 编译验证 ```bash idf.py build ``` ### 9.2 AI 模式验证(默认 mode=0) - [ ] 开机正常进入 WiFi 连接 + RTC 对话 - [ ] LVGL 显示 ScreenHome - [ ] BOOT 单击切换对话状态 - [ ] BOOT 双击 → 切换到吧唧模式,设备重启 - [ ] 内存剩余 > 80KB ### 9.3 吧唧模式验证(mode=1) - [ ] 开机日志显示"电子吧唧模式启动" - [ ] 不连接 WiFi,不播放开机语音 - [ ] BLE 广播可见(手机搜索 "Airhub_XX:XX:XX") - [ ] 手机 APP 可传输图片到设备 - [ ] 屏幕显示传输的图片 - [ ] 10s 无操作后屏幕熄灭 - [ ] 按键或触摸唤醒屏幕 - [ ] BOOT 双击 → 切换回 AI 模式,设备重启 - [ ] 内存剩余 > 150KB ### 9.4 稳定性验证 - [ ] 来回切换 10+ 次,功能正常 - [ ] 各模式下长时间运行(>1小时)无崩溃