Diesen Text habe ich erst 2015 aus dem alten CMS übernommen, der war 2011 noch nicht im Blog.

Testschaltung auf dem Steckbrett

Testschaltung auf dem Steckbrett

Ich habe noch nicht viele Mikrokontroller-Projekte gemacht, aber mehr als eines beinhaltete die Steuerung von LEDs mittels Pulsweitenmodulation (PWM). Mit einer oder mehr LEDs ist das eine Sache die den kleinen Controller schon halbwegs stresst, aber wenn der Controller neben dem Dimmen von LEDs auch noch andere mehr oder weniger komplizierte Aufgaben hat geht einem schnell das Timing in die Brüche mit denen die LEDs angesteuert werden. Ganz zu schweigen vom Programmcode, der mit jeder weiteren Aufgabe unleserlicher wird die ‚zur gleichen Zeit‘ ablaufen soll.

In meinem nächsten Projekt muss ich wieder LEDs faden, daher habe ich nach einem einfacheren Weg gesucht das zu machen. Das Projekt umfasst das Lesen von Speicherkarten, Kommunikation mit einer Echtzeituhr und die Ausgabe von Text auf einem LCD-Display, also bin ich fast sicher dass ich es nicht hinkriegen würde fünf Kanäle zuverlässig zu steuern. Und so viele werden es wohl mindestens werden.

Der erste Plan war, einen fertigen Chip dafür zu benutzen. Ich habe mich umgesehen und das beste was ich fand war ein Teil von Philips (PCA-irgendwas, ich habe die Nummer vergessen), das über einen I2C-Bus gesteuert werden kann. Das Teil kann bis zu acht LEDs ansprechen, aber neben ‚an‘ und ‚aus‘ gibt es nur zwei Helligkeiten die man den Ausgängen zuweisen kann. Diese sind dann wiederum variabel, aber trotzdem kann man so nicht einen Kanal mit 20%, einen mit 50% und einen mit 80% belegen. Außerdem gibt es das Teil nur als SMD, und meine Fähigkeiten am Lötkolben reichen für die Verarbeitung so kleiner Teile leider nicht aus.

Also wuchs der Plan, einen separaten Controller für die Ansteuerung der LEDs zu nehmen, der von einer Art ‚Hauptprozessor‘ angesprochen wird — idealerweise mittels I2C-Bus, da ich ja später noch mehrere andere Geräte benutzen möchte die an den gleichen Bus kommen könnten. Also habe ich einen ATtiny2313 in mein Breadboard gesteckt, den mit einem 20MHz-Quarz getaktet, und wir haben versucht so viele LEDs wie möglich zu steuern…

Pulsweitenmodulation

Die Helligkeitssteuerung von LEDs wird üblicherweise mit Pulsweitenmodulation gemacht. Ich habe das auch schon in mehreren Projekten benutzt.

Was bisher geschah

Bis jetzt habe ich immer alle LEDs eingeschaltet die eine Helligkeit grösser als 0 annehmen sollten, abgewartet bis die erste LED ausgeschaltet werden muss, die LED ausgeschaltet, auf die nächste gewartet, und so weiter. Nach einer bestimmten Zeit sind alle LEDs aus und ich fange von vorne an.

Ich versuche mal, das an einem kleinen Bild zu verdeutlichen:

In diesem Beispiel dauert ein kompletter Durchlauf des PWM-Zyklus 50 Zeiteinheiten. Die erste LED ist die ganze Zeit durch eingeschaltet (100%), die zweiter für 40 von 50 Zeiteinheiten (80%), die dritte für zehn (20%) und die fünfte für 30 Zeiteinheiten (60%). Die vierte LED ist aus (0%). Man sieht, dass der PWM-Zyklus nach 50 Zeiteinheiten von vorn beginnt.

Ein Nachteil dieser Technik ist, dass sie langsam ist. Und sie wird mit jedem weiteren Kanal den man ansteuern möchte langsamer. Wir haben es versucht, aber wir waren auf diese Weise nicht in der Lage mehr als fünf LEDs anzusteuern ohne dass sie sichtbar anfingen zu flackern.

Wir haben auch versucht, alle Zustände der Pulsweitenmodulation in einem Array abzulegen, so dass der Algorithmus nur noch durch das Array wandern und die jeweiligen Werte darstellen muss. Das ging aber auch nicht, weil unser Controller nicht über genügend RAM verfügt um so ein Array abzulegen.

Thomas‘ Idee

