回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【FireBeetle 2 ESP32-C5】幻彩拾音灯 简单

头像 无垠的广袤 2025.10.07 4 0

【FireBeetle 2 ESP32-C5】幻彩拾音灯

本文介绍了 FireBeetle 2 ESP32-C5 开发套件结合 WiFi 网络和 UDP 协议实现 WS2812 彩色拾音灯的项目设计。

项目介绍

电脑主机运行 Python 实现实时音频数据提取,结合局域网 UDP 协议,将转换的音频数据发送至 ESP32-C5 开发板;开发板通过 WiFi 接收频谱数据并控制 WS2812 灯带,进而实现音乐律动的彩色灯光效果。

准备工作:包括开发板固件烧录、Thonny IDE 安装等;

流程图:包括开发板代码和网页服务器代码对应的流程图;

工程代码:包括开发板板端执行代码、主机音频采集 Python 代码等;

工程测试:包括程序运行、发送端和接收端数据传输、颜色和亮度控制、效果检验等;

准备工作

开发板烧录 MicroPython 固件;

电脑安装 Thonny IDE 软件,用以调试板端程序;

详见:【FireBeetle 2 ESP32-C5】 介绍、固件上传、工程测试 DF创客社区 .

硬件连接

开发板与 WS2812 模块的接线方式如下

ESP32-C5WS2812Note
Pin 2DINSignal
3.3VVCCPower
GNDGNDGround

实物连接

ws2812_board_connect.jpg

流程图

flowchart_udp_ws2812_sound.png

工程代码

包括 ESP32-C5 代码、电脑主机端 Python 代码。

 

ESP32-C5 代码

打开 Thonny IDE 软件,新建 ws2812_udp_spk.py 工程文件,并添加如下代码

 

import network
import socket
import json
import neopixel
import machine
import time
import uselect

# Wi-Fi配置
WIFI_SSID = 'xxx'
WIFI_PASSWORD = 'xxx'

# LED配置
LED_PIN = 2  # 根据实际连接调整
LED_COUNT = 8  # LED数量,与频谱频段数对应
UDP_PORT = 8888

