基于 ESP32-P4 开发板的智能语音助手,支持 7 寸 MIPI 触摸屏显示、WiFi/蓝牙 无线通信、摄像头人脸检测、语音唤醒与控制等丰富功能。
- 主控:ESP32-P4 + ESP32-C6 (SDIO WiFi)
- 屏幕:7 寸 1024×600 MIPI 触摸屏
- 摄像头:MIPI CSI 摄像头
- 音频:I2S 麦克风 + 扬声器
- 传感器:DHT22 温湿度、BH1750 光照强度
- 语音助手:支持"你好小智"唤醒词唤醒、语音对话控制
- 智能家居:Smart Home Control 界面,实时显示温湿度/光照,控制风扇/灯光
- 人脸检测:摄像头检测人脸后自动解锁屏幕
- OTA 升级:支持远程固件更新
- MQTT 通信:通过 MQTT 与服务器交互
- 微信风格聊天 UI:对话气泡界面
将项目中全部 FreeRTOS 原生 API 封装为统一的 POSIX 标准接口,使上层应用代码具备跨 RTOS 可移植性。
// 改造前:68 个文件散布裸 FreeRTOS API
xTaskCreate(func, "dht22", 4096, NULL, 5, NULL);
xEventGroupWaitBits(eg, MASK, pdTRUE, pdFALSE, portMAX_DELAY);
// 改造后:统一 POSIX 风格接口,底层实现可替换
posix::task_create({"dht22", 4096, 5, -1}, func);
event_group->wait_bits(MASK, true, false, 0);新增 main/posix_compat/ 模块(posix_event.h / posix_queue.h / posix_task.h / posix_timer.h),上层应用不再直接依赖 FreeRTOS。未来移植到 NuttX / Zephyr 只需替换底层 4 个头文件,68 个业务文件一行不动。
自研轻量级内存保护框架,解决 FreeRTOS 扁平内存模型下野指针导致整机死机的固有问题。
main/mem_protect/
├── mem_pool.h/cc — 5 域分区内存池(AUDIO / DISPLAY / CAMERA / NETWORK / SYSTEM)
├── mem_guard.h — 魔数哨兵检测(越界写入即时捕获)
└── mem_pmp.h — RISC-V PMP 代码段硬件写保护
每个模块在自己的域分配内存,跨域释放被拒绝并告警;释放时校验首尾魔数,越界写入立即报警;代码段通过 PMP 硬件锁定,野指针写入触发 CPU 异常。
智能家居设备采用 Matter 标准的 Endpoint → Cluster → Attribute 三层架构,实现设备模型标准化。
MatterNode
├── Endpoint 1: 本地环境传感器
│ ├── Temperature Measurement → DHT22
│ ├── Humidity Measurement → DHT22
│ └── Light Measurement → BH1750
├── Endpoint 2: 本地执行器
│ ├── Fan Control → GPIO36/7 风扇
│ └── OnOff → GPIO12 灯泡
└── Endpoint 3: Room2 远程传感器 (ESP32-C3)
新增 main/matter_device/ 模块(matter_attribute.h / matter_cluster.h / matter_endpoint.h / matter_device_mgr.h),MCP 工具从原来 6 个手写接口变为 3 个通用工具自动适配;Web API 新增 GET /api/matter/descriptor 返回完整设备树 JSON。
背景问题:ESP32-C3 通过 WiFi 向 P4 上报温湿度和光照数据。P4 的 IP 地址由路由器 DHCP 动态分配,几天一变。C3 固件硬编码了 IP 192.168.1.253,每次 IP 变化就必须手动修改代码并重新烧录 C3。
解决方案:引入 mDNS(组播 DNS) 自动服务发现机制,彻底消除 IP 硬编码依赖。
P4 启动 → 连接 WiFi → mdns_init() → 广播主机名 "xiaozhi.local"
C3 启动 → 连接 WiFi → mdns_init() → getaddrinfo("xiaozhi.local") → 解析到 P4 当前 IP → POST 数据
改动清单:
| 端 | 文件 | 改动 |
|---|---|---|
| P4 | main/idf_component.yml |
添加 espressif/mdns:* 组件依赖 |
| P4 | main/boards/common/wifi_board.cc |
WiFi 连接成功后调用 mdns_init() + mdns_hostname_set("xiaozhi");修正默认 SSID ZBCK → ZBCK-E |
| C3 | c3_sensor_node/main/idf_component.yml |
新建,添加 espressif/mdns:* 依赖 |
| C3 | c3_sensor_node/main/c3_sensor_node.c |
删除硬编码 IP 192.168.1.253;添加 mdns_init() + getaddrinfo("xiaozhi.local") 动态解析;使用 ntohl() 正确处理网络字节序;每 10 分钟自动刷新解析 |
效果:
- ✅ P4 IP 无论怎么变,C3 自动发现,无需重新烧录
- ✅ 数据上报延迟 ≤ 5 秒(与硬编码 IP 相同)
- ✅ C3 首次烧录后永久免维护
关键踩坑:ESP-IDF v5.5 已将 mDNS 从框架内置组件迁移至 Component Manager,需通过
idf_component.yml配合idf.py update-dependencies拉取;LWIP 的getaddrinfo()返回的sin_addr.s_addr为网络字节序,在 ESP32-C3(RISC-V LE)上直接使用会导致 IP 字节序反转(192.168.1.253变为253.1.168.192),必须用ntohl()转换。
- ESP-IDF:v5.5.1
- LVGL:v8.4.0
- 目标芯片:esp32p4
# 配置项目
idf.py set-target esp32p4
idf.py menuconfig
# 编译
idf.py build
# 烧录
idf.py -p COMxxx flash
# 监视日志
idf.py -p COMxxx monitor| 分区 | 大小 | 说明 |
|---|---|---|
| nvs | 24KB | 非易失存储 |
| phy_init | 4KB | PHY 初始化数据 |
| model | 960KB | 语音唤醒模型 |
| factory | 8MB | 应用程序 |
| storage | 4MB | SPIFFS 存储 |
├── main/ # 主程序
│ ├── application.cc # 应用主逻辑
│ ├── boards/ # 板级支持包
│ ├── display/ # 显示/LVGL 相关
│ ├── audio/ # 音频服务
│ ├── camera/ # 相机显示
│ ├── sensors/ # 传感器驱动
│ ├── posix_compat/ # POSIX 标准化层
│ ├── mem_protect/ # 内存隔离保护
│ ├── matter_device/ # 类Matter设备模型
│ └── assets/ # UI 资源文件
├── components/ # 本地组件
├── managed_components/ # 托管组件 (ESP-Registry)
└── partitions-16MiB.csv # 分区表
- 仅支持WKS 7 寸 1024×600 MIPI 屏
- 需外接 PSRAM(ESP32-P4 必备)