一、任务介绍
我们本次选择的任务是智能语音氛围灯带,本次主要的使用模块为rgb灯带、OLED、蜂鸣器模块以及ESP32‑S3 Sense开发板,我们将通过这些模块实现一个智能语音氛围灯带。本次的主要任务是设计三种氛围灯显示模式,然后通过AI模型进行麦克风语音的识别,我们本次需要至少实现三条语音指令,然后在OLED上显示相关信息,并在相关指令切换的时候通过蜂鸣器短鸣进行提示。
二、项目概述
随着物联网技术的快速发展和智能家居概念的深入人心,语音交互作为一种自然、便捷的人机交互方式,正在被越来越广泛地应用于各类智能设备中。本项目设计并实现了一款基于Seeed XIAO ESP32-S3 Sense的智能语音氛围灯带系统,该系统能够通过语音指令实时控制RGB LED灯带的显示模式,同时配备OLED显示屏实时显示当前工作状态,并通过蜂鸣器提供听觉反馈。
本项目的核心目标是构建一个低成本、易于扩展的语音控制LED灯带系统。系统以ESP32-S3为主控芯片,集成了Edge Impulse边缘推理引擎实现本地语音识别,无需依赖云端服务即可完成离线语音控制。整个系统设计遵循模块化原则,各功能模块之间相互独立又紧密协作,便于后续的功能扩展。
项目采用PlatformIO作为开发环境,结合Arduino框架进行程序设计,实现了语音采集、信号处理、模型推理、输出控制等内容。经过实际测试验证,系统能够准确识别用户发出的"open"、"switch"、"close"等语音指令,并相应地切换LED灯带的显示模式,同时在OLED屏幕上显示当前的工作状态,通过蜂鸣器发出提示音。
三、硬件系统设计
1、 主控芯片选型
本项目选用Seeed XIAO ESP32-S3 Sense作为核心控制器。ESP32-S3是乐鑫科技推出的一款高性能、低功耗Wi-Fi+蓝牙双模SoC芯片,采用Xtensa® 32位LX7处理器,主频可达240MHz,具备强大的计算能力。其内置的AI向量指令集特别适合运行神经网络推理任务,非常适合本项目的边缘AI应用场景。
XIAO ESP32-S3 Sense是Seeed Studio基于ESP32-S3推出的微型开发板,尺寸仅为21×17.5mm,体积小巧但功能完备。板载4MB Flash和8MB PSRAM,支持Wi-Fi 802.11 b/g/n和蓝牙5.0通信,通过扩展板的PDM数字麦克风,可以直接进行音频采集。此外,开发板还提供了丰富的外设接口,包括I2C、SPI、UART等,能够满足本项目连接OLED显示屏、RGB LED灯带和蜂鸣器的需求。
2、音频采集模块
音频采集模块采用开发板扩展板内置的PDM(Pulse Density Modulation)数字麦克风。PDM是一种常用的数字音频传输协议,通过密度调制的脉冲信号来表示模拟音频信号的幅度,具有抗干扰能力强、无需模数转换器等优点。系统配置麦克风工作于单声道模式,采样率为16000Hz,采样位宽为16bit,能够满足语音识别应用对音频质量的要求。在硬件连接方面,ESP32-S3通过I2S接口与PDM麦克风通信。I2S(Inter-IC Sound)是一种用于音频设备之间数字传输的同步串行接口协议,支持全双工数据传输。在本项目中,I2S的BCK(位时钟)引脚配置为GPIO42,WS(字时钟)引脚配置为GPIO41,通过这种固定引脚的配置方式,确保了音频数据传输的稳定性。
3、RGB LED灯带
RGB LED灯带采用SK6812智能RGB灯珠,该芯片集成了控制电路和RGB发光单元,采用单线通讯协议,仅需一根数据线即可实现多级联控制。灯带共包含10颗灯珠,每颗灯珠可独立设置颜色和亮度,支持16777216种颜色显示。SK6812的工作电压为5V,与ESP32-S3的IO输出电平兼容。数据信号线连接至GPIO8,通过Neopixel库实现对灯珠的精确控制。在软件层面,定义了三种显示模式:跑马灯模式每次仅点亮一颗绿色灯珠并依次循环移动;彩虹灯模式10颗灯珠同时亮起但颜色随机生成;闪烁模式所有灯珠同步亮起蓝色并以1秒为周期交替闪烁。
4、OLED显示屏
人机界面显示采用SSD1306驱动的0.96英寸OLED显示屏,分辨率为128×64像素,采用I2C接口通信,I2C地址为0x3C。SSD1306是一款成熟的OLED驱动芯片,内置128×64位GDDRAM,支持多种接口模式,功耗低、对比度高,非常适合嵌入式设备使用。显示屏与主控的连接使用D4作为SDA(数据线),D5作为SCL(时钟线),遵循标准I2C通信协议。在实际使用中,通过Adafruit_SSD1306库和Adafruit_GFX库实现图形界面的绘制,屏幕能够清晰显示当前LED灯带的工作模式,包括"OFF"、"Running"、"Rainbow"、"Blink"四种状态。
5、蜂鸣器模块
本项目使用了一个蜂鸣器作为声音反馈装置,当语音指令被成功识别并执行后,蜂鸣器会发出短促的提示音,告知用户当前操作已生效。蜂鸣器通过GPIO9连接至ESP32-S3,利用LEDC(LED控制器)外设产生PWM信号来驱动蜂鸣器发声。LEDC是ESP32系列芯片内置的PWM控制器,共有16个独立通道可供配置。本项目使用通道4,配置PWM频率为2000Hz、分辨率为8位(0-255),通过调节占空比来控制蜂鸣器的音量。当识别到有效语音指令时,将占空比设置为128(50%)持续100毫秒,随后关闭PWM输出,即可产生清晰的提示音效。
5、连接示意图与实物
硬件连接示意图:

