2025寒假练 - 基于CrowPanel HMI开发板实现音频信号播放及分析
该项目使用了CrowPanel HMI开发板,实现了音频信号播放及分析的设计,它的主要功能为:获取PC麦克风的音频信号,通过UDP传输到CrowPanel HMI开发板上进行音频信号显示与分析。
标签
嵌入式系统
ESP32音频
CrowPanel
HMI开发板
枫雪天
更新2025-04-02
115

任务介绍

    本项目实现了硬禾科技2025寒假练CrowPanel HMI开发板的任务2,使用官方提供的CrowPanel ESP32 Display 4.3英寸HMI开发板实现了基于ESP32 UDP通信和数字信号处理的音频信号分析。

硬件平台

    首先介绍本次用到的开发板:CrowPanel ESP32 Display,这是一块基于ESP32 S3微控制器HMI触摸屏开发板,因此它的主体就是一块4.3寸的LCD屏,并且集成了比较丰富的外设接口,例如扩展GPIO、串口、TF卡槽、USB接口、喇叭以及电池接口,在软件方面,官方已经适配好了Arduino IDE、Espressif IDF、PlatformIO和MicroPython多种开发平台,上手开发会很方便。本次我会使用这块CrowPanel开发板,做一个基于ESP32 UDP通信和数字信号处理的音频信号分析实践

  • 主控设备:CrowPanel ESP32 Display开发板
    • 搭载双核Xtensa® 32位LX6微处理器
    • 集成WiFi/蓝牙无线通信模块
    • 480x272分辨率RGB显示屏
    • 电阻式触摸屏交互界面
  • 音频采集端:PC端麦克风设备
    • 16位采样精度
    • 8kHz采样频率
    • 256样本/帧的传输单元

CrowPanel_4.3_inch_display_overview_6.png

任务分析与实现

这次主办方出了三种任务,

  • 任务一是手写识别显示,在屏幕上手写数字,识别结果并在灯板上显示;
  • 任务二是音频信号播放及分析,电脑上采集音频,发送给开发板进行波形显示与信号分析;
  • 任务三是自由命题

    这次我选择了任务二

方案框图:

一、上位机采集层

  • 音频流捕获
    • 基于PyAudio库实现实时音频采集
    • 采用Int16格式原始采样数据
    • 256样本/帧的缓冲区配置
  • 数据传输模块
    • UDP协议无线传输
    • 192.168.1.7:5005目标地址配置
    • 数据归一化处理(32位浮点转换)

二、下位机处理层

  • 通信接口
    • WiFi STA模式连接
    • UDP服务端(5005端口)
    • 数据完整性校验机制
  • 信号处理核心
    • 双模式显示支持:时域波形/频域谱图
    • FFT算法实现(ArduinoFFT库)
    • 汉明窗滤波预处理
    • 动态频率范围检测(0-4kHz)
  • 人机交互界面
    • LVGL图形库驱动
    • 实时刷新图表(48ms周期)
    • 触摸按钮模式切换功能
    • 振幅/频段信息显示面板

技术亮点

  1. 实时音频处理:8kHz采样率下实现<100ms端到端延迟
  2. 双模显示系统:一键切换时域波形与频域谱图
  3. 动态频率检测:自动识别有效频段范围
  4. 多任务架构:FreeRTOS实现显示刷新与数据处理的任务分离
  5. 自适应缩放:根据信号强度动态调整显示范围

代码详解

下位机整体软件流程图:


本次项目涉及到信号采集、处理与显示几个关键部分,接下来结合相关代码来进行讲解


一、信号采集模块(Upper.py)

def audio_callback(in_data, frame_count, time_info, status):
audio_data = np.frombuffer(in_data, dtype=np.int16)
audio_data = audio_data.astype(np.float32) / 32768.0 # 归一化处理
sock.sendto(audio_data.tobytes(), (UDP_IP, UDP_PORT))
return (in_data, pyaudio.paContinue)
  1. 采集参数配置
  • 采样格式:16位整型(paInt16)
  • 采样率:8kHz(满足语音频段需求)
  • 帧缓冲区:256样本/帧(平衡实时性与延迟)
  • 通道数:单声道(CHANNELS=1)
  1. 数据处理流程
  • 类型转换:将原始int16数据转换为float32
  • 归一化处理:除以32768.0映射到[-1,1]范围
  • 网络封装:通过tobytes()转换为二进制流
  1. 传输协议设计
  • UDP协议:采用无连接传输降低延迟
  • 目标地址:192.168.1.7:5005(ESP32接收端)
  • 数据包大小:256

二、信号处理模块(main.cpp)

1. 数据接收层

