Arduino-Weihnachtsstern mit wählbaren Leuchtmustern

von Michael Gaus 




In diesem Projekt wird ein Weihnachtsstern als Aufsteckplatine (Shield) bestehend aus 20 LEDs für den Arduino realisiert. Es können beliebige Leuchtmuster komfortabel mit einem PC-Tool generiert und in die Arduino-Firmware integriert werden. Der Hardwareaufbau erfolgt auf einer Standard-Lochrasterplatine, sodass keine Platine geätzt werden muss.

Ein Video, auf dem der Weihnachtsstern in Aktion zu sehen ist, gibt es hier:  www.youtube.com/watch?v=1E1VOpvfQK0


Hardwareaufbau

Folgende zusätzliche Bauteile sind erforderlich:
20 LEDs, 20 Widerstände mit je 1,5 kOhm, Stiftleisten RM 2,54mm (2x 8-polig und 2x 6-polig), Lochrasterplatine mit Lötpunkten



Die Schaltung kann auf einem Stück Lochrasterplatine aufgelötet werden und über die Stiftleisten dann als sogenanntes "Shield" direkt auf die Buchsen der Arduino Platine aufgesteckt werden.




Die Vorwiderstände für jede LED werden auf der Platinenrückseite montiert, sodass auf der Platinenoberseite nur die 20 LEDs zu sehen sind. Zur Montage der Stiftleisten sollte am besten folgendermaßen vorgegangen werden:

- Zuerst die Stiftleisten in die Buchsen auf der Arduino-Platine einstecken.
- Die Lochrasterplatine auf die Stiftleisten mit etwas Abstand aufsetzen, sodass diese später noch auf der Platinenunterseite verlötet werden können. Hierbei müssen manche Stiftleisten leicht schräg aufgedrückt werden, da der Abstand der Buchsenleisten auf der Arduino-Platine leider nicht dem Standard von 2,54mm entspricht.
- Wenn nun die Arduino-Platine auf die Seite gedreht wird, können Sie Stiftleisten mit den Lötpunkten auf der Lochrasterplatine verlötet werden.








Programmierung der Arduino Platine

In der Entwicklungsumgebung Arduino wird der Sketch star.pde geladen, kompiliert und per Upload-Button auf den Arduino übertragen.
Hier sind bereits einige Sequenzen mit Leuchtmustern enthalten. Diese können nach Belieben geändert werden, z.B. mit dem beiliegenden PC-Tool.


PC-Tool zur Generierung von Leuchtmusterabläufen

Um komfortabel Leuchtmuster generieren zu können, wurde ein PC-Tool mit Visual C++ 2005 entworfen. Das Tool inkl. komplettem Quellcode ist in der ZIP-Datei pc_tool enthalten. Eine ausführbare EXE-Datei ist im Unterverzeichnis release zu finden. Die beiden Dateien on.gif und off.gif werden zur Darstellung der LEDs benötigt. Wenn eine Änderung des Quellcodes gewünscht ist, kann die Projektdatei xmasstar.vcproj im Unterverzeichnis xmasstar geöffnet werden.



Die Bedienung des Tools ist weitgehend selbsterklärend. Im oberen LED-Stern "Eingabe" kann ein gewünschtes Leuchtmuster durch Klick auf die LEDs zusammengestellt werden sowie die gewünschte Anzeigedauer im gleichnamigen Feld in Millisekunden angegeben werden. Durch Klick auf den Button "Muster am Ende anhängen" wird das erstellte Muster an die Sequenz rechts in der Listbox hinten angehängt. Mit den anderen Buttons kann das Muster entsprechend an anderer Stelle eingefügt werden oder auch gelöscht werden. Das Muster in der selektierten Zeile der Listbox wird im unteren LED-Stern "Ausgabe" dargestellt. Durch Klick auf den Button "Simulation" kann hier die erstellte Sequenz komplett abgespielt werden.
Mit den Buttons "Speichern" sowie "Laden" können die Sequenzen in Textdateien gesichert bzw. geladen werden.

Das Datenformat sieht folgendermaßen aus:
Hexwert für die LEDs 1-6 (z.B. 0x3F), Hexwert für die LEDs 7-14 (z.B. 0xFF), Hexwert für die LEDs 15-20 (z.B. 0x3F), Dezimalwert für die Anzeigedauer in Millisekunden (z.B. 250), am Ende ein Zeilenumbruch.

