Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

RGB 32-полосный аудио-спектрум анализатор на Arduino и матрице WS2812B 8x32

Компоненты и расходные материалы

Необходимые инструменты и оборудование

О проекте

Проект

Создание RGB 32-полосного визуализатора аудиочастот (музыкального спектра) на Arduino Nano и матрице 8x32 WS2812B RGB LED.

Оригинальный проект-вдохновитель

Большое спасибо Shajeeb — автору оригинального проекта на базе матриц MAX72xx. Я лишь адаптировал часть управления матрицей под RGB WS2812B.
Оригинал: 32-Band Audio Spectrum Visualizer Analyzer

Особенности WS2812B RGB матрицы

Матрица на 5050 SMD высокой яркости потребляет >10 мА на светодиод. При максимальной яркости всех 256 LED — более 2.5 А. Необходимо внешнее питание.

Добавлен диод в разрыв +5V для возможности автономной работы Arduino от USB (когда USB отключён) и защиты Arduino от перегрузки током матрицы. Также: резистор 390 Ом в линию данных (D6 → Data In) для защиты входа матрицы от пиковых напряжений, и конденсатор 1000 мкФ 12В для стабилизации питания Arduino.

Сборка железа

Первый прототип на многоотверстной плате 4x6 см с двумя RCA-розетками (можно заменить на 3.5 мм Jack). Важно: используйте экранированный кабель для аудиовхода, чтобы избежать гудения. Соединение Arduino ↔ матрица делайте максимально коротким.

Код

База — отличная работа автора библиотеки FFT и финальная реализация Shajeeb. Добавлены две функции:

Аудио-эквалайзация

Тесты проводились со встроенной звуковой картой ПК — для улучшения АЧХ добавлен байтовый массив eq[32] — кривая эквалайзации: подавление басов, усиление высоких. Значение 100 = без изменений, <100 = подавление, >100 = усиление. Отключается флагом EQ_ON = false.

Яркость матрицы

Задана константой BRIGHTNESS = 32 (макс. 255). При >100 белый становится жёлтоватым — вероятно, нужно питать матрицу через центральные красный/чёрный провода, а не правый коннектор. На яркости 64 достаточно 1А БП, иначе нужен 2А.

Будущие обновления

Работаю над версией с библиотекой OpenMusicLabs FHT — в разы быстрее Arduino FFT. Stay tuned! :)
Простите мой английский, использовал Google Translate.

Код: Spectrum_Analyzer_WS2812B.ino

/* Copyright (c) 2019 Shajeeb TM
 * MIT License
 * WS2812B Led Matrix version by Janux
 */
#include <arduinoFFT.h>
#include <SPI.h>
#include <Adafruit_NeoPixel.h>

#define SAMPLES 64            // степень 2
#define xres 32               // столбцов на дисплее (<= SAMPLES/2)
#define yres 8                // строк на дисплее
#define ledPIN 6              // пин управления матрицей
#define NUM_LEDS (xres * yres)
#define BRIGHTNESS 32
#define buttonPin 5           // кнопка смены цветовой схемы

byte yvalue, displaycolumn, displayvalue;
int peaks[xres];
byte state = HIGH, previousState = LOW;
byte displaycolor = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 100;

double vReal[SAMPLES];
double vImag[SAMPLES];
byte data_avgs[xres];
arduinoFFT FFT = arduinoFFT();

Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUM_LEDS, ledPIN, NEO_GRB + NEO_KHZ800);

// EQ фильтр: подавление басов, усиление высоких (для встроенного звука ПК)
bool EQ_ON = true;
byte eq[32] = {50, 55, 60, 70, 75, 80, 85, 95, 100, 100, 100, 100, 100, 100, 100, 100,
               100, 100, 100, 100, 100, 100, 100, 100, 115, 125, 140, 160, 185, 200, 225, 255 };

// Цветовые схемы [схема][строка] — значения для Wheel()
byte colors[][8] = {
  {170, 160, 150, 140, 130, 120, 1, 1},
  {1, 5, 10, 15, 20, 25, 90, 90},
  {90, 85, 80, 75, 70, 65, 1, 1},
  {90, 90, 90, 30, 30, 30, 1, 1},
  {170, 160, 150, 140, 130, 120, 0, 0},  // 0 = кастомный цвет пика
  {170, 160, 150, 140, 130, 120, 1, 1},
  {170, 160, 150, 140, 130, 120, 1, 1}
};

