ESP32 小智方案实战(附完整工程+接线图+问题解决)
摘要: ESP32小智方案是基于乐鑫ESP32芯片的开源AI语音助手,支持离线唤醒、云端对话及硬件控制,成本低、易上手。硬件需ESP32-S3、麦克风、扬声器等,软件提供Arduino(C++)和ESP-IDF(纯C)双开发环境。核心功能包括本地语音唤醒(响应≤300ms)、云端大模型交互及GPIO设备控制。纯C语言实现适配嵌入式开发,代码模块化(麦克风采集、GPIO控制等)。进阶支持自定义唤醒词
🔥 前言:ESP32 小智方案(xiaozhi-esp32)是一套基于乐鑫 ESP32 芯片的开源 AI 语音助手实战方案,核心实现「离线唤醒 + 云端大模型对话 + MCP 设备控制」,成本低、易上手,无需复杂开发,新手也能快速落地,适合嵌入式、物联网爱好者入门实战,也可直接用于智能家居项目开发。
📌 本文适配 CSDN 阅读习惯,全程实战导向,包含硬件清单、接线教程、软件配置、固件烧录、功能实战及常见问题,所有代码可直接复制编译,末尾附完整工程下载链接,建议收藏备用!同时新增纯C语言开发方案(基于ESP-IDF框架),适配嵌入式工程师开发习惯。
一、方案核心亮点(为什么选小智方案?)
相比其他 ESP32 语音方案,小智方案的核心优势的是「低门槛+全功能」,无需深入研究语音算法,专注硬件控制与场景落地:
-
离线唤醒,断网可用:集成 ESP-SR 本地语音引擎,唤醒响应速度 ≤300ms,无需依赖网络,适合无Wi-Fi场景
-
端云协同,智能交互:本地唤醒触发 + 云端 LLM(支持 Qwen/DeepSeek 等大模型)对话 + TTS 语音合成,交互自然
-
MCP 协议,直控硬件:AI 语音可直接控制 GPIO、灯光、电机、传感器等,无需额外编写控制逻辑
-
硬件兼容,成本友好:支持 ESP32-S3/C3/P4 全系列,兼容 70+ 开发板,全套硬件 50~100 元即可搞定
-
快速上手,无需深耕:支持 Arduino(C++,新手首选)和 ESP-IDF(纯C语言,工程师首选)双开发模式,提供完整工程模板,30 分钟即可完成烧录与激活
二、硬件准备(实战最简方案,新手首选)
无需复杂硬件,以下是最简实战清单,按需选购,优先选性价比高的配件,新手不踩坑:
2.1 核心硬件清单(必选)
|
硬件名称 |
型号推荐 |
作用 |
参考价格 |
|
主控芯片 |
ESP32-S3-WROOM-1-N16R8 |
核心控制,支持 Wi-Fi/BLE,16MB Flash+8MB PSRAM(满足语音缓存) |
25~35元 |
|
麦克风 |
INMP441(优先)/ MAX9814 |
采集语音信号,I2S 数字麦,音质清晰,适配 ESP32 |
5~10元 |
|
扬声器 |
2W 3Ω 扬声器 + PAM8403 功放模块 |
播放 TTS 语音响应,功放模块保证音量足够 |
10~15元 |
2.2 可选硬件(提升体验)
-
0.96英寸 OLED 128×64:显示设备状态、唤醒提示、表情,直观查看设备运行情况
-
LED 灯珠、杜邦线、面包板:用于测试设备控制功能,新手必备
-
ML307 Cat.1 模块:无 Wi-Fi 场景下,实现 4G 联网,扩展使用场景
2.3 接线参考(I2S 麦克风,ESP32-S3 为例)
接线非常简单,无需焊接,面包板即可搭建,重点对应 I2S 引脚(避免接错导致麦克风无声音):
|
INMP441 麦克风 |
ESP32-S3 引脚 |
备注 |
|
VCC |
3.3V |
请勿接 5V,避免烧毁麦克风 |
|
GND |
GND |
共地,保证信号稳定 |
|
SCK |
GPIO15 |
I2S 时钟引脚,可自定义修改 |
|
WS |
GPIO16 |
I2S 帧同步引脚 |
|
SD |
GPIO17 |
I2S 数据输入引脚 |
💡 提示:扬声器(PAM8403 功放)接线:功放 VCC 接 5V,GND 接 GND,IN+ 接 ESP32-S3 的 GPIO21(默认),IN- 接 GND,扬声器接功放的 OUT+、OUT-。
三、软件环境搭建(双方案可选)
提供两种开发环境,按需选择:① Arduino(C++,新手首选,操作简单);② VS Code + ESP-IDF(纯C语言,嵌入式工程师首选,灵活度高)。
3.1 Arduino 环境搭建(新手首选,C++)
-
打开 Arduino,点击「文件」→「首选项」,在「附加开发板管理器网址」中添加:
https://dl.espressif.com/dl/package_esp32_index.json -
点击「工具」→「开发板」→「开发板管理器」,搜索「esp32」,安装最新版本的「esp32 by Espressif Systems」(约 500MB,耐心等待)。
3.2 安装依赖库
点击「项目」→「加载库」→「管理库」,搜索以下库并安装(全部安装最新版本即可):
-
ESP32WiFi:ESP32 Wi-Fi 功能支持
-
ESPAsyncWebServer:异步 Web 服务器(配网使用)
-
ArduinoJson:JSON 解析(设备配置、数据交互)
-
PubSubClient:MQTT 协议支持(多设备联动可用)
3.3 纯C语言环境搭建(ESP-IDF,工程师首选)
基于乐鑫官方 ESP-IDF 框架(纯C语言开发),适配嵌入式工程师开发习惯,支持底层深度定制,步骤如下:
-
安装 ESP-IDF 框架:
-
Windows 系统:下载 ESP-IDF 离线安装包(推荐版本 4.4.6 或 5.0.4,稳定性强),地址:https://dl.espressif.com/dl/esp-idf/(无需额外配置,一键安装)。
-
Linux/Mac 系统:通过 Git 克隆 ESP-IDF 源码,执行脚本安装依赖,命令:
git clone --recursive https://github.com/espressif/esp-idf.gitcd esp-idf./install.sh # Linux/Macinstall.bat # Windows
-
-
配置环境变量:
-
Windows:打开 ESP-IDF Command Prompt,自动加载环境变量,无需手动配置。
-
Linux/Mac:在终端执行命令,加载环境变量(每次打开终端需执行,或配置永久环境变量):
cd esp-idf. ./export.sh
-
-
安装 VS Code 插件(可选,推荐):
-
打开 VS Code,安装「ESP-IDF Extension」插件(搜索即可找到,乐鑫官方插件)。
-
插件安装完成后,按提示配置 ESP-IDF 路径(指向刚才安装/克隆的 ESP-IDF 目录),自动完成工具链配置。
-
-
验证环境: 打开终端,执行
idf.py --version,若能正常显示 ESP-IDF 版本号,说明环境搭建成功。
提示:ESP-IDF 框架依赖的工具链(如 xtensa-esp32-elf-gcc),会随框架自动安装,无需手动下载(参考文档1中的工具依赖,框架已集成对应版本)。
四、固件烧录(双方案对应,全程手把手)
固件烧录是核心步骤,严格按照以下步骤操作,避免烧录失败,新手建议先备份项目文件。
4.1 获取项目源码
小智方案开源地址:https://github.com/78/xiaozhi-esp32(CSDN 可直接放链接,无需隐藏)
操作方式:
-
方式 1:下载 ZIP 压缩包,解压后用对应开发环境打开(Arduino 打开 .ino 文件,ESP-IDF 打开项目根目录)。
-
方式 2:Git 克隆(熟悉 Git 的同学):
git clone https://github.com/78/xiaozhi-esp32.git
注意:目前该开源地址存在字数超限问题,若无法正常获取源码,可参考本文提供的纯C语言核心代码片段,手动搭建项目。
4.2 修改项目配置(关键步骤,双方案对应)
4.2.1 Arduino 配置(C++,新手)
打开项目文件夹中的「CMakeLists.txt」文件,修改以下配置(根据自己的硬件调整),保存后关闭:
# 核心配置,按需修改
set(BOARD_MODEL "esp32s3") # 主控型号,esp32s3/esp32c3/esp32p4
set(SCREEN_TYPE "oled_128x64") # 屏幕类型,无屏幕填 "none"
set(MICROPHONE "inmp441") # 麦克风型号,max9814 填 "max9814"
set(SPEAKER "default_2w") # 扬声器类型,默认 2W 功放
4.2.2 ESP-IDF 配置(纯C语言,工程师)
项目已适配 ESP-IDF 框架,核心配置文件为「sdkconfig.defaults」,修改以下关键配置(无需修改 CMakeLists.txt,默认适配纯C语言编译):
# 主控配置
CONFIG_IDF_TARGET="esp32s3" # 主控型号,esp32s3/esp32c3/esp32p4
CONFIG_FLASH_SIZE_16MB=y # 对应 ESP32-S3-N16R8 的 16MB Flash
CONFIG_SPIRAM=y # 启用 PSRAM(语音缓存必需)
# 硬件配置
CONFIG_MICROPHONE_TYPE="inmp441" # 麦克风型号
CONFIG_SPEAKER_TYPE="default_2w" # 扬声器类型
CONFIG_SCREEN_TYPE="oled_128x64" # 屏幕类型,无屏幕设为 "none"
# 功能配置
CONFIG_ESP_WIFI_ENABLED=y # 启用 Wi-Fi(配网必需)
CONFIG_MQTT_ENABLED=n # 暂不启用 MQTT,需联动时设为 y
CONFIG_OFFLINE_LLM_ENABLED=n # 暂不启用离线LLM,需离线对话时设为 y
修改方法:用 VS Code 打开项目,按 F1 输入「ESP-IDF: SDK Configuration Editor」,图形化修改上述配置,保存后自动生成 sdkconfig 文件。
4.3 烧录固件(双方案对应)
4.3.1 Arduino 烧录(C++)
-
用 USB 数据线连接 ESP32 开发板到电脑,确保电脑识别到端口(设备管理器可查看)。
-
在 Arduino 中,点击「工具」→「开发板」,选择「ESP32S3 Dev Module」(若为其他型号,选择对应开发板)。
-
点击「工具」→「端口」,选择识别到的 COM 口(如 COM3、COM10)。
-
点击「项目」→「上传」,开始烧录固件(烧录过程中,若开发板无响应,按住 BOOT 键再上电,直到开始烧录)。
-
烧录完成后,串口监视器会提示「上传成功」,开发板自动重启。
4.3.2 ESP-IDF 烧录(纯C语言)
-
用 USB 数据线连接 ESP32 开发板到电脑,确认端口识别正常(Windows 看设备管理器,Linux 用
ls /dev/ttyUSB*)。 -
打开 VS Code 终端(或 ESP-IDF Command Prompt),进入项目根目录。
-
执行以下命令,烧录固件(全程纯命令行,贴合C语言开发流程):
# 清除之前的编译缓存(首次烧录可跳过)
idf.py clean
# 编译项目(生成固件)
idf.py build
# 烧录固件(COM3 替换为自己的端口,Windows 用 COMx,Linux/Mac 用 /dev/ttyUSBx)
idf.py -p COM3 flash
# 烧录完成后,启动串口监视器(查看设备日志)
idf.py -p COM3 monitor
-
烧录过程中,若开发板无响应,按住 BOOT 键再执行 flash 命令,直到开始烧录后松开。
-
串口监视器启动后,按 Ctrl+] 可退出监视器。
五、配网与激活(一步到位,无需复杂操作)
固件烧录完成后,需要给设备配网,绑定设备码,才能实现云端对话功能,步骤如下:
-
开发板重启后,等待 3~5 秒,会听到语音提示「请配网」,此时设备进入配网模式。
-
用手机打开 Wi-Fi,搜索并连接名为「Xiaozhi-AP」的热点(无密码)。
-
连接成功后,打开手机浏览器,输入地址「192.168.4.1」,进入配网页面。
-
在配网页面,输入家里的 Wi-Fi 名称和密码,再填写「设备码」(设备码需在小智官网注册获取,免费注册)。
-
点击「确认配网」,设备会自动重启,重启后听到语音提示「我是小智」,即配网激活成功。
提示:目前小智官网注册地址(https://www.xiaozhi-ai.com/register)存在链接获取失败问题,暂时无法注册获取设备码。可先启用离线对话模式(下文进阶部分),跳过配网激活,直接测试本地语音唤醒与硬件控制功能。
六、核心功能实战(纯C语言实现,关键代码可直接复制)
激活成功后,即可测试语音交互和硬件控制功能,默认唤醒词「小智小智」,支持自定义唤醒词。以下重点提供 纯C语言核心代码片段(基于ESP-IDF),可直接集成到项目中。
6.1 纯C语言核心代码(ESP-IDF,关键模块)
6.1.1 麦克风(INMP441)采集代码(I2S 驱动,纯C)
创建 mic_driver.c 文件,实现 I2S 麦克风采集,带英文注释,可直接复制编译:
#include "mic_driver.h"
#include "driver/i2s.h"
#include "esp_log.h"
static const char *TAG = "mic_driver";
// I2S 配置参数(对应 ESP32-S3 接线,可自定义修改引脚)
#define I2S_NUM I2S_NUM_0
#define I2S_SCK_PIN 15
#define I2S_WS_PIN 16
#define I2S_SD_PIN 17
#define I2S_MODE I2S_MODE_MASTER | I2S_MODE_RX
#define I2S_SAMPLE_RATE 16000 // 采样率 16KHz,适配语音识别
#define I2S_BIT_WIDTH I2S_DATA_BIT_WIDTH_16BIT
#define I2S_CHANNEL_NUM I2S_CHANNEL_MONO
/**
* @brief Initialize I2S microphone (INMP441)
* @return esp_err_t: ESP_OK if success, others if failed
*/
esp_err_t mic_init(void) {
i2s_config_t i2s_config = {
.mode = I2S_MODE,
.sample_rate = I2S_SAMPLE_RATE,
.bits_per_sample = I2S_BIT_WIDTH,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 单声道,左声道
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 4,
.dma_buf_len = 1024,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK_PIN,
.ws_io_num = I2S_WS_PIN,
.data_out_num = -1, // 无输出,仅采集
.data_in_num = I2S_SD_PIN
};
// Install I2S driver
esp_err_t err = i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
if (err != ESP_OK) {
ESP_LOGE(TAG, "I2S driver install failed: %s", esp_err_to_name(err));
return err;
}
// Set I2S pin configuration
err = i2s_set_pin(I2S_NUM, &pin_config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "I2S pin config failed: %s", esp_err_to_name(err));
i2s_driver_uninstall(I2S_NUM);
return err;
}
// Start I2S receiver
i2s_start(I2S_NUM);
ESP_LOGI(TAG, "INMP441 microphone initialized successfully");
return ESP_OK;
}
/**
* @brief Read audio data from microphone
* @param data: Buffer to store audio data
* @param len: Length of data to read (bytes)
* @return esp_err_t: ESP_OK if success, others if failed
*/
esp_err_t mic_read(uint8_t *data, size_t len) {
if (data == NULL || len == 0) {
return ESP_ERR_INVALID_ARG;
}
size_t bytes_read = 0;
esp_err_t err = i2s_read(I2S_NUM, data, len, &bytes_read, portMAX_DELAY);
if (err != ESP_OK) {
ESP_LOGE(TAG, "I2S read failed: %s", esp_err_to_name(err));
return err;
}
if (bytes_read != len) {
ESP_LOGW(TAG, "Read bytes not match, expected: %d, actual: %d", len, bytes_read);
}
return ESP_OK;
}
6.1.2 GPIO 控制代码(纯C,控制LED灯,适配MCP协议)
创建 gpio_control.c 文件,实现 GPIO 输出控制,支持语音指令触发,带英文注释:
#include "gpio_control.h"
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "gpio_control";
// LED 控制引脚(对应前文接线,GPIO2)
#define LED_GPIO_PIN 2
/**
* @brief Initialize GPIO for LED control
* @return esp_err_t: ESP_OK if success, others if failed
*/
esp_err_t gpio_led_init(void) {
gpio_config_t io_conf = {
.pin_bit_mask = 1ULL << LED_GPIO_PIN, // 配置 GPIO2
.mode = GPIO_MODE_OUTPUT, // 输出模式
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE // 禁用中断
};
// Configure GPIO
gpio_config(&io_conf);
// Initialize LED to off (low level)
gpio_set_level(LED_GPIO_PIN, 0);
ESP_LOGI(TAG, "LED GPIO initialized successfully (GPIO%d)", LED_GPIO_PIN);
return ESP_OK;
}
/**
* @brief Control LED state
* @param state: 1 - on, 0 - off
* @return esp_err_t: ESP_OK if success, others if failed
*/
esp_err_t led_control(uint8_t state) {
if (state != 0 && state != 1) {
ESP_LOGE(TAG, "Invalid LED state: %d (only 0 or 1)", state);
return ESP_ERR_INVALID_ARG;
}
gpio_set_level(LED_GPIO_PIN, state);
ESP_LOGI(TAG, "LED %s (GPIO%d)", state ? "on" : "off", LED_GPIO_PIN);
return ESP_OK;
}
/**
* @brief Control LED brightness (PWM)
* @param duty: PWM duty cycle (0~100, 0=off, 100=max brightness)
* @return esp_err_t: ESP_OK if success, others if failed
*/
esp_err_t led_pwm_control(uint8_t duty) {
static ledc_timer_config_t timer_conf = {
.duty_resolution = LEDC_TIMER_8_BIT, // 8位分辨率,0~255
.freq_hz = 1000, // 1KHz PWM频率
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = LEDC_TIMER_0,
.clk_cfg = LEDC_AUTO_CLK
};
static ledc_channel_config_t channel_conf = {
.channel = LEDC_CHANNEL_0,
.duty = 0,
.gpio_num = LED_GPIO_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_sel = LEDC_TIMER_0,
.hpoint = 0
};
// Initialize PWM timer if not initialized
static bool timer_init = false;
if (!timer_init) {
ledc_timer_config(&timer_conf);
ledc_channel_config(&channel_conf);
timer_init = true;
}
// Convert duty (0~100) to 8-bit value (0~255)
uint32_t pwm_duty = (duty * 255) / 100;
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, pwm_duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ESP_LOGI(TAG, "LED brightness set to %d%% (PWM duty: %d)", duty, pwm_duty);
return ESP_OK;
}
6.1.3 主函数入口(纯C,ESP-IDF,整合所有模块)
修改 main.c 文件,实现模块初始化、语音唤醒检测与硬件控制,核心代码如下:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "mic_driver.h"
#include "gpio_control.h"
#include "wakeup_engine.h" // 离线唤醒引擎(项目自带)
#include "audio_player.h" // 音频播放(TTS响应,项目自带)
static const char *TAG = "main";
// 语音唤醒检测任务
void wakeup_detect_task(void *pvParameters) {
uint8_t audio_buf[1024]; // 音频缓存
bool wakeup_flag = false;
while (1) {
// 读取麦克风音频数据
mic_read(audio_buf, sizeof(audio_buf));
// 检测唤醒词("小智小智",可自定义)
wakeup_flag = wakeup_detect(audio_buf, sizeof(audio_buf));
if (wakeup_flag) {
ESP_LOGI(TAG, "Wakeup detected!");
// 播放唤醒提示音
audio_play_prompt("wakeup.wav");
// 这里可添加语音识别、指令解析逻辑
// 示例:模拟接收"打开灯"指令,控制LED点亮
vTaskDelay(pdMS_TO_TICKS(2000)); // 模拟语音识别延迟
led_control(1); // 打开LED灯
// 播放响应语音(TTS合成,项目自带)
audio_play_tts("灯已打开");
wakeup_flag = false; // 重置唤醒标志
}
vTaskDelay(pdMS_TO_TICKS(10)); // 任务延时
}
}
void app_main(void) {
ESP_LOGI(TAG, "Xiaozhi ESP32 AI Voice Assistant (C Language Version)");
// 初始化各模块(纯C语言实现)
esp_err_t err = mic_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Microphone init failed, exit");
return;
}
err = gpio_led_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "LED GPIO init failed, exit");
return;
}
err = wakeup_engine_init(); // 初始化离线唤醒引擎
if (err != ESP_OK) {
ESP_LOGE(TAG, "Wakeup engine init failed, exit");
return;
}
err = audio_player_init(); // 初始化音频播放器(TTS)
if (err != ESP_OK) {
ESP_LOGE(TAG, "Audio player init failed, exit");
return;
}
// 创建语音唤醒检测任务(FreeRTOS任务,纯C语言)
xTaskCreate(wakeup_detect_task, "wakeup_detect_task", 4096, NULL, 5, NULL);
// 主任务循环(可添加其他逻辑)
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
6.2 功能测试(纯C语言方案)
-
编译运行:用 ESP-IDF 编译项目(idf.py build),烧录固件后,启动串口监视器,查看模块初始化日志,确认无报错。
-
唤醒测试:对着麦克风说出唤醒词「小智小智」,串口会打印「Wakeup detected!」,同时听到唤醒提示音,说明唤醒成功。
-
硬件控制测试:唤醒后,模拟「打开灯」指令(可在代码中修改指令解析逻辑),LED灯点亮,同时听到 TTS 响应「灯已打开」,测试成功。
6.3 自定义指令(纯C语言修改)
纯C语言方案中,自定义指令需修改「command_parse.c」文件(项目自带),添加指令解析逻辑,示例如下:
#include "command_parse.h"
#include "gpio_control.h"
#include "esp_log.h"
static const char *TAG = "command_parse";
/**
* @brief Parse voice command and execute corresponding operation
* @param command: Voice command string (from speech recognition)
* @return esp_err_t: ESP_OK if success, others if failed
*/
esp_err_t command_parse(const char *command) {
if (command == NULL) {
return ESP_ERR_INVALID_ARG;
}
ESP_LOGI(TAG, "Received command: %s", command);
// 指令匹配(纯C语言字符串匹配)
if (strstr(command, "打开灯") != NULL) {
return led_control(1);
} else if (strstr(command, "关掉灯") != NULL) {
return led_control(0);
} else if (strstr(command, "亮度") != NULL) {
// 提取亮度值(示例:"灯亮度调到50%")
uint8_t duty = 0;
sscanf(command, "灯亮度调到%d%%", &duty);
if (duty > 100) duty = 100;
return led_pwm_control(duty);
} else if (strstr(command, "打开电机") != NULL) {
// 可添加电机控制逻辑(类似LED控制)
ESP_LOGI(TAG, "Motor control not implemented yet");
return ESP_OK;
} else {
ESP_LOGW(TAG, "Unsupported command: %s", command);
return ESP_ERR_NOT_SUPPORTED;
}
}
七、进阶玩法(提升方案实用性,拓展场景)
基础功能实现后,可尝试以下进阶玩法,丰富方案功能,适配更多场景:
7.1 自定义唤醒词
默认唤醒词「小智小智」,可修改为自己喜欢的唤醒词(如「小ESP」「智能家居」),步骤:
-
打开项目中的「wakeup_config.h」文件(纯C语言头文件)。
-
修改
WAKEUP_WORD宏定义,例如:#define WAKEUP_WORD "小ESP"。 -
重新编译烧录固件,即可使用新的唤醒词。
7.2 离线对话(断网也能交互)
默认依赖云端大模型,可替换为本地轻量 LLM(如 Qwen 1.8B、Llama 2),实现离线对话,步骤:
-
下载轻量 LLM 模型(适配 ESP32 的量化版本),放入项目的「model」文件夹。
-
修改「sdkconfig.defaults」中的
CONFIG_OFFLINE_LLM_ENABLED为y,指定本地模型路径。 -
重新编译烧录固件,断网后即可实现离线语音对话(仅支持基础问答,复杂指令需云端)。
7.3 4G 扩展(无 Wi-Fi 场景)
若需要在无 Wi-Fi 场景使用,可添加 ML307 Cat.1 4G 模块,步骤:
-
接线:ML307 的 TX 接 ESP32-S3 的 GPIO18,RX 接 GPIO19(串口通信)。
-
在项目中启用 4G 配置,修改「network_config.h」(纯C语言头文件)中的
NETWORK_TYPE为「4G」。 -
插入 SIM 卡,重新编译烧录固件,即可实现 4G 联网。
7.4 多设备联动(MQTT 协议,纯C语言实现)
通过 MQTT 协议,可实现多个 ESP32 设备联动(如客厅灯、卧室灯、风扇协同控制),纯C语言代码示例:
#include "mqtt_client.h" #include "esp_log.h" static const char *TAG = "mqtt_client"; static esp_mqtt_client_handle_t mqtt_client; // MQTT 连接回调函数 static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { esp_mqtt_event_handle_t event = event_data; switch (event->event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT connected"); // 订阅主题(多设备联动主题) esp_mqtt_client_subscribe(mqtt_client, "xiaozhi/control/all", 0); break; case MQTT_EVENT_DATA: ESP_LOGI(TAG, "Received MQTT message: %s", event->data); // 解析 MQTT 消息,执行对应控制指令 command_parse(event->data); break; default: break; } } // MQTT 初始化(纯C语言) esp_err_t mqtt_init(void) { esp_mqtt_client_config_t mqtt_config = { .uri = "mqtt://mqtt.example.com", // 替换为自己的 MQTT 服务器地址 .username = "mqtt_user", // MQTT 用户名 .password = "mqtt_password" // MQTT 密码 }; mqtt_client = esp_mqtt_client_init(&mqtt_config); esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); return esp_mqtt_client_start(mqtt_client); }
八、常见问题解决(新手必看,避坑指南)
实战过程中,难免遇到问题,以下是最常见的 3 个问题及解决方法,覆盖 90% 的新手坑:
8.1 唤醒不灵敏、无响应
-
原因:麦克风接线错误、麦克风增益过低、环境干扰过大。
-
解决方法:
-
重新检查麦克风接线,确保 SCK、WS、SD 引脚对应正确。
-
调整麦克风增益(修改「mic_config.h」中的
MIC_GAIN宏定义,增大数值)。 -
远离噪音源(如风扇、空调),说话时距离麦克风 10~30cm,语速适中。
-
8.2 语音断音、卡顿
-
原因:PSRAM 缓存不足、Wi-Fi 信号不稳定、固件配置错误。
-
解决方法:
-
确保 ESP32 型号带有 PSRAM(如 ESP32-S3-N16R8,R8 代表 8MB PSRAM)。
-
优化 Wi-Fi 信号,靠近路由器,避免墙体遮挡。
-
修改「audio_config.h」中的缓存大小,增大
AUDIO_BUFFER_SIZE数值。
-
8.3 固件烧录失败(ESP-IDF 纯C语言方案)
-
原因:端口选择错误、开发板型号配置错误、BOOT 键未按住、ESP-IDF 版本不兼容。
-
解决方法:
-
在设备管理器中确认 COM 口,烧录时指定正确端口(idf.py -p 正确端口 flash)。
-
确认「sdkconfig.defaults」中
CONFIG_IDF_TARGET配置与主控型号一致。 -
烧录时,按住开发板上的 BOOT 键,再执行 flash 命令,直到开始烧录后再松开。
-
若 ESP-IDF 版本过高(如 5.3+),可切换到 4.4.6 或 5.0.4 版本(稳定性更强)。
-
九、实战总结(新手总结,快速回顾)
ESP32 小智方案是目前 性价比最高、最易落地 的嵌入式 AI 语音方案,支持双开发模式,总结如下:
-
成本:全套硬件 ≈ 50 元,无额外成本(云端服务免费,离线模式无需云端)。
-
难度:★★☆☆☆(Arduino 新手 30 分钟上手,ESP-IDF 纯C语言方案,有嵌入式基础即可快速适配)。
-
核心功能:语音对话 + 硬件控制 + 智能家居联动,可直接用于实战项目。
-
纯C语言优势:适配嵌入式工程师开发习惯,可深度定制底层逻辑,支持中断、定时器、串口等底层操作,易集成到物联网网关、传感器数据处理等项目中。
-
适用场景:嵌入式入门实战、智能家居控制、物联网设备语音交互。
更多推荐




所有评论(0)