Um die Leuchtmustersequenz in das Arduino-Programm einbinden zu können, muss es mit dem Button "Speichern" zuerst als Textdatei gespeichert werden. Die Textdatei kann dann mit einem Texteditor (z.B. Notepad) geöffnet werden und der Inhalt über die Zwischenablage in das Array im Arduino-Programm eingefügt werden. Als Beispiel ist im Arduino-Programm das Array patternDemo zu finden, zwischen den Kommentarzeilen "Start" und "Ende" muss die Leuchtmustersequenz eingefügt werden.


Arduino Quellcode und Funktionsprinzip

Der Code für den ATmega168 auf der Arduino Platine wurde mit der Version arduino-0021 erstellt. Das komplette Projekt ist in der ZIP-Datei Star.zip enthalten (Name der Sketchdatei ist star.pde).

In der Funktion setup werden die Portpins für die LEDs als Ausgang konfiguriert und alle LEDs ausgeschaltet.

In der Hauptschleife loop kann durch Aufruf der Funktion displayPatternWithDuration eine in einem Array vorhandene Leuchtmustersequenz abgearbeitet werden. Als Beispiel soll ein Array namens patternDemo eingebunden werden, dies sieht folgendermaßen aus:

struct STR_PATTERN patternDemo[] PROGMEM =
{
// Start: ab der nächsten Zeile beginnt die Leuchtmustersequenz, die mit dem PC-Tool erstellt und aus der Textdatei kopiert wurde
0x01,0x00,0x00,100,
0x03,0x00,0x00,100,
// Ende: hier endet die Leuchtmustersequenz, die mit dem PC-Tool erstellt wurde
// die nächste Zeile wird als Endekennung des Arrays benötigt und darf nicht gelöscht werden
0xFF,0xFF,0xFF,0  // end marker, do not remove
};

Der Aufruf in der Hauptschleife loop sieht dann wie folgt aus:
displayPatternWithDuration(patternDemo);

Das Schlüsselwort PROGMEM bewirkt, dass das Array im Programm-Flashspeicher des ATmega168 abgelegt wird. Somit können auch mehrere große Arrays angelegt werden, ohne dass es Speicherplatz-Problemen mit dem wesentlich kleineren SRAM kommt.
Um manuell ein Leuchtmuster für die 20 LEDs auszugeben, kann die Funktion ledPattern verwendet, diese erwartet als Parameter die 3 Hexwerte für die LED-Gruppen


#include <avr/pgmspace.h>

// LEDs:
// LED 1-6: PORTC.0-PORTC.5
// LED 7-14: PORTD.0-PORTD.7
// LED 15-20: PORTB.0-PORTB.5


struct STR_PATTERN
{ // Definition der Struktur eines Arrays für eine Leuchtmustersequenz
unsigned char leds_1_6;
unsigned char leds_7_14;
unsigned char leds_15_20;
unsigned int duration;
};


// ein Array namens patternDemo sieht z.B. folgendermaßen aus:
struct STR_PATTERN patternDemo[] PROGMEM =
{
// Start: ab der nächsten Zeile beginnt die Leuchtmustersequenz, die mit dem PC-Tool erstellt und aus der Textdatei kopiert wurde
0x01,0x00,0x00,100,
0x03,0x00,0x00,100,
// Ende: hier endet die Leuchtmustersequenz, die mit dem PC-Tool erstellt wurde
// die nächste Zeile wird als Endekennung des Arrays benötigt und darf nicht gelöscht werden
0xFF,0xFF,0xFF,0 // end marker, do not remove
};



struct STR_PATTERN pattern0[] PROGMEM =
{
0x01,0x00,0x00,100,
0x02,0x00,0x00,100,
0x04,0x00,0x00,100,
0x08,0x00,0x00,100,
0x10,0x00,0x00,100,
0x20,0x00,0x00,100,
0x00,0x01,0x00,100,
0x00,0x02,0x00,100,
0x00,0x04,0x00,100,
0x00,0x08,0x00,100,
0x00,0x10,0x00,100,
0x00,0x20,0x00,100,
0x00,0x40,0x00,100,
0x00,0x80,0x00,100,
0x00,0x00,0x01,100,
0x00,0x00,0x02,100,
0x00,0x00,0x04,100,
0x00,0x00,0x08,100,
0x00,0x00,0x10,100,
0x00,0x00,0x20,100,
0x00,0x00,0x00,100,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};


