LED Spielereien mit Charlieplexing

Beim
programmieren des
Akkuwächters
probierte ich das erste mal Charlieplexing.
Es war für mich klar,
dass ich hier noch etwas weiterforschen muss. Ziel war es, mit wenig
Hardware, möglichst viele LEDs anzusteuern. Reine Spielerei also .
Da im Web ja schon zig LED Lauflichtschaltungen zu bewundern sind,
wollte ich mich hier nicht anschließen und habe meine 20 LEDs, die
wieder ein ATtiny13 steuert nach Vorbild einer 4x5 Matrix angeordnet.
Auf dieser kleinen Anzeige lassen sich Leuchteffekte anzeigen die man
zuvor mit einen Mal- oder Zeichenprogramm komfortabel erstellen kann.
Sogar kleine Laufschriften sind möglich.
Videoclip
Es ist schon erstaunlich, was in die 1 KB Flashspeicher des
Tiny13
passt. Der Clip unten zeigt nur einen kleinen Teil der Animation.
Sicher, man muss sich schon etwas anstrengen um die
Laufschrift auf
dem Minimaldisplay von 4 x 5 Punkten zu entziffern. Für alle
die
es nur schwer lesen können. Bei der Laufschrift handelt es
sich um den altbekannten Satz "THE QUICK BROWN
FOX JUMPS OVER THE LAZY DOG" der alle Buchstaben des
Alphabets enthält (Pangramm).
Die Schaltung
Wie man sieht, werden alle 5 verfügbaren Portleitungen des
ATtiny13, an die 20
LEDs angeschlossen. Um
besser Layouten zu können, habe ich ein paar
Leitungen in der Reihenfolge verändert.
Jede Leitung erhält einen
Vorwiderstand von 56 Ohm. Beim Einschalten einer LED werden also immer
2 Widerstände aktiv und addieren sich somit zu 112 Ohm für eine
leuchtende LED. Werden die LEDs (im Multiplexverfahren 1:20) alle
gleichzeitig eingeschaltet, ergibt sich (theoretisch) einen Strom von
knapp 27 mA. In der Praxis fällt aber noch etwas Spannung an den
Portleitungen ab und es stellt sich ein Strom von ca. 20 mA ein, die
sich die 20 LEDs zu jeweils 1mA teilen. Ich war sehr erstaunt wie hell
die Low Current LEDs bei schon ab einem mA leuchten. Da man eh nur in
den seltensten Fällen alle LEDs einschalten muss, habe ich im Programm
eine Variable Multiplexrate vorgesehen, mit der z.B. 10 (aus 20) LEDs
mit den optimalen 2 mA betrieben werden und dennoch alle LEDs
gleichhell leuchten. Doch dazu mehr weiter unten.
Das Layout..
...verteilt
sich auf 2 einseitige Platinen die im Sandwich- verfahren übereinander
gesteckt werden. Die Tiny13 Platine, wird auf der Lötseite in
SMD-Technik bestückt. Alle passiven Bauteile haben die 0805 Bauform. Um
auch die breitere SMD-Bauform des ATtiny13 verwenden zu können, habe
ich die beiden Unterschiedlichen Tinys im Layout übereinander gelegt.
Da die Pinbelegung gleich
ist, spielt es somit keine Rolle welchen Chip man verwendet. Die
ISP-Pinleiste ist um 90° abgewinkelt und etwas knifflig zu löten.
Hierzu bedarf es auf jeden Fall einer dünnen Lötspitze.
Auf der LED-Platine, werden von den bedrahteten LEDs die rot
markierten Drähte etwas länger gelassen. Diese passen dann in
die
Vias der Tiny13 Platine, welche man mit einzelnen Pins von einreihigen
IC-Fassungen bestücken kann. Wie auch schon beim Akkuwächter,
mach der Dragon Probleme beim flashen per ISP, wenn die LED-Platine
aufgesteckt ist, wogegen der AVRISP mk2 auch bei aufgesteckter
LED-Platine Problemlos flasht.
Die Software
ist
in AVR-Assembler geschrieben und kann mit dem AVR-Studio 4.19 in
eine brennbare .hex Datei assembliert werden. Um eigene Leuchtmuster
oder
Laufschriften zu erzeugen sind keine, (oder wenig) Kenntnissen
Assembler notwendig. Ein paar grundlegende Dinge im Umgang mit dem AVR
Studio 4.19, habe ich schon hier
erläutert.
Die Firmware
Das Programm selbst steht am Anfang des Flashspeichers und hat
eine
Größe von etwa 250 Byte. Somit sind über 750 Bytes für Animationen
frei die hinter dem Programm angehängt und mit assembliert
werden.
Eine abzuspielende Sequenz sieht wie fogt aus.
quick:
.db scroll,168,12,20
.db 0x1D, 0x5C, 0x25, 0x4D, 0x46, 0x62, 0x45, 0x23, 0x92, 0x8E, \
0xA8, 0xB1, 0x84, 0x8B, 0xB0, 0xEA,
0xE2, 0x13, 0xD4, 0x62, \
0x30, 0x09, 0x50, 0x55, 0x51, 0x45,
0x55, 0x45, 0xA2, 0x2A, \
0x82, 0xAD, 0xAA, 0x0A, 0x8A, 0x28,
0x4A, 0x82, 0x28, 0x54, \
0x55, 0x40, 0x09, 0xD8, 0x55, 0x51,
0x86, 0x65, 0x55, 0x63, \
0x29, 0x02, 0xAA, 0xB1, 0x0A, 0x8B,
0x30, 0x4E, 0xC2, 0x28, \
0x94, 0x55, 0x40, 0x09, 0x50, 0x55,
0x51, 0x45, 0x55, 0x55, \
0x22, 0x2A, 0x8A, 0xA8, 0xA0, 0x8A,
0x52, 0x28, 0x4A, 0x82, \
0x39, 0x08, 0x55, 0x50, 0x09, 0x5C,
0x32, 0x4D, 0x46, 0x52, \
0x29, 0x22, 0x12, 0x84, 0x48, 0xA3,
0x04, 0x23, 0xA8, 0x4A, \
0xE3, 0xAB, 0xC8, 0x62, 0x30,
/*padding*/ 0
Jede abzuspielende Sequenz bekommt einen Label (oben quick),
dann
folgt der Header, der 4 Steuerbytes enthält. Der Rest des Datenblocks
besteht aus der Bitmap.
Die 4 Steuerbytes beschreiben dem Player die Art der
Animation,
die breite der Bitmap, die Multiplexrate und die Geschwindigkeit.
- Das erste Byte entscheidet ob die Bitmap (Pixelweise) geschoben oder durchgeblättert wird. Hier scroll für schieben oder film für durchblättern (Daumenkino) eintragen.
- Das
2. Byte (168) enthält die breite der Bitmap in Pixel. Die Maximale
Breite ist 256 . Kleinere Werte, sollten durch 8 teilbar sein. Soll die
Breite das maximum (256 betragen), hier eine 0 eintragen.
- Byte Nummer 3 (die 12) enthält die
Multiplexrate. Je
niedriger die Zahl, desto heller leuchten die LEDs. Zerlegt man die
Laufschrift in Einzelbilder sucht man den Frame der die meisten
eingeschalteten LEDs enthält. Diese Anzahl wird dann
eingetragen. Sinnvolle Werte liegen zwischen 8 und 20.
- Das letzte Byte ist für die Geschwindigkeit zuständig. Jede Erhöhung des Wertes lässt die Zeit um 10 mS länger werden die zwischen dem Anzeigen von 2 Frames vergeht.
- Danach folgt die Bitmap. Um diese zu erstellen benötigt man
ein Malprogramm welches im Bitmapformat (.bmp) speichern kann und
einen Konverter der die Bitmap in hex wandelt. Ich nutze Gimp2.8 und den
Grafikkonverter in der Version 1.4 von laeubi-soft.de.
Vielen Dank von mir an Läubi, für dieses wertvolle Tool.
Die Sequenz wird im Hauptprogramm mit dem Makro play wie folgt aufgerufen.
;**************************************************************************
;Main
;**************************************************************************
main: play quick
rjmp main
;**************************************************************************
;Main Ende
;**************************************************************************
Nach dem assemblieren (Build) des Beispiels von oben, erhält
man vom Studio folgende Meldung.
ATtiny13
memory use summary [bytes]:
Segment Begin
End
Code Data
Used Size Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x00017e
228 150
378 1024 36.9%
[.dseg] 0x000060
0x000088
0
40
40 64 62.5%
[.eseg] 0x000000
0x000000
0
0
0
64 0.0%
Assembly complete, 0 errors. 0 warnings
Wichtig ist hier die Zeile [.cseg],
die uns sagt, dass wir erst 378
von 1024 möglichen Bytes im Flash des Tiny13 und somit 36,9% belegt
haben. Es ist also noch jede Menge Platz für weitere Sequenzen. Diese
werden alle der Reihe nach zwischen main:
und rjmp
main
aufgerufen. Die Daten der Bitmap, kommen ans Ende des Quellcodes.
Natürlich kann
man jede Sequenz auch als eigene Datei abspeichern und im Quellcode
an passender Stelle includen.
Sequenz erstellen
Dazu benötigt man ein Grafikprogramm in welchem man beliebige Größen von Bitmaps erstellen, bearbeiten und als .bmp speichern kann. Ich benutze in meinem Beispiel das (open Source) Gimp in der Version 2.8.