Nach einigen Tests die mehr oder weniger schlechte Ergebnisse brachten hatte Thomas eine großartige Idee wie man die PWM implementieren könnte. Sie arbeitet auch mit einem Array für alle Zustände, allerdings werden die Zustände nicht gleich lange dargestellt. Der erste Status wird nur für eine Zeiteinheit angezeigt, der zweite für zwei Einheiten, der dritte für vier, und so weiter. Auf die Weise werden die LEDs zwar während eines PWM-Zyklus‘ mehr als nur einmal an- und ausgeschaltet, aber das tut niemandem weh.

Ich versuche mich noch einmal an einem Bildchen:

Hier sehen wir also eine Pulsweitenmodulation mit acht Kanälen, die bis zu 64 verschiedene Helligkeiten annehmen können. Kanal 1 wird nur für eine Zeiteinheit eingeschaltet, Kanal 2 für zwei Einheiten, und so weiter. Interessant ist der fünfte Kanal: die LED wird für eine Zeiteinheit ein-, dann für zwei Einheiten aus-, und dann wieder für vier Einheiten eingeschaltet.

Wir sehen uns mal ein komplexeres Beispiel an — in dem auch hellere LEDs vorkommen:

Die Kanäle 1 bis 8 zeigen die Helligkeiten 33, 18, 23, 32, 21, 63, 64 und 24.

Helligkeit 75 auf dem Oszilloskop

Helligkeit 75 auf dem Oszilloskop

Der Vorteil dieser Technik ist, dass man sich einerseits nur eine begrenzte Anzahl von Zuständen merken muss (sechs in diesem Beispiel), und andererseits die Schleife durch die Zustände sehr einfach ist: Status n wird an die Ausgänge geschickt, dann wird für 2^(n-1) Zeiteinheiten gewartet, dann folgt der nächste Zustand.

Jeder Zustand wird durch ein Bitmuster dargestellt, das im jeweiligen Schritt an die Ausgänge geschickt wird. Mit anderen Worten: eine Spalte die im obigen Bild am Anfang einer Wartezeit steht. In diesem Beispiel haben wir also sechs Zustände: 01010101, 01100110, 01110100, 11100000, 11110110 und 01101001. Der erste wird für eine Zeiteinheit dargestellt, der zweite für zwei Einheiten, der dritte für vier, und so weiter…

Ein weiterer Vorteil dieser Technik ist, dass die Anzahl der Ausgänge fast unerheblich für die Systemlast ist. Nur wenn neue Helligkeiten angefordert werden muss der Algorithmus die Zustände neu berechnen, aber das ist schnell gemacht. Mit diesem Algorithmus ist es also möglich, unterschiedliche Helligkeiten auf allen freien Pins eines Controllers anzuzeigen. Für einen ATtiny2313 heisst das, dass man 13 LEDs faden kann während man immer noch in der Lage ist mittels I2C mit anderen Geräten zu kommunizieren!

Kommunikation via I2C

I2C zu sprechen ist zwar keine Raketenwissenschaft, aber da das eine Menge mit Bit-Shifterei zu tun hat wenn man es implementieren will habe ich da eine fertige Bibliothek benutzt.

Genommen habe ich die Bibliothek von Donald R. Blake, er hat die freundlicherweise unter die GPL gestellt und sie auf avrfreaks.net veröffentlicht. Man findet das originale Posting im Thread ‚8 bit communication between AVR using TWI‚, und einige Nachträge in ‚I2C Slave on an ATtiny45‚.

Danke für die Arbeit, Donald! Und dafür dass Du eine freie Lizenz benutzt hast.

Da sein Paket nur als Attachment im Forum erhältlich zu sein scheint, und ich mir nicht sicher bin für wie lange das der Fall sein wird, habe ich es in den Tarball dieses Projektes mit aufgenommen.

Benutzung

Man sollte dieses Gerät benutzen können wie jeden anderen I2C-Slave auch:

Anschließen

Die folgenden Pins des Controllers müssen mit der Schaltung verbunden werden:

  • Pin 1 – Reset – sollte über einen 10k-Widerstand an VCC angeschlossen werden
  • Pin 4 und 5 – XTAL1 und XTAL2 – verbunden mit einem 20MHz-Quarz, dann mit 22p-Kondensatoren an GND
  • Pin 10 – GND – Masse
  • Pin 17 – SDA – I2C-Daten
  • Pin 19 – SCL – I2C-Takt
  • Pin 20 – VCC – 5V