struct STR_PATTERN pattern1[] PROGMEM =
{
0x00,0x00,0x00,100,
0x01,0x00,0x00,100,
0x03,0x00,0x00,100,
0x07,0x00,0x00,100,
0x0F,0x00,0x00,100,
0x1F,0x00,0x00,100,
0x3F,0x00,0x00,100,
0x3F,0x01,0x00,100,
0x3F,0x03,0x00,100,
0x3F,0x07,0x00,100,
0x3F,0x0F,0x00,100,
0x3F,0x1F,0x00,100,
0x3F,0x3F,0x00,100,
0x3F,0x7F,0x00,100,
0x3F,0xFF,0x00,100,
0x3F,0xFF,0x01,100,
0x3F,0xFF,0x03,100,
0x3F,0xFF,0x07,100,
0x3F,0xFF,0x0F,100,
0x3F,0xFF,0x1F,100,
0x3F,0xFF,0x3F,100,
0x3F,0xFF,0x3F,100,
0x3E,0xFF,0x3F,100,
0x3C,0xFF,0x3F,100,
0x38,0xFF,0x3F,100,
0x30,0xFF,0x3F,100,
0x20,0xFF,0x3F,100,
0x00,0xFF,0x3F,100,
0x00,0xFE,0x3F,100,
0x00,0xFC,0x3F,100,
0x00,0xF8,0x3F,100,
0x00,0xF0,0x3F,100,
0x00,0xE0,0x3F,100,
0x00,0xC0,0x3F,100,
0x00,0x80,0x3F,100,
0x00,0x00,0x3F,100,
0x00,0x00,0x3E,100,
0x00,0x00,0x3C,100,
0x00,0x00,0x38,100,
0x00,0x00,0x30,100,
0x00,0x00,0x20,100,
0x00,0x00,0x00,100,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};

struct STR_PATTERN pattern2[] PROGMEM =
{
0x3C,0x01,0x00,300,
0x00,0x1F,0x00,300,
0x00,0xF0,0x01,300,
0x00,0x00,0x1F,300,
0x07,0x00,0x30,300,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};


struct STR_PATTERN pattern3[] PROGMEM =
{
0x11,0x44,0x04,300,
0x33,0xCC,0x0C,300,
0x37,0xDD,0x1D,300,
0x3F,0xFF,0x3F,300,
0x00,0x00,0x00,300,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};


struct STR_PATTERN pattern4[] PROGMEM =
{
0x11,0x44,0x04,300,
0x22,0x88,0x08,300,
0x04,0x11,0x11,300,
0x08,0x22,0x22,300,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};

struct STR_PATTERN pattern5[] PROGMEM =
{
0x00,0x00,0x00,300,
0x11,0x44,0x04,300,
0x3B,0xEE,0x2E,300,
0x3F,0xFF,0x3F,300,
0x3F,0xFF,0x3F,300,
0x3B,0xEE,0x2E,300,
0x11,0x44,0x04,300,
0x00,0x00,0x00,300,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};


struct STR_PATTERN patternBlink[] PROGMEM =
{
0x3F,0xFF,0x3F,300,
0x00,0x00,0x00,300,

0xFF,0xFF,0xFF,0 // end marker, do not remove
};


void ledPattern(unsigned char led_1_6, unsigned char led_7_14, unsigned char led_15_20)
{
PORTC = led_1_6;
PORTD = led_7_14;
PORTB = led_15_20;
}


void displayPatternWithDuration(struct STR_PATTERN * PROGMEM pattern)
{
unsigned int j = 0;

while(pgm_read_byte(&pattern[j].leds_1_6) != 0xFF)
{
ledPattern(pgm_read_byte(&pattern[j].leds_1_6), pgm_read_byte(&pattern[j].leds_7_14), pgm_read_byte(&pattern[j].leds_15_20));
delay(pgm_read_word(&pattern[j].duration));
j++;
}
}



void clearPattern(void)
{
PORTC = 0;
PORTD = 0;
PORTB = 0;
}


void setup()
{
PORTB = 0;
DDRB |= 0x3F;
PORTD = 0;
DDRD |= 0xFF;
PORTC = 0;
DDRC |= 0x3F;
}



void loop()
{
unsigned char i;

clearPattern();

displayPatternWithDuration(pattern0);

for(i = 0; i < 3; i++)
{
displayPatternWithDuration(patternBlink);
}

displayPatternWithDuration(pattern1);

for(i = 0; i < 3; i++)
{
displayPatternWithDuration(pattern2);
}

for(i = 0; i < 3; i++)
{
displayPatternWithDuration(pattern3);
}

for(i = 0; i < 3; i++)
{
displayPatternWithDuration(pattern4);
}

for(i = 0; i < 3; i++)
{
displayPatternWithDuration(pattern5);
}

}



zurück