2026寒假练-基于小脚丫FPGA实现基于麦克风的实时音量表与频谱显示
基于小脚丫 FPGA (MAX10-10M02) 的实时音量表与频谱分析仪项目报告
1. 所选任务介绍
本项目选自 2026 年寒假电赛训练营 中的 “基于麦克风的实时音量表与频谱显示” 任务。
任务核心要求:
利用 FPGA 电赛训练套件(本方案采用 Altera MAX10-10M02 小脚丫核心板)配合 麦克风放大模块,构建一个完整的音频信号处理系统。
- 信号采集:ADC 采样率设定为 8–20 kHz,由 FPGA 产生采样时钟。
- 预处理:实现直流分量去除、数字增益控制及简单的自动增益/滤波处理。
- 时域分析:计算短时包络作为音量值,驱动板载 LED 条形图指示灯。
- 频域分析:实现 4 个频段的能量分析(本方案采用 Goertzel 算法 替代 FFT 以节省资源),并在 OLED 上绘制频谱柱状图。
- 人机交互:通过按键切换“音量/频谱”显示模式,利用旋转编码器实时调节增益与包络衰减时间常数。
2. 项目介绍
本系统设计了一个轻量级、高实时性的音频可视化工具。针对 MAX10-10M02 逻辑资源有限的特点,系统摒弃了资源消耗巨大的 FFT 算法,转而采用 串行 Goertzel 算法 进行特定频点能量检测,并结合 IIR 高通滤波 与 峰值保持包络检波 技术,实现了在低逻辑占用下的高性能音频分析。
系统工作流程:
- 采集:FPGA 直接驱动外部 ADC 芯片(3PA1030),以 8kHz 采样率获取音频数据。
- 处理:数据经过直流去除、数字增益放大后,分为两路并行处理:
- 音量路:进行全波整流、峰值保持与动态衰减,生成音量包络值。
- 频谱路:通过状态机串行执行 4 次 Goertzel 迭代,分别计算 800Hz、900Hz、1000Hz、1100Hz 四个频点的能量功率。
- 显示:
- 音量模式:板载 10 颗 LED 根据包络值点亮形成条形图,数码管显示当前参数。
- 频谱模式:OLED 屏幕绘制 4 根动态柱状图,高度对应各频段能量。
- 交互:旋转编码器可实时调节“数字增益”和“包络衰减步长”,按键切换显示模式。
3. 硬件介绍
本项目基于 小脚丫 FPGA 电赛训练套件 (Altera-MAX10-10M02) 构建,具体硬件配置如下:
硬件模块 | 型号/规格 | 作用说明 |
|---|---|---|
FPGA 核心板 | Altera MAX10-10M02 | 主控芯片,包含 10K LEs,内置 PLL,负责所有逻辑控制、DSP 运算及外设驱动。 |
麦克风放大模块 | 配套驻极体麦克风 + 运放电路 | 将微弱声音信号放大至 0-3.3V 范围,输出 |
ADC 模块 | 3PA1030 (板载/扩展) | 10 位精度 ADC,由 FPGA 提供 CLK,输出 10bit 并行数据 ( |
OLED 显示屏 | 0.96 寸 SSD1306 (SPI 接口) | 用于显示 4 频段频谱柱状图,分辨率 128x64。 |
LED 指示灯 | 板载 10x 单色 LED + RGB LED | 单色 LED 组成音量条形图。 |
数码管 | 2 位 7 段数码管 | 显示当前调节的参数值(增益或衰减步长)。 |
输入控制 | 旋转编码器 (EC11) + 独立按键 | 编码器用于无级调节参数;按键用于模式切换及快速增减。 |
拨码开关 | 4 位 DIP Switch | 预留功能,可用于静态配置或调试模式选择。 |
4. 方案框图和项目设计思路
4.1 系统方案框图

4.2 设计思路详解
- ADC 驱动与时钟管理
- 使用参数化分频模块
clk_divider_param将系统时钟分频产生 8kHz 采样时钟,直接驱动 ADC 的CLK引脚。 - ADC 数据在时钟上升沿锁存,并通过
data_valid信号同步下游模块,确保时序一致。
- 使用参数化分频模块
- 信号预处理 (DC Removal & Gain)
- 去直流:采用一阶 IIR 高通滤波器 (
iir模块)。利用移位操作替代乘法实现低通平均,有效滤除麦克风偏置电压。 - 增益控制:将去直流后的有符号数与设定的
gain(Q0.8 定点格式) 相乘,实现 0~255/256 倍的数字放大,并进行饱和限幅防止溢出。
- 去直流:采用一阶 IIR 高通滤波器 (
- 音量包络提取
- 整流:对信号取绝对值。
- 峰值保持:若当前值大于保持值,立即更新(快升);否则按
decay_step线性递减(慢降)。 - 衰减分频:引入
decay_div参数,控制衰减发生的频率。只有计数器达到阈值时才执行减法,从而实现平滑的视觉回落效果,避免 LED 高频闪烁。 - 映射:将包络值线性映射到 0-8 区间,驱动 LED 。
- 频谱分析 (Goertzel 算法)
- 算法选择:由于只需检测 4 个频点,使用 Goertzel 算法比 FFT 更高效,且无需存储大量数据。
- 串行复用:设计一个状态机 (
goertzel模块),在 4 个时间段内分别对同一组采样数据流进行 800Hz, 900Hz, 1000Hz, 1100Hz 的迭代计算。 - 资源优化:共用一套乘法器和延迟寄存器,仅在状态切换时加载不同的系数 ,极大节省了 MAX10 的逻辑资源。
- 功率计算:迭代结束后计算 ,并缩放至 0-63 供 OLED 显示。
- 显示与人机交互
- OLED 驱动:编写 SPI 协议状态机,初始化 SSD1306,并在页地址模式下逐列写入像素数据。根据 4 个频段的能量值动态生成每列的像素掩码,绘制矩形柱状图。
- 参数调节:
param_control_demo模块检测编码器脉冲,切换mode_sel状态,分别修改gain或decay_step寄存器,并将数值实时显示在数码管上。
5. 调试软件及使用的编程语言说明
5.1 开发环境
- IDE:Intel Quartus Prime Lite Edition (适配 MAX10 系列)。
- 仿真工具:ModelSim-Altera (用于验证 Goertzel 算法收敛性及滤波器频率响应)。
- 在线调试:DSLogic逻辑分析仪 (抓取 ADC 原始波形、包络曲线及状态机跳转信号)。
- 编程语言:Verilog HDL (IEEE 1364-2001/2005 标准)。
5.2 软件流程图描述
- 系统复位:初始化所有寄存器,OLED 清屏,增益设为默认值。
- 主循环 (基于采样时钟 8kHz):
- Step 1: 读取 ADC 数据。
- Step 2: 执行 IIR 滤波去除直流。
- Step 3: 应用数字增益。
- Step 4 (并行处理):
- 分支 A (音量): 整流 -> 峰值保持 (受 decay_div 控制) -> 更新 LED状态。
- 分支 B (频谱): Goertzel 状态机推进 (IDLE -> CALC_800 -> ... -> OUTPUT) -> 更新频谱能量值。
- Step 5: 扫描编码器/按键 -> 更新参数寄存器 -> 刷新数码管显示。
- OLED 刷新循环 (独立高速时钟):
- 不断重绘屏幕,根据最新的频谱能量值生成像素数据并通过 SPI 发送,保证显示无闪烁。
5.3 关键代码介绍
A. 核心算法:Goertzel 串行引擎
该模块通过状态机复用资源,依次计算 4 个频点功率,显著节省 DSP 资源。
// 状态机核心逻辑片段 (goertzel.v)
CALC_800: begin
current_coeff <= COEFF_800; // 加载 800Hz 系数 (定点数)
// 迭代公式: Q0 = x[n] + 2*cos(w)*Q1 - Q2
mult_full = $signed(current_coeff) * $signed(Q1);
Q0 = mult_full[27:8] - Q2 + sample_data; // 截取高位保留精度
if (cnt == N-1) begin
power_800_temp <= compute_power(Q0, Q1, current_coeff); // 计算最终功率
cnt <= 0;
next_state <= CALC_900; // 切换至下一频点
end else begin
Q2 <= Q1; Q1 <= Q0; cnt <= cnt + 1;
end
end
B. 包络检波与衰减控制
实现了可配置的衰减速度,使音量条反应灵敏但回落平滑。
// 峰值保持与分频衰减 (dc_data.v)
if (abs_val_scaled > env_curr) begin
env_curr <= abs_val_scaled; // 快速上升:立即跟踪峰值
end else begin
// 慢速下降:仅当计数器达到阈值时才执行衰减
if (decay_cnt == decay_div) begin
env_curr <= (env_curr > decay_step) ? (env_curr - decay_step) : 20'd0;
end
end
C. OLED 像素级绘图
直接在 SPI 发送阶段根据列坐标和高度阈值生成像素数据,无需庞大的 Frame Buffer 显存。
// 动态生成列数据 (oled_rect_display.v)
if(xpos_count >= 8'd10 && xpos_count <= 8'd25) begin // 第一根柱子区域
for(bit_idx = 0; bit_idx < 8; bit_idx = bit_idx + 1) begin
pixel_row = pixel_row_base - bit_idx;
// 判断当前像素行是否在高度范围内 (rect1_h)
if(pixel_row >= (63 - rect1_h[5:0]))
pixel_data[bit_idx] = 1'b1; // 点亮像素
end
end
OLED_data = pixel_data; // 发送生成的字节
6. 功能展示图及说明
- 实物连接图
- FPGA资源占用报告
- 仿真展示
7. 项目中遇到的难题及解决方法
- 难题一:Goertzel 算法系数量化误差导致频率响应偏差。
- 现象:初期测试发现对目标频率响应不明显,频点漂移。
- 解决:采用 定点数表示法 (Q8.8),将系数左移 8 位存储,在乘法运算后统一右移还原,显著提高了频率选择性和计算精度。
- 难题二:OLED 显示闪烁且占用过多时序资源。
- 现象:直接在音频采样时钟 (8kHz) 下驱动 OLED SPI,导致刷屏率低,画面抖动。
- 原因:音频采样率远低于 OLED 所需刷新率,且 SPI 时序占用了大量状态机周期。
- 解决:将 OLED 驱动逻辑独立出来,使用更高的分频时钟(如 1MHz)运行独立的 SPI 状态机,并采用“页地址模式”连续发送数据,减少命令交互次数,实现流畅刷新。
- 难题三:包络衰减速度难以兼顾灵敏度和稳定性。
- 现象:衰减太快导致 LED 闪烁,太慢则声音停止后灯很久不灭。
- 解决:引入 衰减分频器 (
decay_div) 和 步进值 (decay_step) 双重控制。用户可通过编码器调节这两个参数,找到最佳视觉体验点,实现了“快升慢降”的专业电平表效果。
- 难题四:MAX10 资源紧张,多路乘法器导致编译失败。
- 现象:同时实例化增益乘法、Goertzel 乘法时提示 Logic Elements 不足。
- 解决:将 Goertzel 的 4 路计算改为 时间复用 (串行) 架构,只保留一个乘法器模块,通过状态机轮流服务 4 个频点,资源占用降低,成功适配 MAX10-10M02。
8. 心得体会
通过本次基于 MAX10-10M02 的音频分析仪设计,深刻理解了 FPGA 并行处理 与 资源权衡 的核心思想。
- 算法适配硬件:在资源有限的嵌入式 FPGA 上,盲目套用标准算法(如 FFT)往往行不通。通过改用 Goertzel 算法和串行架构,用最少的逻辑单元实现了预期的频谱分析功能,明白了“合适的算法才是最好的算法”。
- 定点运算的艺术:在没有硬核 DSP 的芯片上,通过移位和加减法模拟浮点运算,不仅节省了资源,更加深了对数字信号的量化、精度损失的认识。
- 系统级调试能力:从模拟前端噪声抑制到数字滤波参数整定,再到人机交互的平滑度调整,整个系统是一个有机整体。逻辑分析仪的使用能够“看见”信号在芯片内部的流动,极大地提高了调试效率。
- 工程实践价值:本项目完整覆盖了信号链的各个环节(采集 - 处理 - 显示 - 交互),是电赛备战的绝佳练手项目。它不仅锻炼了代码能力,更培养了面对硬件限制时的创新解决问题的能力。


