Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

FHT Audio Spectrum Visualizer – Beeindruckende LED-Audio-Anzeige bauen

Komponenten und Zubehör

Arduino Nano R3 × 1
WS2812B 8x32 RGB LED-Matrix × 1
Widerstand 4,75 kΩ × 3
Widerstand 100 kΩ × 2
Widerstand 10 kΩ × 2
Durchgangswiderstand 390 Ω × 1
1N4007 Diode (1N4004 funktioniert auch) × 1
Kondensator 100 nF × 2
Kondensator 1000 µF × 1
Taster 12 mm (oder zwei Panel-Taster für Gehäuseeinbau) × 2
4x6 cm Lochrasterplatine × 1
PCB Stereo RCA Buchse × 1

Benötigte Werkzeuge und Maschinen

Über dieses Projekt

Die Arduino FHT-Bibliothek

FHT (Fast Hartley Transform) erledigt dieselbe Aufgabe wie die bekanntere FFT (Fast Fourier Transform), arbeitet aber ausschließlich mit reellen Daten, während FFT komplexe Daten benötigt. Dadurch benötigt FHT nur halb so viel Rechenleistung und Speicher.

Die Bibliothek nutzt ein einzelnes Array für die Datenerfassung statt zweier (reell/imaginär), vereinfacht komplexe Mathematik und vermeidet Schleifen mit komplexen Gleitkomma-Logarithmen durch Lookup-Tabellen.

Nachteil: Es werden nur halb so viele Werte wie die Array-Größe zurückgegeben, was zu Auflösungsverlust an den Enden des Audiobereichs führt. Für ein simples Gadget, das LEDs im Musikrhythmus blinken lässt, ist die Präzision jedoch ausreichend.

Details zur FHT-Bibliothek finden Sie auf der Open Music Lab Website mit Dokumentation, Funktionserklärungen und Arduino-Beispielen.

Die FHT-Bibliothek ist so schnell, dass ein Delay im Code nötig war, um Flackern zu reduzieren. Das Ergebnis ist deutlich flüssiger und reaktionsschneller als die FFT-Version. Der geringere Ressourcenverbrauch erlaubte zusätzliche Funktionen.

Die neue Version

Das Projekt entspricht der Vorversion; wer diese schon gebaut hat, muss nur einen Taster, einen 10 kΩ Widerstand hinzufügen und den Code aktualisieren.

Zusätzliche Funktionen dieser Version:

Code

FHT Code Version (Arduino)

/* Copyright (c) 2020 Janux
   MIT License ... (gekürzt) */
#define LIN_OUT 1
#define FHT_N 128
#include <FHT.h>

#define xres 32
#define yres 8
#define ledPIN 6
#define NUM_LEDS (xres * yres)
#include <Adafruit_NeoPixel.h>

#define colorPIN 5
#define brightnessPIN 10
byte displaycolor = 0;
byte brightness = 1;

#include <EEPROM.h>
#define CONFIG_START 32
#define CONFIG_VERSION "VER01"

typedef struct {
  char version[6];
  byte displaycolor;
  byte brightness;
} configuration_type;

configuration_type CONFIGURATION = { CONFIG_VERSION, displaycolor, brightness };

byte yvalue;
int peaks[xres];
byte state = HIGH;
byte previousState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 100;
byte data_avgs[xres];

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

byte eq[32] = { 60,65,70,75,80,85,90,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,115,125,140,160,185,200,200,200 };
bool EQ_ON = true;

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,110,0}
};

byte charBitmap[] = {
  0x1C,0x10,0x10,0x10,0x10,0x1C,0x08,0x18,0x08,0x08,0x08,0x1C,
  0x0C,0x12,0x04,0x08,0x10,0x1E,0x0C,0x12,0x02,0x06,0x12,0x0C,
  0x10,0x10,0x10,0x14,0x1E,0x04,0x1E,0x10,0x1E,0x02,0x12,0x0C,
  0x1E,0x10,0x10,0x1E,0x12,0x1E,0x1E,0x02,0x04,0x08,0x08,0x08,
  0x0C,0x12,0x0C,0x12,0x12,0x0C,0x1C,0x12,0x1C,0x12,0x12,0x1C
};

void setup() {
  pixel.begin();
  ADCSRA = 0b11100101; // ADC free running, Prescaler 32
  ADMUX = 0b00000000;  // Pin A0, externe Referenz
  if (loadConfig()) {
    displaycolor = CONFIGURATION.displaycolor;
    brightness = CONFIGURATION.brightness;
  }
  pixel.setBrightness(brightness * 24 + 8);
  showSettings(3, true);
}

void loop() {
  while (1) {
    Sampling();
    RearrangeFHT();
    SendToDisplay();
    colorChange();
    brightnessChange();
    delay(10);
  }
}

void Sampling() {
  for (int i = 0; i < FHT_N; i++) {
    while (!(ADCSRA & 0x10));
    ADCSRA = 0b11110101;
    byte m = ADCL;
    byte j = ADCH;
    int value = (j << 8) | m;
    value -= 0x0200;
    value <<= 6;
    fht_input[i] = value / 8;
  }
  fht_window();
  fht_reorder();
  fht_run();
  fht_mag_lin();
}