Zeichnen
Zuerst unter [Datei -> Neu] wählen und als Bildgrösse
256 Breite
und 5 Höhe eintragen, OK klicken. Damit man in der Bitmap vernünftig
zeichnen kann, den Zoom auf etwa 3000% stellen. Soll eine Laufschrift
erstellt werden, das Raster unter [Bild -> Raster konfigurieren]
auf
Breite 1 und Höhe 1 einstellen. Bei einer Daumenkino Sequenz, den
Raster
auf Breite 4 und Höhe 5 einstellen. Das Kettensymbol zuvor,
durch
anklicken trennen. Das Raster unter [Ansicht -> Raster Anzeigen]
einschalten.
Zum Zeichnen den Stift wählen und als Pinsel das Pixel. Unter dem
Pinsel bei Größe, eine 1 eintragen.
Nun kann man in der Bitmap Zeichnen. Jedes schwarze Pixel schaltet
später die entsprechende LED in der Matrix. Zum löschen von Pixeln,
einfach Vorder und Hintergrundfarbe Tauschen.
Zuschneiden
Vor dem Speichern wird die Bitmap auf eine passende Größe
zugeschnitten.
Dazu das Rechteck (oben Links im Werkzeugkasten) wählen und den
gewünschten Ausschnitt eingrenzen. Während des ziehen des Rechtecks,
die sich ändernde Breite in der Statusleiste beobachten und eine Breite
wählen, die durch 8
teilbar ist. Nun unter [Bild -> Auf Auswahl
zuschneiden] die
nicht gewünschten Bereiche abtrennen. Es sollten am Anfang und am Ende
der Laufschrift mindestens 3 Pixelin der Breite frei bleiben, damit
eine kurze Pause
zwischen dieser, und der nächsten Sequenz entsteht.
Exportieren
Unter (Datei -> Exportieren] einen Pfad wählen und nach einem Dateinamen mit Endung .bmp, .gif oder .png, die Datei Speichern.
Konvertieren
Um die Bitmap für den AVR-Assembler lesbar zu machen, lädt man die Bitmap in Läubis GrafikConverter 1.4.
Hauptfenster
Nach dem öffnen der Bitmap erhalten wir in etwa folgendes Bild.
Man sollte nach dem Laden der Bitmap, die Auflösung (hier 168*5) und die Anzahl der Farben prüfen. Die X - Auflösung sollte wie oben schon erwähnt, durch 8 teilbar sein. Ist soweit alles klar kann man die Datei Speichern.
Speichern
Im Speichern Dialog, wählt man zunächst Sourcecode -File aus. Die Box darunter, stellt man auf AVR Studio ASM ein. Bei Bytes pro Zeile, eine gerade Anzahl eintragen. Die Datei kann dann als .txt oder .asm File abgespeichert werden.Die gespeicherte Datei kann nun mit einem Texteditor oder direkt im AVR-Studio geöffnet werden und ans Ende des Quellcode kopiert werden. Natürlich kann man die Datei auch separat lassen und an passender Stelle im Quelltext includen. Der Label (Sprungmarke) der erzeugten Datei, sollte noch umbenannt werden, da dieser Satzzeichen enthält bei denen der Assembler meckert.
Download
Hier könnt ihr euch die Eagle Dateien und den Quellcode downloaden.
Viel Spaß beim Basteln,
Jürgen