void setup() {
  pixel.begin();
  pixel.setBrightness(BRIGHTNESS);
  // Настройка АЦП: free running mode, прескалер 32
  ADCSRA = 0b11100101;  // 0xE5
  ADMUX = 0b00000000;   // A0, внешний опорный
}

void loop() {
  // Сэмплирование
  for (int i = 0; i < SAMPLES; i++) {
    while (!(ADCSRA & 0x10));  // ждём ADIF
    ADCSRA = 0b11110101;       // сброс ADIF (0xF5)
    int value = ADC - 512;     // чтение АЦП, снятие DC смещения
    vReal[i] = value / 8;      // сжатие
    vImag[i] = 0;
  }
  
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);

  // Перераспределение FFT результата под 32 столбца
  int step = (SAMPLES / 2) / xres;
  int c = 0;
  for (int i = 0; i < (SAMPLES / 2); i += step) {
    data_avgs[c] = 0;
    for (int k = 0; k < step; k++) data_avgs[c] += vReal[i + k];
    data_avgs[c] /= step;
    c++;
  }

  // Вывод на матрицу
  for (int i = 0; i < xres; i++) {
    if (EQ_ON) data_avgs[i] = data_avgs[i] * (float)eq[i] / 100;
    data_avgs[i] = constrain(data_avgs[i], 0, 80);
    data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres);
    yvalue = data_avgs[i];
    
    peaks[i]--;  // затухание пика
    if (yvalue > peaks[i]) peaks[i] = yvalue;
    yvalue = peaks[i];
    
    displaycolumn = i; displayvalue = yvalue;
    setColumn(displaycolumn, displayvalue);
  }
  pixel.show();
  displaycolorChange();
}

// Зажигает LED столбца x до высоты y
void setColumn(byte x, byte y) {
  byte led, i;
  for (i = 0; i < yres; i++) {
    led = GetLedFromMatrix(x, i);
    if (peaks[x] > i) {
      switch (displaycolor) {
        case 4:  // кастомный цвет пика (0 в массиве)
          if (colors[displaycolor][i] > 0)
            pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
          else
            pixel.setPixelColor(led, 255, 255, 255);  // белый пик
          break;
        case 5:  // цвет по столбцу
          pixel.setPixelColor(led, Wheel(x * 16));
          break;
        case 6:  // цвет по строке
          pixel.setPixelColor(led, Wheel(i * 36));
          break;
        default:  // схемы 0-3 из массива colors
          pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
      }
    } else {
      pixel.setPixelColor(led, 0);
    }
  }
}

// Расчёт номера LED по координатам (x=0-31, y=0-7)
// Змеиная разводка, нулевой LED в правом нижнем углу (вход справа)
byte GetLedFromMatrix(byte x, byte y) {
  x = xres - x - 1;
  if (x & 0x01)  // нечётные столбцы — обратный порядок
    return ((x + 1) * yres - y - 1);
  else           // чётные — прямой
    return ((x + 1) * yres - yres + y);
}

// Смена цветовой схемы кнопкой с антидребезгом
void displaycolorChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) {
    displaycolor++;
    if (displaycolor > 6) displaycolor = 0;
    lastDebounceTime = millis();
  }
  previousState = reading;
}

// Цветовое колесо 0-255 → RGB (из Adafruit Neopixel demo)
unsigned long Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) return pixel.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  if (WheelPos < 170) { WheelPos -= 85; return pixel.Color(0, WheelPos * 3, 255 - WheelPos * 3); }
  WheelPos -= 170; return pixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

3D-модели и дополнительные файлы

Изображения схем и архив с 3D-частьми: arduino_rgb_audio_analyzer_lX4Dv4Pta2.zip

Схемы

Схемотехнический диаграмм подключения.

Производственный процесс

  1. 32-полосный Arduino аудио-спектральный анализатор — линейный и псевдологарфмический дисплей
  2. Умный датчик полива «Thirst Alert» на Arduino — DIY сигнализация засухи для растений
  3. Итальянские словесные часы на Arduino Nano, NeoPixel, LCD и RTC
  4. Надежный счетчик кВт·ч на Sigfox с Arduino MKR Fox 1200
  5. Bluetooth-монитор температуры на Arduino Nano с NTC-термистором
  6. Бесконтактный жестовый замок: APDS-9960 + Arduino для безопасного доступа
  7. Набор-компаньон для Arduino Nano — необходимые компоненты и инструменты для DIY-электроники
  8. Набор USB-MIDI адаптера для Arduino Micro / Leonardo — полный список деталей
  9. Гальванически разделённый аналоговый вход для Arduino на LM331 и оптопаре 4N25
  10. Точный тест времени реакции на Arduino UNO