Die I2C-Daten und -Taktleitungen sollten mit 4,7k-Widerständen terminiert werden um die Leitungen auf VCC hoch zu ziehen. An alle übrigen Pins können LEDs angeschlossen werden. Die Anordnung ist wie folgt:

  • Pin 2 – PD0 – Kanal 0
  • Pin 3 – PD1 – Kanal 1
  • Pin 6 – PD2 – Kanal 2
  • Pin 7 – PD3 – Kanal 3
  • Pin 8 – PD4 – Kanal 4
  • Pin 9 – PD5 – Kanal 5
  • Pin 11 – PD6 – Kanal 6
  • Pin 12 – PB0 – Kanal 7
  • Pin 13 – PB1 – Kanal 8
  • Pin 14 – PB2 – Kanal 9
  • Pin 15 – PB3 – Kanal 10
  • Pin 16 – PB4 – Kanal 11
  • Pin 18 – PB6 – Kanal 12
Ansprechen

In meinen Tests habe ich einen ATmega8 mit der I2C-Bibliotkek von Peter Fleury (http://jump.to/fleury — auch an Ihn Dank für die freie Lizenz!) als I2C-Master benutzt.

Eine typische Funktion um den Dimmer anzusprechen sieht wie folgt aus:

Beispiele

I2C-Dimmer auf dem Testbrett

Hier sieht man alle LEDs in verschiedenen Geschwindigkeiten faden.


Der Code auf dem I2C-Master der dieses Muster erzeugt sieht in etwa wie folgt aus:

Sichtbare PWM

Hier sieht man das Signal einer LED, die von 0 bis 127 fadet. Leider hat mein Oldtimer-Oszilloskop im mittleren Teil Probleme korrekt zu triggern.


Dies ist der Code der auf dem I2C-Master lief:

Nachteile

Bis jetzt hat das Teil in allen getesteten Situationen prima funktioniert. Alles läuft wie geplant.

Ich schätze, dass dieser Dimmer im Vergleich zu fertigen Controller-ICs etwas langsam ist. Ich kann zwar kein Flackern in den LEDs erkennen, da sie immer noch ziemlich schnell geschaltet werden (etwa einmal alle 6ms, also ein Flackern mit 166Hz — zu schnell für mich).

Danke!

Wieder mal geht mein besonderer Dank an Thomas Stegemann. Er hatte die tolle Idee für den PWM-Algorithmus, und ich bin immer wieder beeindruckt von der Geduld mit der er mir eine dermaßen kranke Sprache wie C näher bringt…

Lizenz

Dieses Projekt steht unter der GNU General Public License (GPL). Eine Kopie der GPL liegt dem Paket in der Datei License.txt bei.

Download

Dieser Text ist erst 2015 von meinem alten CMS in den Blog gewandert.

Testschaltung auf dem Steckbrett

Testschaltung auf dem Steckbrett

Dieses Projekt macht aus einem AVR ATmega8 Mikrocontroller einen LED-Controller für eine Matrix aus 8×8 LEDs. Der Controller verhält sich als I2C-Slave, die anzuzeigenden Bitmuster können also über diesen Bus (der auch als TWI bekannt ist, Two Wire Interface) geschickt werden.

Sinn und Zweck

In meinem nächsten grösseren Projekt will ich Zahlenwerte auf Siebensegmentanzeigen ausgeben. Ich habe vor einer Weile eine Menge von diesen Dingern gekauft, jetzt kommen sie zum Einsatz. Das sind vierstellige mit einem zwölfpoligen Anschluss an der Unterseite. Acht Pins für die Kathoden der LEDs (sieben Segmente plus Punkt) und vier Anoden, eine für jede Ziffer.

Man kann sich diese Module als Matrix aus vier mal acht LEDs vorstellen, wie in dem Schaltplan hier dargestellt wird. Ich benutze zwei von den Modulen, also habe ich eine Matrix aus acht mal acht LEDs.

Die Zeilen und Spalten dieser Matrix werden an den Mikrocontroller angeschlossen, so dass der die Lampen Zeile für Zeile befeuern kann. Das hat zwei Vorteile: erstens sind maximal acht LEDs gleichzeitig an, das drückt den Stromverbrauch. Und zweitens braucht man auf diese Weise nur 16 Pins um 64 LEDs anzutreiben.

Durch diese Art der Ansteuerung flackert die Ausgabe natürlich etwas, aber der Controller ist schnell genug damit man das mit dem bloßen Auge nicht sehen kann.

Ich hätte meine Displaymodule natürlich auch direkt an den Hauptcontroller des nächsten Projektes anschließen können, aber da habe ich nicht mehr genug freie Pins. Außerdem wird das Programm auf dem Hauptcontroller übersichtlicher wenn das Multiplexen der LEDs woanders geschieht, da ich mich nicht um irgendein Timing kümmern muss. Also ist ein billiger ATmega8 ein prima LED-Treiber, und ich sage dem per I2C was er anzeigen soll.

I2C sprechen

Der ATmega8 hat ein eingebautes Hardware-I2C-Interface, also braucht es nicht allzu viel Code um I2C zu sprechen. Trotzdem habe ich mir von roboternetz.de die kleine Bibliothek gezogen, die Uwe Grosse-Wortmann (uwegw) geschrieben hat. Ich habe die nur etwas umformatiert um den Code meinem Programmierstil anzupassen. Nein, ich habe die Kommentare nicht gelöscht… ;-)

