LED-Cube 8x8x8 Matrix
(Mai 2010) Als erstes die Idee …
Ich hatte, soweit ich’s noch weiss, bei YouTube ein Video von einem LED-Cube gesehen und dachte mir: „Das will ich auch!“
=> gedacht -> geplant -> gekauft
Da LEDs in der Menge (man bedenke 8×8 LEDs für eine Ebene = 64 LEDs und davon dann 8 Ebenen = 512 LEDs!!) einiges kosten und erst recht wenn diese dann auch noch blau sein sollen, muss eine günstige Quelle erschlossen werden. Und was gibt es da wohl besseres als die einschlägigen Online Auktionshäuser?
Aber so einfach war das dann doch nicht, denn unter den vielen Angeboten muss erst mal das passende gefunden werden.
Am Ende hab ich dann welche für so um die 45€ bekommen und sogar noch mit Vorwiderstand für jede LED, den ich gar nicht gebraucht hätte … 🙂
Auf dem Bild ist übrigens nur ein Teil der LEDs zu sehen.
Wer genau hinschaut kann erkennen das alle LEDs schon gebogen sind.
Übrigens scheiß viel Arbeit.
Ich war allein mit dem Biegen einige Abende beschäftigt (und dabei locker 5-6 Filme geschaut ;-)).
Als Nächstes mussten die Leuchten in Position gebracht werden.
Dafür hatte ich mir aus einem kleinen Brett eine Schablone gebaut, womit ich auch gleich die „Köpfe“ weiß lackieren konnte.
Denn vorherige Leuchttests haben ergeben das auf diese Art bearbeitete LEDs besser aussehen.
Der nächste Schritt war übrigens auch nur geringfügig weniger Aufwand … Das Löten nämlich.
Die Länge des benötigten Drahtes ist nicht zu unterschätzen. Ein paar Meter waren es am Ende dann doch schon geworden.
Was nun noch fehlt ist … richtig, die Steuerung.
Verwendet habe ich hierfür so genannte 8-bit D-Latch/e/es, keine Ahnung wie man die im Plural schreibt :-)).
Das „tolle“ an diesen IC’s ist, dass ich per µC jeweils 1 Byte an das Latch geben kann und es erst dann ausgeben lassen wenn ich einen Eingang des IC’s setze. D.h. ich kann die Datenleitungen aller 8 IC’s zusammenlegen und immer nur das IC die Daten ausgeben lassen, welches ich dann auswählen kann.
Die 8 Ebenen können dann über die MOSFET’s (da es nicht im Plan zu sehen ist, es sind IRLU 2905) ausgewählt werden.
Nun gut, ich hoffe mal man kann es so verstehen …
Natürlich darf auch die nötige Verpackung nicht fehlen und daher habe ich mir Bilderrahmen bestellt (übrigens die gleiche Art, die ich auch für die Word-Clock benutzt habe).
Vorne kann man die Drähte sehen, die später für die Auswahl der einzelnen Ebenen sind.
Und nun … der erste Test. Alles funktioniert wie ich es mir ausgedacht habe … zum Glück ;-).
Das die LEDs im Foto farblich nicht der Farbe Blau entsprechen liegt allein an der Aufnahme mit meiner Kamera.
Zum Abschluss mein kleines Testprogramm, das die Ebenen von unten nach oben wie in einem Schieberegister ansteuert.
.include "m32def.inc" ;ATMEGA32-Routinen einbinden
;--------------------Registerdefinitionen--------------------
.def temp0 = r16 ;allgemeines Arbeitsregister
.def temp1 = r17 ;allgemeines Arbeitsregister
;--------------------Ein+Ausgänge--------------------
;PortA: PortB:
; Pin0 =(A)= Bit0 Pin0 =(A)= unbenutzt
; Pin1 =(A)= Bit1 Pin1 =(A)= unbenutzt
; Pin2 =(A)= Bit2 Pin2 =(A)= unbenutzt
; Pin3 =(A)= Bit3 Pin3 =(A)= unbenutzt
; Pin4 =(A)= Bit4 Pin4 =(A)= unbenutzt
; Pin5 =(A)= Bit5 Pin5 =(A)= unbenutzt
; Pin6 =(A)= Bit6 Pin6 =(A)= unbenutzt
; Pin7 =(A)= Bit7 Pin7 =(A)= unbenutzt
;PortC: PortD:
; Pin0 =(A)= Spalte1 Pin0 =(A)= Layer1
; Pin1 =(A)= Spalte2 Pin1 =(A)= Layer2
; Pin2 =(A)= Spalte3 Pin2 =(A)= Layer3
; Pin3 =(A)= Spalte4 Pin3 =(A)= Layer4
; Pin4 =(A)= Spalte5 Pin4 =(A)= Layer5
; Pin5 =(A)= Spalte6 Pin5 =(A)= Layer6
; Pin6 =(A)= Spalte7 Pin6 =(A)= Layer7
; Pin7 =(A)= Spalte8 Pin7 =(A)= Layer8
;--------------------Vorbereitungen--------------------
;Stackpointer initialisieren
ldi temp0, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, temp0
ldi temp0, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp0
;PortA-D
ldi temp0, 0b11111111
out DDRA, temp0 ;PortA = Ausgang
out DDRB, temp0 ;PortB = Ausgang
out DDRC, temp0 ;PortC = Ausgang
out DDRD, temp0 ;PortD = Ausgang
;--------------------Hauptprgramm--------------------
;einmal zu Anfang ausführen:
ldi temp0, 0xFF
out PortC, temp0
out PortA, temp0
ldi temp1, 0xFF
begin: ldi temp0, 0x00
main: out PortD, temp0 ;temp0 in Layer ausgeben
inc temp0 ;temp0 um 1 erhöhen
rcall timer
cp temp0 , temp1 ;vergleiche temp0 mit temp1
breq begin ;wenn gleich springe zu "begin"
rjmp main ;wenn ungleich springe zu "main" (Schleife)
;dauerhaft ausführen (Schleife):
;--------------------Timer--------------------
timer:
ldi R29, $5F
WGLOOP0: ldi R30, $17
WGLOOP1: ldi R31, $79
WGLOOP2: dec R31
brne WGLOOP2
dec R30
brne WGLOOP1
dec R29
brne WGLOOP0
ret ;Rücksprung ins Hauptprogramm
;--------------------Programmende--------------------
;kommt nie hier an
loop:
rjmp loop ;springe zurück zu "loop"
Update
(05.09.10)
Wie angekündigt ein Bild von der fertig eingebauten Platine.
Sieht etwas wüst aus, ist es aber auch. Da der ganze Einbau nicht hoch sein durfte habe ich die Flachbandkabel direkt angelötet. Passt gerade so, aber wenn ich da noch mal was ändern muss oder sonst was machen will, wird das ’ne richtige Friemelarbeit.
Praktisch ist aber, das ich direkt mit den Klammern, die das Brettchen gegen den Rahmen pressen, die Platinen befestigen konnte. Also keine unschönen Schrauben oder Ähnliches die man von oben sehen könnte.
Update
(15.12.11)
Heute gibt es zwar kein neues Bild vom LED-Cube, dafür aber ein neues Programm.
Da ich seit nun doch schon längerer Zeit wieder Lust hatte etwas zu programmieren, habe ich einen neuen Modus für den LED-Cube geschrieben.
Und zwar einen Zufallsmodus. D.h. es gehen (mehr oder weniger) zufällig irgendwelche LEDs an und auch wieder aus.
Der vorherige Modus ist weiterhin funktionsfähig, muss aber „entkommentarisiert“ werden, damit er auch abgearbeitet wird.
.include "m32def.inc" ;ATMEGA32-Routinen einbinden
;--------------------Registerdefinitionen--------------------
.def temp0 = r16 ;allgemeines Arbeitsregister
.def temp1 = r17 ;allgemeines Arbeitsregister
.def temp2 = r18 ;Register für Zufallszahl
.def temp3 = r19 ;Register für Zufallszahl
.def random1 = r20 ;Zufallszahl
.def random2 = r21 ;Zufallszahl
;--------------------Ein+Ausgänge--------------------
;PortA: PortB:
; Pin0 =(A)= Bit0 Pin0 =(A)= unbenutzt
; Pin1 =(A)= Bit1 Pin1 =(A)= unbenutzt
; Pin2 =(A)= Bit2 Pin2 =(A)= unbenutzt
; Pin3 =(A)= Bit3 Pin3 =(A)= unbenutzt
; Pin4 =(A)= Bit4 Pin4 =(A)= unbenutzt
; Pin5 =(A)= Bit5 Pin5 =(A)= unbenutzt
; Pin6 =(A)= Bit6 Pin6 =(A)= unbenutzt
; Pin7 =(A)= Bit7 Pin7 =(A)= unbenutzt
;PortC: PortD:
; Pin0 =(A)= Spalte1 Pin0 =(A)= Layer1
; Pin1 =(A)= Spalte2 Pin1 =(A)= Layer2
; Pin2 =(A)= Spalte3 Pin2 =(A)= Layer3
; Pin3 =(A)= Spalte4 Pin3 =(A)= Layer4
; Pin4 =(A)= Spalte5 Pin4 =(A)= Layer5
; Pin5 =(A)= Spalte6 Pin5 =(A)= Layer6
; Pin6 =(A)= Spalte7 Pin6 =(A)= Layer7
; Pin7 =(A)= Spalte8 Pin7 =(A)= Layer8
;--------------------Vorbereitungen--------------------
;Stackpointer initialisieren
ldi temp0, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, temp0
ldi temp0, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp0
;Eingangs- /Ausgangsdeklaration
ldi temp0, 0b11111111
out DDRA, temp0 ;PortA = Ausgang
out DDRB, temp0 ;PortB = Ausgang
out DDRC, temp0 ;PortC = Ausgang
out DDRD, temp0 ;PortD = Ausgang
;Ursprungszustand des Würfels (alles aus)
ldi temp0, 0xFF
out PortC, temp0
out PortA, temp0
;--------------------Hauptprogramm--------------------
;Moduswahl
main:
;jmp EbenenSchieben
jmp Zufall
;--------------------Unterprogramme--------------------
Zufall: ;Zufallsmuster
rcall random
rcall timer
out PortD, random1
out PortC, random2
out PortA, random1
rjmp Zufall ;Schleife
EbenenSchieben: ;addiert immer um 1
ldi temp1, 0xFF
ES1:
ldi temp0, 0x00 ;nur einmal am Anfang ausführen
ES2:
out PortD, temp0 ;temp0 in Layer ausgeben
inc temp0 ;temp0 um 1 erhöhen
rcall timer
cp temp0 , temp1 ;vergleiche temp0 mit temp1
breq ES1 ;wenn gleich springe zu "ES1"
rjmp ES2 ;Schleife
;--------------------Timer--------------------
;Quelle: AVR DELAY LOOP GENERATOR V1.2 (C)2000 by Tjabo Kloppenburg
;bzw.: http://www.home.unix-ag.org/tjabo/avr/dlg_02/dlg02.php
;Eingestellt für 16MHz Takt und 0,025s
timer:
ldi R29, $F1
WGLOOP0: ldi R30, $0E
WGLOOP1: ldi R31, $9D
WGLOOP2: dec R31
brne WGLOOP2
dec R30
brne WGLOOP1
dec R29
brne WGLOOP0
ret
;--------------------Zufallszahl--------------------
;Quelle: http://www.mikrocontroller.net/topic/91659#785292
;Autor des Beitrags: Knut Ballhause (Firma: TravelRec.)
random:
mov temp2, random1 ;exor feedback outputs for SR input
andi temp2, 0b00000001
lsl temp2
lsl temp2
eor temp2, random1
andi temp2, 0b00000100
swap temp2
lsl temp2
mov temp3, random2
andi temp3, 0b00001000
swap temp3
eor temp3, random2
andi temp3, 0b10000000
eor temp3, temp2
rol temp3
rol random1
rol random2
ret
;--------------------Programmende--------------------
;kommt nie hier an
loop:
rjmp loop ;springe zurück zu "loop"