亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

组件与物料

组件 数量 备注
Arduino Nano 33 BLE 1 nRF52840 内核
MAX9814 电容麦克风模块 1 自动增益控制 (AGC)
0.91" OLED I2C 128×32 1 SSD1306 驱动
4.7nF 电容 1 RC 低通滤波截止频率用
470μF 电容 1 电源总线滤波
2kΩ 电阻 1 RC 低通滤波截止频率用

应用与服务

项目简介

功能演示

OLED 上实时显示 11 段对数分布频谱柱状图,左低频右高频,随音乐/声音动态跳动。

硬件连接

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

低频工频噪声抑制

市电 50/60Hz 耦合噪声可用法拉第笼屏蔽:电路装金属盒接地。

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

采样率与抗混叠滤波

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

Arduino 核心 analogRead() 在 Nano 33 BLE 上约 35 kSPS,奈奎斯特极限 17.5kHz。考虑 busy-wait 采样开销,保守上限 8kHz。需 RC 低通滤波器抗混叠:

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示
Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示
Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

最大采样率实测

#define ANALOG_PIN A0
#define SAMPLES 1000000.0
int newTime, analogValue;
void setup() {
  Serial.begin(9600);
  Serial.println("Sampling... please, wait.");
}
void loop() {
  newTime = micros();
  for (int i=0; i<(int)SAMPLES; i++) analogValue = analogRead(ANALOG_PIN);
  float elapsedTimePerSampleUs = (micros()-newTime)/SAMPLES;
  Serial.print("Time per sample (us): "); Serial.println(elapsedTimePerSampleUs);
  Serial.print("Max sampling freq(hz): "); Serial.println(1e6/elapsedTimePerSampleUs);
}
Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

实测 ~35 kSPS。采样代码用 micros() busy-wait 定时:

for (int i=0; i<SAMPLES; i++) {
  unsigned long newTime = micros();
  int value = analogRead(ANALOG_PIN);
  vReal[i] = value; vImag[i] = 0;
  while (micros() < (newTime + sampling_period_us)) yield();
}

显示界面设计

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

128×32 像素分 11 个频带,对数刻度模拟人耳感知。人耳 20Hz-20kHz,婴儿略高,成人上限 15-17kHz。使用第 3-13 带 (共 11 带)。

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

每柱:虚线=频带峰值,实心矩形=频带均值,单位 dB (经启发式基准归一化)。

工作流程

  1. 定时采样 1024 点 (24kHz 采样率)
  2. FFT 变频域 (去直流、汉宁窗、幅度谱)
  3. 按对数截止频率分 14 带,取 3-13 带
  4. 计算各带均值与峰值,换算 dB 绘制

麦克风模块详解 (MAX9814)

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

OLED 显示屏

128×32 白色 OLED,I2C 四线 (SDA/SCL/3.3V/GND),无 RESET 脚。需库:Adafruit_SSD1306、Adafruit_GFX。

后续优化

Nano 33 BLE 的 nRF52840 可用 PDM/更高速 ADC,后续版本将优化采样与 FFT。

代码

完整草图 (依赖 arduinoFFT、Adafruit_GFX、Adafruit_SSD1306):

/* Sound Spectrum Visualizer for Arduino Nano 33 BLE
 * @author Enrique Albertos
 * GPL v3
 */
#include "arduinoFFT.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SAMPLES 1024
#define SAMPLING_FREQ 24000
#define AMPLITUDE 100
#define FREQUENCY_BANDS 14
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define BARWIDTH 11
#define BARS 11
#define ANALOG_PIN A0
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
double vImag[SAMPLES], vReal[SAMPLES];
unsigned long sampling_period_us;
arduinoFFT fft = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);
float reference = log10(50.0);
double coutoffFrequencies[FREQUENCY_BANDS];

void setup() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) for(;;);
  display.clearDisplay(); display.display();
  display.setRotation(0); display.invertDisplay(false);
  sampling_period_us = (1.0/SAMPLING_FREQ)*1e6;
  double basePot = pow(SAMPLING_FREQ/2.0, 1.0/FREQUENCY_BANDS);
  coutoffFrequencies[0] = basePot;
  for (int i=1; i<FREQUENCY_BANDS; i++) coutoffFrequencies[i] = basePot*coutoffFrequencies[i-1];
  for (int i=0; i<BARS-1; i++)
    for (int j=0; j<SCREEN_HEIGHT; j+=4)
      display.writePixel((i+1)*BARWIDTH+2, j, SSD1306_WHITE);
  display.drawRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,SSD1306_WHITE);
}