void RearrangeFHT() {
  int step = (FHT_N / 2) / xres;
  int c = 0;
  for (int i = 0; i < (FHT_N / 2); i += step) {
    data_avgs[c] = 0;
    for (int k = 0; k < step; k++) {
      data_avgs[c] += fht_lin_out[i + k];
    }
    data_avgs[c] /= step;
    c++;
  }
}

void SendToDisplay() {
  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];
    setColumn(i, yvalue);
  }
  pixel.show();
}

void setColumn(byte x, byte y) {
  int led, i;
  for (i = 0; i < yres; i++) {
    led = GetLedFromMatrix(x, i);
    if (peaks[x] > i) {
      switch (displaycolor) {
        case 4:
          if (colors[displaycolor][i] == 0)
            pixel.setPixelColor(led, 255, 255, 255);
          else
            pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
          break;
        case 5:
          pixel.setPixelColor(led, Wheel(x * 16));
          break;
        case 6:
          pixel.setPixelColor(led, Wheel(i * y * 3));
          break;
        case 7:
          if (i < yres - 2) {
            if (x & 0x01) pixel.setPixelColor(led, 0, 0, 255);
            else pixel.setPixelColor(led, 255, 0, 0);
          } else {
            pixel.setPixelColor(led, 255, 255, 255);
          }
          break;
        default:
          pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
      }
    } else {
      pixel.setPixelColor(led, pixel.Color(0, 0, 0));
    }
  }
}

int GetLedFromMatrix(byte x, byte y) {
  int led;
  x = xres - x - 1;
  if (x & 0x01) led = ((x + 1) * yres - y - 1);
  else led = ((x + 1) * yres - yres + y);
  return constrain(led, 0, NUM_LEDS);
}

void colorChange() {
  int reading = digitalRead(colorPIN);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) {
    displaycolor++;
    if (displaycolor > 7) displaycolor = 0;
    showSettings(1, true);
    saveConfig();
    lastDebounceTime = millis();
  }
  previousState = reading;
}

void brightnessChange() {
  int reading = digitalRead(brightnessPIN);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) {
    brightness++;
    if (brightness > 7) brightness = 0;
    pixel.setBrightness(brightness * 24 + 8);
    showSettings(2, true);
    saveConfig();
    lastDebounceTime = millis();
  }
  previousState = reading;
}

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);
}

int loadConfig() {
  if (EEPROM.read(CONFIG_START + 0) == CONFIG_VERSION[0] &&
      EEPROM.read(CONFIG_START + 1) == CONFIG_VERSION[1] &&
      EEPROM.read(CONFIG_START + 2) == CONFIG_VERSION[2] &&
      EEPROM.read(CONFIG_START + 3) == CONFIG_VERSION[3] &&
      EEPROM.read(CONFIG_START + 4) == CONFIG_VERSION[4]) {
    for (unsigned int i = 0; i < sizeof(CONFIGURATION); i++)
      *((char*)&CONFIGURATION + i) = EEPROM.read(CONFIG_START + i);
    return 1;
  }
  return 0;
}

void saveConfig() {
  CONFIGURATION.displaycolor = displaycolor;
  CONFIGURATION.brightness = brightness;
  for (unsigned int i = 0; i < sizeof(CONFIGURATION); i++)
    EEPROM.write(CONFIG_START + i, *((char*)&CONFIGURATION + i));
}

void showSettings(byte num, bool show) {
  if (show) {
    pixel.clear();
    if (num == 1 || num == 3) {
      drawChar(0, 0); drawChar(displaycolor + 1, 5);
    }
    if (num == 2 || num == 3) {
      drawChar(9, xres - 9); drawChar(brightness + 1, xres - 4);
    }
    delay(1000);
    pixel.clear();
  }
}

void drawChar(byte val, byte pos) {
  for (int x = 4; x >= 0; x--) {
    for (int y = 5; y >= 0; y--) {
      if ((charBitmap[val * 6 + 5 - y] >> x) & 0x01) {
        pixel.setPixelColor(GetLedFromMatrix(4 - x + pos, y + 1), Wheel((pos > 10) * 170));
        pixel.show();
      }
    }
  }
}
// by Janux®, Last version 28/06/2020.

Schaltpläne

FHT Audio Spectrum Visualizer – Beeindruckende LED-Audio-Anzeige bauen
FHT Audio Spectrum Visualizer – Beeindruckende LED-Audio-Anzeige bauen

Herstellungsprozess

  1. 32-Band Arduino Audio-Spektrumanalysator – Linear & Pseudo-Log Darstellung
  2. Smart Thirst Alert: DIY Pflanzen-Alarm für optimale Bewässerung
  3. Italienische Word Clock mit Arduino Nano, NeoPixel, LCD & RTC
  4. Zuverlässiger Sigfox-kWh-Zähler mit Arduino MKR Fox 1200
  5. Bluetooth-Temperaturmonitor mit Arduino Nano
  6. Berührungsloses Gesten-Schloss: Sicherer Zugang mit APDS-9960 & Arduino
  7. Arduino Nano Begleiter-Set – Essentielle Bauteile & Werkzeuge für DIY-Elektronik
  8. USB-MIDI-Adapter für Arduino Micro / Leonardo – Komplettes Bauteil-Kit & Code
  9. Isolierter Analogeingang für Arduino: Spannung/Strom galvanisch trennen
  10. Präziser Reaktionszeit-Test mit Arduino UNO