class MusicLEDController:
    def __init__(self):
        # 初始化Wi-Fi
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)
        
        # 初始化NeoPixel
        self.np = neopixel.NeoPixel(machine.Pin(LED_PIN), LED_COUNT)
        
        # UDP socket
        self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.udp_socket.bind(('0.0.0.0', UDP_PORT))
        
        # 设置socket为非阻塞模式
        self.udp_socket.setblocking(False)
        
        # 创建select对象用于非阻塞接收
        self.poll = uselect.poll()
        self.poll.register(self.udp_socket, uselect.POLLIN)
        
    def connect_wifi(self):
        """连接Wi-Fi"""
        if not self.wlan.isconnected():
            print('连接Wi-Fi...')
            self.wlan.connect(WIFI_SSID, WIFI_PASSWORD)
            while not self.wlan.isconnected():
                time.sleep(1)
        print('网络配置:', self.wlan.ifconfig())
    
    def spectrum_to_color(self, value, max_value=255):
        """将频谱值转换为颜色"""
        # 根据频谱值生成从蓝色到红色的渐变
        if value < max_value // 3:
            # 蓝色到绿色
            r = 0
            g = int(255 * value / (max_value // 3))
            b = 255 - g
        elif value < 2 * max_value // 3:
            # 绿色到黄色
            r = int(255 * (value - max_value // 3) / (max_value // 3))
            g = 255
            b = 0
        else:
            # 黄色到红色
            r = 255
            g = 255 - int(255 * (value - 2 * max_value // 3) / (max_value // 3))
            b = 0
        
        return (r, g, b)
    
    def update_leds(self, spectrum):
        """根据频谱更新LED"""
        for i in range(min(len(spectrum), LED_COUNT)):
            color = self.spectrum_to_color(spectrum[i])
            self.np[i] = color
        self.np.write()
    
    def run(self):
        """主循环"""
        self.connect_wifi()
        print("等待频谱数据...")
        
        last_activity_time = time.time()
        
        while True:
            try:
                # 检查是否有数据可读(非阻塞)
                events = self.poll.poll(10)  # 10ms超时
                
                if events:
                    # 有数据到达,接收UDP数据
                    data, addr = self.udp_socket.recvfrom(1024)
                    last_activity_time = time.time()
                    
                    # 解析JSON数据
                    try:
                        message = json.loads(data.decode('utf-8'))
                        spectrum = message['spectrum']
                        
                        # 更新LED
                        self.update_leds(spectrum)
                        print("更新LED:", spectrum)  # 调试输出
                        
                    except Exception as e:
                        print("数据解析错误:", e)
                
                # 如果超过5秒没有数据,关闭所有LED
                if time.time() - last_activity_time > 5:
                    self.np.fill((0, 0, 0))
                    self.np.write()
                    
            except Exception as e:
                print("错误:", e)
                time.sleep(0.1)

# 启动控制器
controller = MusicLEDController()
controller.run()

保存代码,并上传至 ESP32-C5 开发板根目录。

 

音频转发

电脑主机新建 udp_sound_server.py 文件,添加如下代码

 

# udp_sound_server.py
import socket, pyaudio, numpy as np, struct, time

CHUNK      = 1024          # 20 ms @ 48 kHz ≈ 960,取 1024 方便 FFT
RATE       = 48000
CHANNELS   = 2
FORMAT     = pyaudio.paInt16
UDP_IP     = "192.168.1.101"   # ESP32-C5 地址
UDP_PORT   = 4210

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
pa   = pyaudio.PyAudio()
# 打印所有音频设备
for i in range(pa.get_device_count()):
    info = pa.get_device_info_by_index(i)
    print(i, info['name'], info['maxInputChannels'])

stream = pa.open(format=FORMAT, channels=CHANNELS, rate=RATE,
                 input=True, frames_per_buffer=CHUNK)

print("→ 发送中… Ctrl-C 退出")
try:
    while True:
        data = stream.read(CHUNK, exception_on_overflow=False)
        samples = np.frombuffer(data, dtype=np.int16).astype(np.float32)
        # 双声道转单声道
        samples = samples.reshape(-1, CHANNELS).mean(axis=1)
        rms = np.sqrt(np.mean(samples**2))
        vol = min(255, int(rms / 20000 * 255))   # 经验系数,可再调
        sock.sendto(struct.pack("B", vol), (UDP_IP, UDP_PORT))
        time.sleep(0.02)          # 约 50 包/秒
except KeyboardInterrupt:
    pass
finally:
    stream.stop_stream(); stream.close(); pa.terminate()

 

保存代码;

 

工程测试

包括程序运行和效果演示、颜色和亮度控制等。

运行程序

打开 Thonny IDE 并连接开发板;

运行 ws2812_udp_spk.py 程序,终端输出 WiFi 连接并输出开发板 ip 地址;

UDP_C5_run.jpg

在电脑服务器端打开终端,进入目标文件所在路径,运行 python UDP_server.py

UDP_server_run.jpg

程序自动检测并获取电脑主机实时音频数据,并通过 UDP 转发至开发板对应的 ip 端口;

 

效果演示

运行开发板程序和主机 UDP 音频采集、转换和转发程序后,可在 CMD 终端和 Shell 终端监测数据流传输情况;

UDP_sound_run.gif

同时 ESP32-C5 控制 GPIO 连接的 WS2812 模块,颜色和亮度跟随 UDP 端口接收到的 8 段音频数据律动;

灯光效果

 

udp_sound_ws2812.gif

 

总结

本文介绍了 FireBeetle 2 ESP32-C5 开发套件结合 WiFi 网络和 UDP 协议实现 WS2812 彩色拾音灯的项目设计。包括主机端 Python 代码、板端执行代码、工程测试流程、控制效果演示等,为相关产品的开发设计和快速应用提供了参考。

评论

user-avatar