int packetSize = Udp.parsePacket();
if (packetSize == sizeof(audioBuffer)) {
Udp.read((char*)audioBuffer, sizeof(audioBuffer));
}
  • 完整性校验:验证数据包长度是否为256*4=1024字节
  • 错误处理:打印长度不匹配警告信息
  • 缓冲区管理:使用全局audioBuffer数组存储浮点数据

2. FFT处理核心

cpp// 应用汉明窗口
FFT.windowing(vReal, 256, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
// 计算FFT
FFT.compute(vReal, vImag, 256, FFT_FORWARD);
// 计算幅度谱
FFT.complexToMagnitude(vReal, vImag, 256);

关键技术点:

  • 窗函数:采用汉明窗减少频谱泄漏
  • 复数处理:分离实部虚部进行计算
  • 频率分辨率:8000/256=31.25Hz
  • 有效频段:仅显示0-4kHz(128个频点)

3. 动态频率检测

for (int i = 0; i < 128; i++) {
if (vReal[i] > threshold) {
// 寻找最大/最小有效幅度
}
}
double frequencyResolution = samplingFrequency / 256.0;
  • 噪声阈值:设定2.0幅度阈值过滤背景噪声
  • 极值追踪:记录最大/最小幅度对应的频点
  • 频率计算:索引值×31.25Hz得到实际频率

三、显示模块设计

1. 图形框架初始化

lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, 480*272/8);
lv_disp_drv_register(&disp_drv);
lv_chart_create(lv_scr_act());
  • 显示缓冲:分配480*272/8≈16KB显存
  • 刷新模式:LV_CHART_UPDATE_MODE_SHIFT(滚动显示)
  • 坐标系:Y轴动态调整范围(波形模式±1000,频谱模式0-1000)

2. 双模式显示控制

void btn_event_cb(lv_event_t * e) {
displaySpectrum = !displaySpectrum;
lv_label_set_text(info_label, ...);
}
  • 模式切换:通过触摸按钮触发displaySpectrum标志
  • 视图重构:
    lv_chart_set_point_count(chart, displaySpectrum?128:256);
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, ...);

3. 实时渲染优化

xTaskCreatePinnedToCore(lvgl_task, "LVGL Task", 4096, NULL, 1, NULL, 0);
void lvgl_task() {
lv_timer_handler();
vTaskDelay(48); // 约20FPS
}
  • 多核架构:显示任务运行在核心0,数据处理在核心1
  • 刷新周期:48ms(符合人眼视觉暂留特性)
  • 数据同步:通过audioBufferMutex信号量保护共享缓冲

四、系统性能优化

  1. 内存管理
  • 静态分配:预定义audioBuffer[256]避免动态分配
  • 数据类型:采用float32平衡精度与计算效率
  1. 实时性保障
  • UDP协议:无连接特性降低传输延迟
  • FFT优化:使用ArduinoFFT库的模板化实现
  • 任务优先级:LVGL任务设置为较高优先级(1级)
  1. 用户体验增强
  • 自动缩放:根据信号幅度动态调整Y轴范围
  • 视觉反馈:信息面板显示实时幅值/频率范围
  • 触摸响应:非阻塞式事件处理(LV_EVENT_CLICKED)


上位机整体软件流程图:

效果展示

音频波形显示

时域波形

WIN_20250309_22_09_56_Pro.jpg

频域波形

WIN_20250309_22_16_30_Pro.jpg

遇到的难题与解决办法

数据包较大时数据接收不到

当音频数据包超过1024字节时,下位机出现以下异常:

  1. 数据接收不完整(payload长度不匹配)
  2. 系统日志提示"Read mismatch"错误

原因分析

  1. UDP分片丢失
    • ESP32默认MTU为1500字节
    • 实际有效载荷:1472字节(扣除IP/UDP头)
    • 原始数据包大小:256采样点 × 4字节 = 1024字节(接近临界值)
  2. WiFi堆栈限制
    // 原始接收代码
    int n = Udp.read((char*)audioBuffer, sizeof(audioBuffer));
    // 当网络波动时可能无法完整读取

因此需要调整UDP参数与缓冲区大小,实现完整的数据接收。同时为了提高响应的实时性,尽量使用点数较低的FFT计算(本次使用256).

活动感想

本项目完整实现了从音频采集到频谱分析的全链路开发,让我深入实践了嵌入式系统中的实时信号处理技术。通过UDP协议优化和多线程优化,锻炼了在资源受限环境下开发实时系统的能力。特别感谢硬禾科技提供的高质量开发平台,其完善的周边生态显著降低了嵌入式图形界面开发的门槛。

    感谢硬禾学堂举办的寒假练活动,祝硬禾的活动越办越好!

附件下载
源代码.zip
团队介绍
个人
团队成员
枫雪天
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号