模块实际连接图:

四、软件系统设计
1、开发环境与框架
项目开发采用PlatformIO作为集成开发环境,这是一个跨平台的物联网开发工具,支持多种嵌入式平台和框架。PlatformIO提供了统一的项目构建系统、库管理功能和设备调试工具,能够大大简化嵌入式项目的开发流程。
程序基于Arduino框架编写,Arduino以其简洁的API设计和丰富的库资源著称,非常适合快速原型开发。
核心推理引擎选用Edge Impulse边缘AI平台生成的TFLite Micro模型,Edge Impulse是一家专注于边缘机器学习的公司,提供了从数据采集、模型训练到部署上线的完整工具链。
2、语音识别模型
系统使用的语音识别模型由Edge Impulse平台训练完成,支持识别6个英文词汇:"close"(关闭)、"fast"(快速)、"noise"(噪音)、"open"(打开)、"slow"(慢速)、"switch"(切换)。模型采用经典的MFCC(梅尔频率倒谱系数)进行音频特征提取,结合小型神经网络进行分类推理。实际通过不断调试效果比较好的为"close"(关闭)、"noise"(噪音)、"open"(打开)、"switch"(切换),其中有效的识别标签为3个。
模型的关键参数配置如下:输入采样率为16000Hz,每次推理需要16000个采样点(即1秒音频),MFCC特征维度为637,模型输出为6个类别的置信度分数。为了适应ESP32-S3的有限资源,模型经过量化优化,使用INT8数据类型进行推理,相比全精度Float32模型大幅减少了内存占用和计算量。
以下为训练时的部分分布图,"noise"(噪音)是后加的:

3、主要代码与逻辑
主程序采用事件驱动与轮询相结合的架构,主要包含以下几个功能模块:音频采集模块负责从I2S接口读取麦克风数据并进行预处理;推理模块调用Edge Impulse运行时执行神经网络推理;命令处理模块解析识别结果并执行相应动作;输出控制模块负责更新LED灯带、OLED显示屏和蜂鸣器的状态。
程序的核心是一个名为"capture_samples"的FreeRTOS后台任务,该任务以最高优先级运行,持续不断地从I2S接口读取音频数据。每次读取2048字节(1024个采样点)的数据后,进行4倍增益放大以提高信号强度,然后将数据写入循环缓冲区。主循环(loop函数)则等待缓冲区数据就绪标志,触发推理并处理结果。
部分模块需要进行初始,OLED使用的IIC接口,需要关联对应的引脚,使用的是现有的库文件#include ,需要进行初始化:
/* OLED配置 */
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C
#define I2C_SDA_PIN D4
#define I2C_SCL_PIN D5
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 初始化OLED显示屏
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); // SDA=4(D4), SCL=5(D5)
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println("SSD1306 allocation failed");
} else {
Serial.println("OLED Ready");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 10);
display.println("Voice Control");
display.setCursor(0, 30);
display.println("Ready!");
display.display();
delay(2000);
}
蜂鸣器使用的是PWM驱动,代码如下:
/* 蜂鸣器配置 */
#define BUZZER_PIN 9
#define BUZZER_CHANNEL 4
// 初始化蜂鸣器
ledcSetup(BUZZER_CHANNEL, 2000, 8); // PWM通道4,频率2000Hz,分辨率8位
ledcAttachPin(BUZZER_PIN, BUZZER_CHANNEL);
ledcWrite(BUZZER_CHANNEL, 0); // 初始关闭
灯带初始化如下:
/* LED灯带配置 */
#define PIN_NEOPIXEL 8 // 控制引脚
#define NUMPIXELS 10 // 灯珠数量
Adafruit_NeoPixel pixels(NUMPIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
// 初始化LED灯带
pixels.begin();
pixels.setBrightness(50); // 设置亮度0-255
pixels.clear();
pixels.show();
4、语音识别与命令处理
考虑到语音识别模型的推理延迟和用户体验,系统采用定期推理策略,每隔1秒(约16000个采样点)执行一次推理。为提高识别准确率,定义了0.8(80%)的置信度阈值,只有当识别结果的最高置信度超过该阈值时才判定为有效识别。对于"switch"词汇,由于其置信度通常较低,特意降低阈值至0.6以确保能够正常触发模式切换。
// 打印提示信息
ei_printf("请说话...\n");
bool m = microphone_inference_record();
if (!m) {
ei_printf("ERR: Failed to record audio...\n");
return;
}
signal_t signal;
signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
signal.get_data = µphone_audio_signal_get_data;
ei_impulse_result_t result = { 0 };
EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
if (r != EI_IMPULSE_OK) {
ei_printf("ERR: Failed to run classifier (%d)\n", r);
return;
}
// 只打印超过阈值的类别,并处理LED命令
bool has_detection = false;
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
if (result.classification[ix].value >= CONFIDENCE_THRESHOLD) {
ei_printf("Detected: %s (%.2f)\n", result.classification[ix].label, result.classification[ix].value);
// 处理LED命令
handle_led_command(result.classification[ix].label, result.classification[ix].value);
has_detection = true;
}
}
// 如果没有超过阈值的检测,尝试处理swtich命令(降低阈值)
if (!has_detection) {
ei_printf("No detection (max: %.2f)\n", result.classification[0].value);
// 检查最高置信度是否是 swtich(降低阈值到0.6)
if (result.classification[0].value >= 0.6 && strcmp(result.classification[0].label, "swtich") == 0) {
ei_printf("Detected (low threshold): %s (%.2f)\n", result.classification[0].label, result.classification[0].value);
handle_led_command(result.classification[0].label, result.classification[0].value);
}
}
命令处理逻辑设计如下:
当识别到"open"且当前处于关闭状态时,开启LED灯带并进入跑马灯模式;
当识别到"switch"时,在跑马灯、彩虹灯、闪烁三种模式之间循环切换;
当识别到"close"时,关闭LED灯带。
代码如下:
static void handle_led_command(const char* label, float confidence)
{
if (strcmp(label, "open") == 0) {
// 识别到open,开启显示(默认跑马灯模式)
if (led_state == LED_OFF) {
led_state = LED_MODE1_RUNNING;
running_light_pos = 0;
blink_on = true;
ei_printf("LED: Running mode\n");
beep(); // 蜂鸣器响一下
}
}
else if (strcmp(label, "swtich") == 0) {
// 识别到switch,三种模式循环切换
// 跑马灯 -> 彩虹灯 -> 闪烁 -> 跑马灯
if (led_state == LED_MODE1_RUNNING) {
led_state = LED_MODE2_RAINBOW;
ei_printf("LED: Rainbow mode\n");
beep(); // 蜂鸣器响一下
}
else if (led_state == LED_MODE2_RAINBOW) {
led_state = LED_MODE3_BLINK;
blink_on = true;
ei_printf("LED: Blink mode\n");
beep(); // 蜂鸣器响一下
}
else if (led_state == LED_MODE3_BLINK) {
led_state = LED_MODE1_RUNNING;
running_light_pos = 0;
ei_printf("LED: Running mode\n");
beep(); // 蜂鸣器响一下
}
else if (led_state == LED_OFF) {
// 如果关闭时说switch,开启跑马灯
led_state = LED_MODE1_RUNNING;
running_light_pos = 0;
ei_printf("LED: Running mode\n");
beep(); // 蜂鸣器响一下
}
}
else if (strcmp(label, "close") == 0) {
// 识别到close,关闭显示
led_state = LED_OFF;
pixels.clear();
pixels.show();
ei_printf("LED: Off\n");
beep(); // 蜂鸣器响一下
}
}
每次成功执行命令后,同步更新OLED显示屏的显示内容,并通过蜂鸣器发出提示音,代码如下:
static void update_led()
{
uint32_t now = millis();
// 间隔1秒更新
if (now - led_last_update < 1000) {
return;
}
led_last_update = now;
switch (led_state) {
case LED_OFF:
pixels.clear();
break;
case LED_MODE1_RUNNING:
// 跑马灯模式:每次只亮一个绿色灯
pixels.clear();
pixels.setPixelColor(running_light_pos, pixels.Color(0, 255, 0)); // 绿色
running_light_pos = (running_light_pos + 1) % NUMPIXELS;
break;
case LED_MODE2_RAINBOW:
// 彩虹灯模式:每个灯随机颜色
for (int i = 0; i < NUMPIXELS; i++) {
uint8_t r = random(256);
uint8_t g = random(256);
uint8_t b = random(256);
pixels.setPixelColor(i, pixels.Color(r, g, b));
}
break;
case LED_MODE3_BLINK:
// 闪烁模式:全部蓝色灯,间隔1s亮灭交替
if (blink_on) {
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 255)); // 蓝色
}
} else {
pixels.clear();
}
blink_on = !blink_on;
break;
}
pixels.show();
}
五、系统测试与功能验证
1、开发环境配置
在开始开发之前,需要正确配置开发环境。首先在计算机上安装PlatformIO Core或PlatformIO IDE插件,然后在platformio.ini配置文件中添加项目依赖库,包括Adafruit NeoPixel(RGB LED控制)、Adafruit GFX Library(图形绘制)和Adafruit SSD1306(OLED显示)。项目还配置了Edge Impulse SDK的头文件路径,确保推理引擎能够正常调用。编译环境配置完成后,将Seeed XIAO ESP32-S3 Sense通过USB-C线缆连接至计算机,使用PlatformIO的Upload功能即可将固件烧录至开发板。首次烧录时可能需要按住开发板上的BOOT按钮进入下载模式。
2、功能测试验证
系统上电后,首先初始化各个外设模块:串口通信速率设置为115200bps、LED灯带亮度设为50%、OLED屏幕显示启动画面、蜂鸣器进入待机状态。随后启动I2S音频采集和FreeRTOS后台任务,系统开始进入工作状态。测试过程中,使用串口监视器观察程序运行状态和识别结果。当用户说出"open"指令后,系统成功识别并在串口输出"Detected: open (0.85)",LED灯带随即进入跑马灯模式,OLED屏幕显示"Mode: Running",蜂鸣器发出"哔"的一声提示音。继续说出"switch"指令,灯带在跑马灯、彩虹灯、闪烁三种模式之间依次切换,OLED屏幕和蜂鸣器同步更新和响应。最后说出"close"指令,LED灯带和OLED屏幕均恢复至关闭状态。经过多次测试验证,系统对"open"和"close"指令的识别准确率较高,能够可靠地响应用户操作。"switch"指令由于需要降低阈值才能触发,实际使用中可能存在一定的误触发概率,建议在后续模型优化中增加该词汇的训练样本数量以提高识别准确率。其中最重要的内容就是AI语音的识别,通过串口打印可以有效实现逻辑上的衔接,串口打印内容如下:

实际上我们在进行效果展示的时候也是通过这个串口的窗口来把握说话的时机,尽量让其采集的是有效片段,不然很容易发声误识别的现象。
下图是部分功能页面:
关闭时:

显示模式一:

显示模式二:

六、项目总结与展望
本项目成功实现了一款基于Seeed XIAO ESP32-S3 Sense的智能语音氛围灯带系统,该系统以边缘AI技术为核心,无需联网即可完成本地语音识别和指令执行。系统集成了RGB LED灯带、OLED显示屏和蜂鸣器三大输出设备,能够根据用户语音指令实时切换显示模式,并通过视觉和听觉双重反馈确认操作执行。
从技术层面来看,本项目涉及了嵌入式系统开发、音频信号处理、边缘机器学习等多个技术领域的知识。通过本次实践,深入理解了ESP32系列芯片的开发方法、Edge Impulse平台的模型部署流程、以及各类传感器和执行器的驱动技术。