Benutzung

Am anderen Ende der Kommunikation habe ich die großartige Procyon AVRlib von Pascal Stang benutzt. Ein einfaches Code-Beispiel um mit der I2C LED Matrix zu sprechen sieht so aus:

Der Schaltplan

Der Schaltplan

Man bemerke: der Buffer hält nicht wirklich die Zahlen die auf dem Display dargestellt werden sollen, zumindest nicht in diesem Beispiel. Da sind nur die Bitmuster drin.

Zahlen anzeigen

Wenn man Siebensegmentanzeigen an den Controller anschließt um darauf Zahlen anzuzeigen müssen die auf der Master-Seite des Busses definiert werden. Ich habe die Definitionen nicht in dieses Projekt aufgenommen um dem Master die volle Kontrolle über die LEDs zu geben, selbst wenn keine Zahlen angezeigt werden sollen.

Außerdem hängt die Darstellung davon ab wie die Displays an den Controller angeschlossen sind. Ich weiß nicht ob die Pinbelegung irgendwie standardisiert ist.

Um ein Beispiel zu geben wie sowas gebaut wird, hier ist ein Codeausschnitt der mit meinem Display funktioniert:

Nachteile

Bis jetzt hat das Teil in allen getesteten Situationen prima funktioniert. Alles läuft wie geplant.

Danke!

Ich danke den Autoren der Bibliotheken die ich benutzt habe: Uwe Grosse-Wortmann (uwegw) für die I2C-Slave-Bibliothek und Pascal Stang für seine Procyon AVRlib.

Lizenz

Dieses Projekt steht unter der GNU General Public License (GPL). Eine Kopie der GPL liegt dem Paket in der Datei License.txt bei.

Download

I2C LED MatrixSchlag auf Schlag: Ich habe nicht vor, jetzt jede Woche ein neues Projekt auf die Seite zu stellen. Ideen hätte ich genug, aber nicht ansatzweise die Zeit um alles umzusetzen. Im Moment drängt es mich aber etwas, mein nächstes größeres Projekt fertig zu kriegen, unter anderem habe ich deshalb auch letzte Woche schnell die Tastatur fertig gemacht. Hier geht es um einen Teil des nächsten Projektes.

Vor einer ganzen Weile habe ich mal billig einen Posten Siebensegmentanzeigen gekauft. Die sollen jetzt mal zum Einsatz kommen. Grün, vierstellig, gemeinsame Anode (letzteres ist der Grund warum ich doch nicht auf Charlieplexing zurückgreifen kann). Die haben also 12 Pins an der Unterseite: acht Segmente und jeweils eine Anode pro Ziffer. Ich werde zwei davon brauchen. Die Segmentanschlüsse kann ich jeweils verbinden, die Anoden muss ich vom Controller aus einzeln ansteuern. Also acht Segmente plus acht Anoden, macht 16 Pins. So viel habe ich nicht frei.

Sicher könnte man da was mit anderen Bausteinen machen, ich habe mir meinen eigenen gebaut. Einen ATmega8 der per I2C zu steuern ist, und der diese Aufgabe spielend übernehmen kann. So brauche ich an meinem ‚Hauptprozessor‘ nur noch die zwei Pins für den I2C-Bus. Außerdem verlagert sich der Job, die LEDs zu Multiplexen in den anderen Controller. So muss ich beim Programmieren auch nicht auf das Timing achten damit die LEDs nicht flimmern.

Das ganze habe ich schön dokumentiert und freigegeben, unter dem nicht sehr originellen Namen I2C LED Matrix.

‚Matrix‘ deshalb weil man an den Baustein einfach eine Matrix aus 8×8 LEDs anschließen kann. Das müssen nicht unbedingt Siebensegmentanzeigen sein. Der Vorteil ist, dass man so beliebige Zeichen darstellen kann, Nachteil dieser Flexibilität ist allerdings auch dass man sich die Zeichen auf dem steuernden Controller erstmal definieren muss. Naja, schwer ist das aber auch nicht, ein Beispiel habe ich auf der Seite.

Vielleicht kann das ja jemand gebrauchen. Und bevor die Befürchtung aufkommt dass es hier jetzt nur noch uC-Basteleien gibt: ich fürchte bis das angekündigte größere Projekt fertig wird, wird einige Zeit ins Land gehen… hoffentlich nur ein paar Wochen, aber… wer weiß?