int oldHeight[20], oldMax[20];
void loop() {
  for (int i=0; i<SAMPLES; i++) {
    unsigned long newTime = micros();
    int value = analogRead(ANALOG_PIN);
    vReal[i] = value; vImag[i] = 0;
    while (micros() < (newTime + sampling_period_us)) yield();
  }
  fft.DCRemoval(); fft.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  fft.Compute(FFT_FORWARD); fft.ComplexToMagnitude();
  double median[20]={0}, max[20]={0};
  int index=0; double hz=0, hzPerSample = (1.0*SAMPLING_FREQ)/SAMPLES;
  double sum=0; int count=0;
  for (int i=2; i<SAMPLES/2; i++) {
    count++; sum += vReal[i];
    if (vReal[i] > max[index]) max[index] = vReal[i];
    if (hz > coutoffFrequencies[index]) {
      median[index] = sum/count; sum=0; count=0; index++; max[index]=0; median[index]=0;
    }
    hz += hzPerSample;
  }
  if (sum>0) { median[index]=sum/count; }
  int bar=0;
  for (int i=FREQUENCY_BANDS-1; i>=3; i--) {
    int newHeight=0, newMax=0;
    if (median[i]>0 && max[i]>0) {
      newHeight = 20.0*(log10(median[i])-reference);
      newMax    = 20.0*(log10(max[i])-reference);
    }
    if (newHeight<0 || newMax<0) { newHeight=1; newMax=1; }
    if (newHeight>=SCREEN_HEIGHT-2) newHeight=SCREEN_HEIGHT-3;
    if (newMax>=SCREEN_HEIGHT-2) newMax=SCREEN_HEIGHT-3;
    int barX = bar*BARWIDTH+5;
    if (oldHeight[i] > newHeight)
      display.fillRect(barX, newHeight+1, 7, oldHeight[i], SSD1306_BLACK);
    if (oldMax[i] > newHeight)
      for (int j=oldMax[i]; j>newHeight; j-=2)
        display.drawFastHLine(barX, j, 7, SSD1306_BLACK);
    for (int j=newMax; j>newHeight; j-=2)
      display.drawFastHLine(barX, j, 7, SSD1306_WHITE);
    display.fillRect(barX, 1, 7, newHeight, SSD1306_WHITE);
    oldMax[i]=newMax; oldHeight[i]=newHeight; bar++;
  }
  display.drawFastHLine(0, SCREEN_HEIGHT-1, SCREEN_WIDTH, SSD1306_WHITE);
  display.display();
}

原理图

Fritzing: soundspectrumvisualizer_qLzRsVPVlc.fzz

Arduino Nano 33 BLE 声频频谱可视化:实时 OLED 声纹显示

制造工艺

  1. 用 Arduino UNO 和 OLED 显示屏制作经典 Pong 游戏:分步教程
  2. K30 CO₂ 传感器:室内空气质量实时监测
  3. 基于 1Sheeld 与 Arduino 的盲聋人士沟通辅助系统
  4. 智能存钱罐:Arduino Nano 控制硬币识别器实现余额显示
  5. Arduino + HC-05 蓝牙控制 LED:MIT App Inventor 手机 App 开发全攻略
  6. Arduino Nano + 摇杆控制双步进电机:Visuino 图形化教程
  7. 使用 Arduino Nano 33 BLE Sense 实现音频数据传输
  8. Arduino Nano 手持盖革计数器:DIY 核辐射检测仪
  9. Arduino UNO + 以太网盾板实现低成本太阳辐射测量仪(热电堆原理)
  10. 手把手打造Arduino Nano喂食机器人
  11. Arduino 实时天气时钟:OLED 显示时间、日期与温度
  12. 便携可编程口袋电源:Arduino 兼容、OLED 显示、电压电流功率三表合一