8x8x8 RGB LED-Würfel mit Arduino bauen – DIY Anleitung
Komponenten und Zubehör
| Komponente | Menge | Hinweis |
|---|---|---|
| RGB Diffus Common Anode 5mm LED | 512 | |
| DM13A LED-Treiber | 12 | |
| 74HC138 3-zu-8 Leitungsdecoder | 1 | |
| IRF9640 P-Kanal MOSFET | 8 | |
| Arduino UNO | 1 | Auch Breadboard-Version mit ATmega328, 16MHz Quarz, 2x 22pF Kondensatoren möglich |
| Digilent 5V 2,5A Schaltnetzteil | 1 | |
| Widerstand 10k Ohm | 8 | |
| Widerstand 1k Ohm | 8 | |
| Widerstand 100 Ohm | 8 |
Apps und Online-Dienste
- Arduino IDE
Über dieses Projekt
Video
Ein Video zum Projekt ist verfügbar.
Aufbau
Dieser Bau wurde von Kevin Darrahs RGB-Würfel inspiriert.
Bei Kevins Bau muss seine Geduld grenzenlos sein – leider ist meine das nicht.
Ich entschied mich, die 24 Schieberegister, 192 Transistoren und 640 Widerstände durch 12 DM13A LED-Treiber (ca. 1$ pro Stück auf eBay) zu ersetzen.
Der Würfel selbst wurde wie von Kevin im folgenden Video beschrieben gebaut:
Nach Fertigstellung des Würfels erstellte ich eine Leiterplatte im Toner-Transfer-Verfahren für die DM13A-Treiberchips und den Würfel selbst. Anstatt für eine kommerziell gefertigte Platine mit durchkontaktierten Löchern zu bezahlen, entschied ich mich, jede LED-Verbindung manuell mit Drahtwickeldraht zum entsprechenden DM13A-Pin zu verdrahten. Die mitgelieferten Eagle-Dateien enthalten sowohl die handverdrahtete als auch eine autoroutete Version (ungetestet).
Der Mikroprozessor- und Anodenboard enthält auch einen MSGEQ7 – Sieben-Band-Grafik-Equalizer und Mikrofonvorverstärker, mit denen ich in Zukunft experimentieren möchte. Aktuell sind sie nicht in Betrieb. Wenn Sie ein kommerzielles UNO- oder Nano-Board verwenden möchten, benötigen Sie nur den 74HC138 3-zu-8 Decoder, die 8 P-Kanal-MOSFETs und die zugehörigen Widerstände. Diese können Sie auf einer Lochrasterplatine aufbauen.
Das 5V 20W Netzteil wurde auf eBay gekauft. Das Gehäuse fertigte ich aus 40mm x 9mm gehobeltem Kiefernholz.
Ich fügte ein paar Animationen zu Kevins Würfel-Software hinzu, aber im Grunde bleibt sie unverändert.
Fazit
Sie sollten 600 Stück 5mm Common Anode diffuse RGB LEDs auf eBay für ca. 30$ US kaufen können. Auch nach Vereinfachung der Elektronik war der Bau des Würfels sehr zeitaufwendig, aber am Ende lohnend.
Code
Cube_8x8x8_V1.ino (C/C++)
/* The 8x8x8 RGB LED Cube by John Bradnam based on work by Kevin Darrah
* Latest V12 04/17/2013
* Release Notes:
* V11 - Fixed bug with BAM timing
* V12 - Bitweise Operation für PIN LOW korrigiert: PORTx &= ~(1< 250 kHz
TIMSK1 = B00000010; // Interrupt bei OCR1A Match
OCR1A = 30; // Interrupt alle (30+1)*4µs = 124µs -> ~8 kHz Multiplexfrequenz
pinMode(LATCH_PIN, OUTPUT);
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LAYER_A, OUTPUT);
pinMode(LAYER_B, OUTPUT);
pinMode(LAYER_C, OUTPUT);
digitalWrite(LAYER_A, LOW);
digitalWrite(LAYER_B, LOW);
digitalWrite(LAYER_C, LOW);
pinMode(SWITCH_PGM, INPUT);
pinMode(SWITCH_SEQ, INPUT);
// BLANK_PIN erst am Ende auf OUTPUT, damit LEDs beim Boot nicht aufblitzen
SPI.begin();
interrupts(); // Showtime!
}
void loop() {
if (digitalRead(SWITCH_PGM) == HIGH) test_leds();
else {
clean();
animation++;
switch (animation) {
case 1: rainVersionTwo(20); break;
case 2: folder(10); break;
case 3: sinwaveTwo(15); break;
case 4: randomColor(10); break;
case 5: wipe_out(10); break;
case 6: bouncyvTwo(15); break;
case 7: color_wheelTWO(10); break;
case 8: harlem_shake(); break;
case 9: ripples(10); break;
case 10: animation = 0; break;
}
}
}
// LED Routine: LED(Ebene, Reihe, Spalte, Rot 0-15, Grün 0-15, Blau 0-15)
void LED(int level, int row, int column, byte red, byte green, byte blue) {
level = constrain(level, 0, CUBE_MAX);
row = constrain(row, 0, CUBE_MAX);
column = constrain(column, 0, CUBE_MAX);
red = constrain(red, 0, 15);
green = constrain(green, 0, 15);
blue = constrain(blue, 0, 15);
int wholebyte = (level * LEDS_PER_LEVEL) + (row * CUBE_SIZE) + column;
int whichbyte = int(wholebyte / 8);
int whichbit = (wholebyte & 7);
// 4-bit Farbauflösung: jedes Bit in separatem Array
bitWrite(red0[whichbyte], whichbit, bitRead(red, 0));
bitWrite(red1[whichbyte], whichbit, bitRead(red, 1));
bitWrite(red2[whichbyte], whichbit, bitRead(red, 2));
bitWrite(red3[whichbyte], whichbit, bitRead(red, 3));
bitWrite(green0[whichbyte], whichbit, bitRead(green, 0));
bitWrite(green1[whichbyte], whichbit, bitRead(green, 1));
bitWrite(green2[whichbyte], whichbit, bitRead(green, 2));
bitWrite(green3[whichbyte], whichbit, bitRead(green, 3));
bitWrite(blue0[whichbyte], whichbit, bitRead(blue, 0));
bitWrite(blue1[whichbyte], whichbit, bitRead(blue, 1));
bitWrite(blue2[whichbyte], whichbit, bitRead(blue, 2));
bitWrite(blue3[whichbyte], whichbit, bitRead(blue, 3));
}
// Multiplex BAM Interrupt Service Routine
ISR(TIMER1_COMPA_vect) {
PORTD |= 1 << BLANK_PIN; // Alle LEDs AUS
// BAM Bit und Counter Logik
if (BAM_Counter == (CUBE_SIZE * 1)) BAM_Bit++;
else if (BAM_Counter == (CUBE_SIZE * 3)) BAM_Bit++;
else if (BAM_Counter == (CUBE_SIZE * 7)) BAM_Bit++;
BAM_Counter++;
int bytes_per_level = LEDS_PER_LEVEL / 8;
int shift_max = level + bytes_per_level;
switch (BAM_Bit) {
case 0:
for (int s = level; s < shift_max; s++) SPI.transfer(blue0[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(green0[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(red0[s]);
break;
case 1:
for (int s = level; s < shift_max; s++) SPI.transfer(blue1[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(green1[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(red1[s]);
break;
case 2:
for (int s = level; s < shift_max; s++) SPI.transfer(blue2[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(green2[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(red2[s]);
break;
case 3:
for (int s = level; s < shift_max; s++) SPI.transfer(blue3[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(green3[s]);
for (int s = level; s < shift_max; s++) SPI.transfer(red3[s]);
if (BAM_Counter == (CUBE_SIZE * 15)) {
BAM_Counter = 0; BAM_Bit = 0;
}
break;
}
// Anoden-Level über 74HC138 auswählen
digitalWrite(LAYER_A, bitRead(anodeLevel, 0));
digitalWrite(LAYER_B, bitRead(anodeLevel, 1));
digitalWrite(LAYER_C, bitRead(anodeLevel, 2));
PORTD |= 1 << LATCH_PIN; // Latch HIGH
PORTD &= ~(1 << LATCH_PIN); // Latch LOW
PORTD &= ~(1 << BLANK_PIN); // Blank LOW -> LEDs AN mit neuen Daten
anodeLevel = (anodeLevel + 1) & CUBE_MAX;
level = (level + bytes_per_level) & (LEDS_PER_LEVEL - 1);
pinMode(BLANK_PIN, OUTPUT); // Hier verschoben, damit Ausgänge bis zum ersten ISR-Aufruf aus bleiben
}
// Animationen folgen hier... (rainVersionTwo, folder, sinwaveTwo, randomColor,
// wipe_out, bouncyvTwo, color_wheelTWO, harlem_shake, ripples, test_leds, fill, clean)
// Code gekürzt – vollständige Version im Original oder Download
Der vollständige Code mit allen Animationen ist sehr umfangreich. Er enthält Funktionen für Regen, Falteffekte, Sinuswellen, zufällige Farben, Wisch-Effekte, Bounce, Farbrad, Harlem Shake, Wellen und mehr.
Schaltpläne
eagle_files_WfqPEUP7Mp.zip
Herstellungsprozess
- Smart Thirst Alert: DIY Pflanzen-Alarm für optimale Bewässerung
- Einen beeindruckenden 5x5x5 LED-Würfel mit Arduino Mega bauen
- Italienische Word Clock mit Arduino Nano, NeoPixel, LCD & RTC
- Zuverlässiger Sigfox-kWh-Zähler mit Arduino MKR Fox 1200
- Arduino RGB-LED-Farbmischer – Einsteigerfreundliches DIY-Projekt
- Bluetooth-Temperaturmonitor mit Arduino Nano
- Outdoor DMX-fähige RGB-LED-Fluter – Günstig & Hochleistungsstark
- Berührungsloses Gesten-Schloss: Sicherer Zugang mit APDS-9960 & Arduino
- Isolierter Analogeingang für Arduino: Spannung/Strom galvanisch trennen
- Präziser Reaktionszeit-Test mit Arduino UNO