Dokumentation LED Cube 8x8x8 ein Praktikumsprojekt von Claudia Denk Severin Völkl unter der Leitung von Gerald Schickhuber Prof. Georg Scharfenberg durchgeführt vom 18.08.08 bis 26.09.08 im BiSP-Labor der HS Regensburg Seybothstraße 2 93053 Regensburg
2 LED Cube
Inhaltsverzeichnis 1. Aufbau des Würfels...4 2. Funktionsbeschreibung...5 3. Softwarebeschreibung...6 4. Technische Daten...8 5. Die Würfel-Bibliothek...9 6. Beispielprogramm...10 7. Gefahrenhinweise/Pflegeanweisung...11 LED Cube 3
1. Aufbau des Würfels Liste der dazu benötigten Teile: 512 Leuchtdioden 64 dicke Drähte (Säulen; 1-2mm) 88 dünne Drähte (Querstreben; 0,5-1mm) 2 Holzbretter viel Lötzinn - 1. Schritt Löten Sie zunächst je 8 Leuchtdioden im Abstand von 4cm mit der Kathode an insgesamt 64 starre Drähte (Säulen). Biegen Sie dazu die Beinchen der Dioden derart, dass Sie später am Tag die Anodendrähte (Querstreben) senkrecht dazu anlöten können. 2. Schritt: Verbinden Sie nun jeweils 8 Leuchtstangen mit 8 Anodendrähten, so dass ein quadratisches Gitter entsteht. 3. Schritt: Stecken Sie die Gitter in ein vorgebohrtes Holzbrett mit den Lochabständen von jeweils 4cm. Die Bohrlochgröße entspricht etwa der Drahtdicke. Verbinden Sie sie anschließend an den Anoden ebenenweise zu einem Würfel. Führen Sie die Anoden jeder Ebene mittels weiterer Drähte durch das Holzbrett hindurch an dessen Unterseite. 4 LED Cube
2. Funktionsbeschreibung Der Würfel besteht aus 512 Leuchtdioden, die in acht Ebenen zu 64 Dioden angeordnet sind. Die Ebenen werden mit Hilfe eines Multiplexers 1 der Reihe nach eingeschaltet. Das Einschalten erfolgt im 1/8-Puls-Betrieb. Für das Durchschalten der Ebenen wurde 1ms pro Ebene gewählt. Somit ergibt sich eine Zeilenfrequenz von 1000 Hz und ein Bildaufbau mit der Frequenz von 125 Hz. Die Ansteuerung der einzelnen Dioden in einer Ebene übernehmen acht low-aktive Schieberegister 2 deren parallele Ausgänge mit den Kathodenstangen (Säulen) verbunden sind. Über einen Stelleingang begrenzen sie auch den Diodenstrom auf etwa 100mA. Die Register werden seriell mit Daten geladen. Die seriellen Eingänge (einer je Register) liegen am Controller an den Ports 1.0 bis 1.7. Nachdem dort ein Datenbyte ins entsprechende Register geladen wurde, können dessen Bits durch Auslösen einer Taktflanke am Port 3.4 des Controllers in die Register geschoben werden. Sind alle Register aufgeladen, können über eine Flanke an den Latch-Enable-Eingängen der Register, die parallel mit Port 3.5 des Controllers verschaltet sind, die Daten auf die parallelen Ausgänge gelegt werden. Ein 1-aus-16-Decoder (Multiplexer) übernimmt dabei die Adressierung der Ebenen über die Anodenstangen. Seine Ausgänge sind mit den Gates der p-kanal-fets verbunden, die im Bedarfsfall eine Spannung von 5V an die Anodenstangen anlegen. Die Ausgänge des IC sind standardmäßig auf High-Pegel gesetzt. Deswegen sind Pullup-Widerstände zum Deaktivieren der FETs nicht notwendig. Der Decoder ist über vier Adressleitungen mit den Ports 3.0 bis 3.3 des Controllers verbunden, die bei dessen Ausfall über Pull-up-Widerstände auf VCC gezogen werden. In diesem Fall würde Ausgang 15 aktiviert werden, und somit könnte man dort einen Low-Pegel messen. 1 Wir verwenden in der Schaltung einen 74HCT154 mit low-aktiven Ausgängen. 2 Es handelt sich um acht TLC5916 8-Bit Constant-Current LED Sink Drivers. LED Cube 5
3. Softwarebeschreibung Das beiliegende Beispielprogramm, welches die Würfel-Bibliothek nutzt, ist wie folgt aufgebaut: Hauptprogramm Interrupt-Routine Start Einstieg Interrupt Watchdog framerendered Ports false framerendered =false true Timer Kopieren des Backbuffers in den Frontbuffer false framerequest true Deaktivierung der aktuellen Ebene framerequest =false Rendering des Frames im Backbuffer Bereitstellen der nächsten Ebene Aktivierung der nächsten Ebene framerendered =true Ausstieg 6 LED Cube
Zu Beginn wird der Watchdog deaktiviert, um einem automatischen Reset des Systems vorzubeugen. Die Ports und der Timer für den Interruptaufruf werden initialisiert. Im Anschluss daran tritt das Programm in eine Endlosschleife ein, in der falls erforderlich der als nächstes anzuzeigende Frame errechnet wird. Während des Programmablaufs wird jede Millisekunde eine Interruptroutine aufgerufen, in der die Ansteuerung der nächsten Ebene erfolgt. Dazu wird die Technik des Double-Bufferings 3 eingesetzt. Solange das Rendering des neuen Frames nicht vollständig abgeschlossen ist, wird noch die alte Bildinformation, die sich in einem separaten Puffer (back buffer) befindet, zur Ausgabe verwendet. Erst danach wird ein Flag framerendered gesetzt, aufgrund dessen der Puffer mit dem neuen Frame in den Ausgabepuffer (front buffer) kopiert wird. Diese Vorgehensweise verhindert ein Flackern des Bildes unter Aufrechterhaltung der Zeilenfrequenz. Wahlweise kann hierbei zusätzlich ein VSync abgewartet werden. Da der Interrupt jede Millisekunde eintritt, wird hier auch ein Zähler hochgezählt, mithilfe dessen eine regelmäßige Bilderzeugung realisiert wird. In unserem Beispiel wird nur alle 33 Zählerschritte mittels Setzens eines Flags framerequest ein neues Bild angefragt, was einer tatsächlichen Bildrate von augenfreundlichen 4 33fps entspricht. Dieses Vorgehen soll den Controller bei brachialer Programmierung des Hauptprogramms entlasten. 3 siehe auch http://de.wikipedia.org/wiki/double_buffering 4 siehe auch http://de.wikipedia.org/wiki/bewegte_bilder LED Cube 7
4. Technische Daten Farbe der LEDs Gelb Maße (H, B, T) 470mm, 360mm, 360mm Temperaturbereich 0 C-70 C Betriebsspannung 18V 36V Betriebsspannung µc 3,6V Betriebsspannung Logik 5V Leerlaufbetrieb (alle Dioden aus) Stromaufnahme bei 18V 170mA Stromaufnahme bei 30V 125mA Volllastbetrieb (alle Dioden ein) Stromaufnahme bei 18V 890mA Stromaufnahme bei 30V 535mA Taktfrequenz µc 16MHz Bildwiederholrate 125Hz 8 LED Cube
5. Würfel-Bibliothek (ledlib.h) typedef UINT8 cube[8][8] typedef char pattern2d[8][8] void clearcube(cube acube) Löscht alle Bits des übergebenen Würfels. void fillcube(cube acube) Setzt alle Bits des übergebenen Würfels. void setpixel(cube acube, UINT8 x, UINT8 y, UINT8 z) Setzt im übergebenen Würfel das Bit an der angegebenen Position. void delpixel(cube acube, UINT8 x, UINT8 y, UINT8 z) Löscht im übergebenen Würfel das Bit an der angegebenen Position. void copycube(cube sourcecube, cube draincube) Kopiert den Inhalt von sourcecube nach draincube. UINT8 cubesareequal(cube cube1, cube cube2) Gibt 0x01 zurück, wenn sich die übergebenen Würfel gleichen, sonst 0x00. UINT16 activeleds(cube acube) Gibt die Anzahl der leuchtenden LEDs zurück. void drawpattern(cube acube, pattern2d pattern, UINT8 slice) Überträgt ein 2D-Muster auf eine Scheibe des Würfels. void randomizecube(cube acube, UINT8 percentage) Setzt im übergebenen Würfel zufällig. void commit3devolution(cube oldcube, cube newcube) Begeht 3D-Evolution. LED Cube 9
6. Beispielprogramm #include "ledlib.h" typedef char cube[8][8]; //Bibliothek einbinden //Würfelobjekte sind 8x8x8 Bits groß cube maincube, intcube; //Hauptprogramm- und Interruptwürfel deklarieren unsigned char framerequest, framerendered; //Frameflags deklarieren unsigned long counter=0; //Counter initialisieren void main(void) { init_watchdog(); init_dco(); init_ports(); init_timer(); clearcube(maincube); //Watchdogs ausschalten //16MHz //Ports konfigurieren //Timer konfigurieren //Würfelpuffer löschen enable_interrupt(); //Globale Interrupts einschalten framerequest=1; //Mit Frameanfrage beginnen... framerendered=0; //...ohne einen Frame im Puffer for(;;) //Hauptschleife { if (framerequest) { //Framerequest gesetzt? framerequest=0; //Flag löschen clearcube(maincube); //Würfel löschen maincube[(counter/2)%8][(counter/3)%8]=0xff; framerendered=1; //Flag setzen //etwas zeichnen #pragma vector=timer0_a0_vector interrupt void Timer_A (void) { static unsigned char layer=0, slice=0, ints=0; if (layer==8) layer=0; //Jedes Mal den Layer wechseln if (framerendered && layer==0) { framerendered=0; copycube(maincube,intcube); if(ints==33) { counter; framerequest=1; ints=0; //Intern bis 33 zählen... //...dann Counter erhöhen //und Request-Flag setzen P3OUT &=~ 0x0F; //Ebenen ausschalten for (slice=0; slice<8; slice) { //Gitter durchzählen... P1OUT = intcube[layer][slice]; //...und jeweils 1 Bit an... P3OUT = BIT4; //...alle Register senden... P3OUT &=~BIT4; //...und Clock-Flanke erzeugen P3OUT = BIT5; //Latch-Flanke schicken P3OUT &=~BIT5; P3OUT = layer & 0x0F; //Nächste Ebene einschalten 10 LED Cube
7. Gefahrenhinweise/Pflegeanweisung Vor hochenergetischen elektromagnetischen Pulsen (EMP) schützen! Von Kindern fernhalten! Gefahr des Verschluckens. Nicht sandstrahlen! Nicht spülmaschinenfest! Vor starker mechanischer Beanspruchung schützen! Nicht unbeaufsichtigt brennen lassen! Gefahr der Stromverschwendung. Vor der Reinigung Netzstecker ziehen! Reinigung mit antistatischem Staubtuch. LED Cube 11