Inhaltsverzeichnis:

RGB-LED-Matrix - Gunook
RGB-LED-Matrix - Gunook

Video: RGB-LED-Matrix - Gunook

Video: RGB-LED-Matrix - Gunook
Video: How does an RGB LED Matrix work? 2024, Juli
Anonim
Image
Image
Hardware-Design
Hardware-Design

Suche Instructable, und Sie können viele LED-Matrix-Projekte finden. Keiner von ihnen war ganz das, was ich wollte, nämlich die Interaktionen von Hardware- und Softwaredesign zu erforschen, um etwas zu produzieren, und das Endprodukt in einer ordentlichen Leiterplatte mit einem Treiber zu produzieren, der mich mit High-Level auf den "LED-Bildschirm" ziehen lässt Konstrukte (z. B. Zeichnen einer Linie im Gegensatz zum Setzen bestimmter Pixel). Dieser Teil war mir wichtig, da viele der LED-Matrix-Treiber einfach sind und nicht viel bieten, um programmgesteuert ein Bild oder eine Animation zu erstellen. Dies bedeutet nicht, dass Sie mit den anderen Treibern keine Bilder und Animationen erstellen können, sondern dass Sie von Projekt zu Projekt mehr repetitive Arbeiten ausführen müssen.

Also machte ich mich daran, meine Vision zu verwirklichen. Der erste Schritt war das Design der Hardware. Dies war wahrscheinlich die größte Herausforderung für mich, da mein Hintergrund eher Software ist. Auch hier gab es viele vorgebackene Designs, und ich habe sie sicherlich als Inspiration verwendet, aber ich wollte durch das Tun lernen, also habe ich eine 4x4-Matrix auf einem Steckbrett prototypiert. Ich habe durch diesen Prozess viel gelernt, da meine ersten Iterationen nicht funktionierten. Aber ich habe Hardware-Design gemacht, das funktioniert hat, was es mir wiederum ermöglichte, einen Treiber zu entwickeln.

Ich habe das Arduino als meine Treiberplattform gewählt, weil es weit verbreitet ist und viele Referenzen online hat. Während meine berufliche Erfahrung es mir ermöglichte, schneller zu einer funktionierenden Version eines Treibers zu gelangen als meine Hardware-Anstrengungen, gab es immer noch viele Iterationen, während ich die Treiberleistung für den ATMega-Mikrocontroller optimierte und eine Programmier-API entwickelte, die mir gefiel.

Dieses Instructuctable dokumentiert das Design und einige wichtige Erkenntnisse aus meinem Projekt. Weitere Informationen zu diesem Projekt finden Sie auf meiner Website hier, einschließlich vollständiger Kits, die Sie kaufen können, um Ihre eigene RGB-LED-Matrix zu bauen.

Schritt 1: Hardware-Design

Das Hauptziel meines Hardwaredesigns war es, eine Reihe von RGB-LEDs zu erstellen, die ich programmieren konnte, aber ich wollte auch nicht viel Geld ausgeben. Der Ansatz, für den ich mich entschieden habe, bestand darin, 74HC595-Schieberegister zur Steuerung der LEDs zu verwenden. Um die Anzahl der benötigten Schieberegister zu minimieren, ordnete ich die RGB-LEDs in einem Matrix-Layout an, bei dem die gemeinsamen Anoden in Reihen und die roten, grünen und blauen Kathodenleitungen in Spalten miteinander verbunden waren. Für die 4x4-Matrix sah der Schaltplan wie der beigefügte Schaltplan aus.

Eine Sache, die Sie sofort bemerken werden, ist, dass es aufgrund der Matrixschaltung einige LED-Beleuchtungskonfigurationen gibt, die nicht durchgeführt werden können, wenn alle gewünschten LEDs gleichzeitig eingeschaltet sind. Zum Beispiel kann die Matrix nicht gleichzeitig zwei LEDs leuchten, die diagonal zueinander sind, da die Stromversorgung sowohl der Zeilen als auch der Spalten bewirkt, dass die beiden gegenüberliegenden LEDs auf der senkrechten Diagonale zu den gewünschten LEDs leuchten. Um dies zu umgehen, verwenden wir Multiplexing, um jede Zeile zu durchsuchen. Es gibt viele Ressourcen im Internet, die sich mit der Multiplexing-Technik befassen. Ich werde nicht versuchen, sie hier zu replizieren.

Da ich gemeinsame Anoden-LEDs verwende, bedeutet dies, dass die Zeilen positive Leistung liefern und die Spalten auf Masse sinken. Die gute Nachricht ist, dass die Schieberegister 74HC595 sowohl Strom liefern als auch ableiten können, aber die schlechte Nachricht ist, dass sie eine Begrenzung haben, wie viel Strom sie liefern oder ableiten können. Einzelne Pins des 74HC595 haben eine maximale Stromaufnahme von 70 mA, aber es ist am besten, weniger als 20 mA zu halten. Die einzelnen Farben unserer RGB-LEDs haben jeweils eine Stromaufnahme von ca. 20 mA. Dies bedeutet, dass der 74HC595 eine ganze Reihe von LEDs nicht direkt mit Strom versorgen kann, wenn ich sie alle einschalten möchte.

Anstatt die Reihe direkt zu versorgen, steuert der 74HC595 stattdessen einen Transistor für jede Reihe an, und der Transistor schaltet den Strom ein oder aus, der die Reihe versorgt. Da das Design LEDs mit gemeinsamer Anode verwendet, ist der Schalttransistor PNP. Wenn wir eine LED mit gemeinsamer Kathode verwenden würden, wäre der Schalttransistor NPN. Beachten Sie, dass bei Verwendung eines PNP-Transistors zum Ansteuern einer Zeile die Einstellung des Schieberegisters zum Einschalten jetzt niedrig wird, da ein PNP-Transistor eine negative Spannung zwischen dem Emitter und der Basis benötigt, um eingeschaltet zu werden, wodurch positiver Strom in die fließen kann Reihe.

Eine andere zu berücksichtigende Sache ist das gewünschte Bit-Layout der Schieberegister. Das heißt, unter den Schieberegistern steuern welche Bits welche Zeilen oder Spalten in der Matrix. Das Design, mit dem ich gesendet habe, ist, dass das erste Bit oder "höchstwertige Bit", das an die verketteten Schieberegister gesendet wird, das rote Element der LED-Spalte steuert, das zweite Bit das grüne Element der ersten Spalte steuert, das dritte Bit das der ersten Spalte steuert blaues Element, das vierte Bit steuert das rote Element der zweiten Spalte, … dieses Muster wiederholt sich über die Spalten von links nach rechts. Dann steuert das nächste gesendete Bit die letzte oder unterste Zeile, das nächste die vorletzte Zeile, … dies wiederholt sich, bis das letzte gesendete Bit oder "least signifikant bit" die erste oder oberste Zeile in der Matrix steuert.

Schließlich musste ich bestimmen, welche Widerstände ich für jede der LEDs in der RGB-LED verwenden würde. Während Sie die Standardformel verwenden konnten, die die Durchlassspannung und den gewünschten Strom kombiniert, um den erforderlichen Widerstand zu berechnen, stellte ich fest, dass das Einstellen des Stroms jeder LED auf 20 Milliampere zu einer gebrochen weißen Farbe führte, wenn alle roten, grünen und blauen LEDs an waren. Also fing ich an, es ins Auge zu fassen. Zu viel Rot im Weiß bedeutete, den Widerstand der roten LED zu erhöhen, um den Strom zu reduzieren. Ich habe wiederholt Widerstände mit unterschiedlichen Ohm ausgetauscht, bis ich eine Kombination gefunden habe, die eine weiße Farbe erzeugt, die ich für richtig hielt. Die endgültige Kombination war 180 Ω für die rote LED, 220 Ω für die grüne LED und 100 Ω für die blaue LED.

Schritt 2: Hardware-Konstruktion - Steckbrett

Hardware-Konstruktion - Steckbrett
Hardware-Konstruktion - Steckbrett
Hardware-Konstruktion - Steckbrett
Hardware-Konstruktion - Steckbrett

Die erste Phase des Hardwarekonstrukteurs war das Brotboarding. Hier habe ich eine 4x4-Matrix mit den RGB-LEDs gemacht. Diese Matrix würde 16 Bits zur Steuerung benötigen, 12 für die RGB-Spalten und 4 für jede Zeile. Zwei 74HC595-Schieberegister können alles bewältigen. Ich recherchierte und entwarf zuerst eine Schaltung, von der ich dachte, dass sie funktionieren würde, und baute sie dann auf dem Steckbrett auf.

Die wahrscheinlich größte Herausforderung des Steckbrettbaus bestand darin, alle Drähte zu verwalten. Ich nahm einen vorgeformten Drahtsatz für Steckbretter, aber dann war es etwas unhandlich. Ein Trick, den ich als hilfreich empfand, bestand darin, einen "Port" für die Verbindung mit dem Arduino-Board zu erstellen. Das heißt, anstatt die Pins auf dem Arduino direkt mit den verschiedenen IC-Pins auf dem Steckbrett zu verbinden, widmen Sie ein paar Reihen auf dem Steckbrett als Verbindungspunkt für das Arduino und verbinden Sie dann die relevanten ID-Pins mit diesen Reihen. Für dieses Projekt benötigen Sie nur fünf Verbindungen zum Arduino: +5V, Masse, Daten, Takt und Latch.

Sobald der Steckbrettbau fertig war, musste ich ihn testen. Ohne einen Treiber, der die richtigen Signale an die Schieberegister sendet, konnte ich jedoch nicht testen, ob das Hardware-Layout funktioniert.

Schritt 3: Treibersoftware-Design

Image
Image

Aufgrund meiner eigenen beruflichen Erfahrung in der Softwareentwicklung war mir dieser Teil des Projekts wahrscheinlich am klarsten. Ich habe viele der anderen Arduino-basierten LED-Matrix-Treiber untersucht. Es gibt zwar sicherlich gute Treiber, aber keiner hatte das Design, das ich wollte. Meine Designziele des Treibers waren:

  • Stellen Sie eine High-Level-API bereit, um Bilder und Animationen programmgesteuert erstellen zu können. Die meisten Treiber, die ich sah, konzentrierten sich mehr auf hartcodierte Bilder. Da ich von Beruf ein C++-Programmierer bin, wollte ich außerdem ein gutes objektorientiertes Design verwenden, um die Aktivitäten zum Zeichnen in die LED-Matrix zu implementieren und zu verwalten.
  • Verwenden Sie einen doppelt gepufferten Ansatz, um das Bild auf dem Bildschirm zu verwalten. In einen Puffer wird programmgesteuert eingezogen, während der andere den Zustand der Matrixpixel zu einem bestimmten Zeitpunkt darstellt. Der Vorteil dieses Ansatzes besteht darin, dass Sie das nächste Frame-Update für den Bildschirm zwischen den Update-Zyklen des Multiplexings nicht vollständig rendern müssen.
  • Verwenden Sie PWM, um mehr als die sieben Grundfarben zuzulassen, die ein RGB durch einfache Kombinationen der roten, grünen und blauen Elemente rendern kann.
  • Schreiben Sie den Treiber so, dass er mit RGB-LED-Matrizen unterschiedlicher Größe, die meinem allgemeinen Matrixdesign-Ansatz folgten, "einfach funktioniert". Beachten Sie, dass mein Hardware-Design zwar 74HC595-Schieberegister verwendet, aber ich würde erwarten, dass mein Treiber mit jedem Ein/Aus-Mechanismus im Schieberegisterstil arbeitet, der ein ähnliches Bit-Layout wie mein Hardware-Design verwendet. Zum Beispiel würde ich erwarten, dass mein Treiber mit einem Hardware-Design arbeitet, das DM13A-Chips zur Steuerung der Spalten und einen 74HC595-Chip zur Steuerung der Zeilen verwendet.

Wenn Sie sich direkt den Treibercode ansehen möchten, finden Sie ihn hier auf GitHub.

Die erste Iteration meines Treibers war eine kleine Lernkurve über die Fähigkeiten der Arduino-Plattform. Die offensichtlichste Einschränkung ist der RAM, der für Arduino Uno und Nano 2 KB beträgt. Die Verwendung von C++-Objekten in einem solchen Szenario wird aufgrund des Speicheraufwands von Objekten häufig nicht empfohlen. Ich hatte jedoch das Gefühl, dass der Nutzen von Objekten in C++ ihre Kosten (im RAM) überwog, wenn sie richtig gemacht wurden.

Die zweite große Herausforderung bestand darin, herauszufinden, wie wir die Pulsweitenmodulation über die Schieberegister implementieren, damit ich mehr als die sieben primitiven Farben der RGB-LED erzeugen konnte. Nachdem ich viele Jahre auf Linux-Plattformen programmiert hatte, war ich es gewohnt, Konstrukte wie Threads zu verwenden, um Prozesse zu verwalten, die ein konsistentes Timing erfordern. Das Timing des Schieberegister-Aktualisierungsvorgangs ist ziemlich kritisch, wenn ein Treiber für eine LED-Matrix hergestellt wird, die Multiplexing verwendet. Der Grund dafür ist, dass, obwohl das Multiplexing so schnell erfolgt, dass Ihre Augen das Ein- und Ausschalten der einzelnen LEDs nicht sehen können, Sie Unterschiede in der Gesamtgesamtzeit einer der LEDs erkennen können. Wenn eine LED-Reihe über einen längeren Zeitraum konstant leuchtet als die anderen, wird sie während des Multiplexens heller. Dies kann zu einer ungleichmäßigen Helligkeit in der Matrix oder zu einem periodischen Strobing der Matrix als Ganzes führen (dies tritt auf, wenn ein Aktualisierungszyklus länger dauert als die anderen).

Da ich einen konsistenten Timing-Mechanismus benötigte, um zu bewirken, dass die Schieberegisteraktualisierungen zustimmen, der Arduino jedoch Threads formal nicht unterstützt, musste ich meinen eigenen Threading-ähnlichen Mechanismus erstellen. Meine erste Iteration bestand darin, einfach einen Schleifen-Timer zu erstellen, der von der Arduino-Funktion loop () abhing und eine Aktion auslöste, wenn seit dem letzten Auslösen der Aktion eine bestimmte Zeit verstrichen ist. Dies ist eine Form des „kooperativen Multitaskings“. Klingt gut, aber in der Praxis erwies sich dies als inkonsistent, wenn die Feuerrate in Mikrosekunden gemessen wurde. Der Grund dafür ist, dass, wenn ich zwei dieser Schleifen-Timer laufen ließe, eine ihrer Aktionen häufig lange genug dauerte, um die zweite Aktion später als gewünscht auszulösen.

Ich fand, dass die Lösung für dieses Problem darin besteht, den nativen Clock-Interrupt-Mechanismus des Arduino zu verwenden. Dieser Mechanismus ermöglicht es Ihnen, ein kleines bisschen Code in sehr konsistenten Intervallen auszuführen. Also entwarf ich den Treibercode um das Designelement herum, einen Taktinterrupt zu verwenden, um den Code zum Senden der Schieberegister der Matrix beim nächsten Update im Multiplexzyklus auszulösen. Um dies zu tun und Aktualisierungen des Bildschirmbildes zu ermöglichen, um einen aktiven Dump in die Schieberegister nicht zu stören (etwas, das wir als "Race Condition" bezeichnen würden), habe ich einen Ansatz verwendet, bei dem ich Zwillingspuffer für die Schieberegisterbits habe, eins zum Schreiben und einen zum Lesen. Wenn der Benutzer das Matrixbild aktualisiert, erfolgen diese Operationen im Schreibpuffer. Wenn diese Operationen abgeschlossen sind, werden Interrupts vorübergehend ausgesetzt (das bedeutet, dass der Taktinterrupt nicht ausgelöst werden kann) und der Schreibpuffer wird mit dem vorherigen Lesepuffer getauscht und ist nicht der neue Lesepuffer, dann werden die Interpreten wieder aktiviert. Wenn dann die Taktunterbrechung ausgelöst wird, die anzeigt, dass es Zeit ist, die nächste Bitkonfiguration an die Schieberegister zu senden, werden diese Informationen aus dem aktuellen Lesepuffer gelesen. Auf diese Weise findet nie ein Schreiben in einen Puffer statt, aus dem gerade während einer Taktunterbrechung gelesen wird, was die an die Schieberegister gesendeten Informationen verfälschen könnte.

Das Entwerfen des Rests des Treibers war ein relativ einfacher Fall von objektorientiertem Design. Zum Beispiel habe ich ein Objekt erstellt, um das Bitbild des Schieberegisters für einen bestimmten Bildschirmzustand zu verwalten. Durch das Einkapseln des Codes, der sich auf die Bitbildverwaltung bezieht, war das Erstellen des oben erwähnten Zwillingspuffer-Ansatzes selbst eine einfache Übung. Aber ich habe dieses Instructable nicht geschrieben, um die Tugenden des objektorientierten Designs zu preisen. Andere Gestaltungselemente umfassen das Konzept einer Glyphe und eines RGB-Bildes. Eine Glyphe ist ein grundlegendes Bildkonstrukt, das keine angeborenen Farbinformationen enthält. Sie können es sich als Schwarz-Weiß-Bild vorstellen. Wenn das Glyph auf den LED-Bildschirm gezeichnet wird, werden Farbinformationen angezeigt, um anzuzeigen, wie die "weißen" Pixel eingefärbt werden sollen. Ein RGB-Bild ist ein Bild, bei dem jedes Pixel seine eigenen Farbinformationen hat.

Ich empfehle Ihnen, die Arduino-Skizzenbeispiele und die Treiber-Header-Dokumentation zu lesen, um sich mit der Verwendung des Treibers zum Erstellen von Bildern und Animationen auf einer RGB-LED-Matrix vertraut zu machen.

Schritt 4: LED-Ghosting

LED-Ghosting
LED-Ghosting
LED-Ghosting
LED-Ghosting

In einer LED-Matrix ist "Ghosting" das Phänomen, dass eine LED in der Matrix leuchtet, wenn es nicht erwünscht ist, normalerweise ein sehr reduzierter Pegel. Mein ursprüngliches Hardwaredesign war anfällig für Geisterbilder, vor allem in der letzten Reihe. Die Ursache dafür sind zwei Dinge: Transistoren schalten nicht sofort ab und parasitäre Kapazitäten in den RGB-LEDs.

Da wir durch die Zeilen scannen, wird die vorherige Zeile im Scanzyklus aufgrund der Tatsache, dass Transistoren nicht sofort ausgeschaltet werden, immer noch teilweise mit Strom versorgt, wenn die nächste Zeile eingeschaltet wird. Wenn eine bestimmte Spalte, die in der vorherigen Reihe ausgeschaltet war, neu eingeschaltet wird, wenn die neue Reihe mit Strom versorgt wird, leuchtet die LED dieser Spalte in der vorherigen Reihe kurz auf, während sich der Schalttransistor dieser vorherigen Reihe noch dreht aus. Was dazu führt, dass der Transistor eine merkliche Zeit zum Ausschalten braucht, ist die Sättigung in der Basis des Transistors. Dies bewirkt, dass die Kollektor-Emitter-Strecke des Transistors weiterhin leitet, wenn Strom von der Basis entfernt wird, zumindest bis die Sättigung verschwindet. Angesichts der Tatsache, dass unser Multiplexing-Aktualisierungszyklus bewirkt, dass Zeilen absichtlich für einen in Mikrosekunden gemessenen Zeitraum eingeschaltet werden, kann die Zeitspanne, in der der gesättigte Transistor der vorherigen Zeile leitend bleibt, ein merklicher Bruchteil davon sein. Als Ergebnis kann Ihr Auge die winzige Zeit wahrnehmen, in der die LED der vorherigen Reihe eingeschaltet ist.

Um das Sättigungsproblem des Transistors zu beheben, kann dem Transistor zwischen der Basis und dem Kollektor eine Schottky-Diode hinzugefügt werden, um einen kleinen Rückstrom zur Basis zu erzeugen, wenn der Transistor eingeschaltet ist, und verhindert, dass der Transistor gesättigt wird. Dies führt wiederum dazu, dass der Transistor schneller abschaltet, wenn der Strom von der Basis entfernt wird. In diesem Artikel finden Sie eine ausführliche Erklärung dieses Effekts. Wie Sie auf dem Bild in diesem Abschnitt sehen können, ist das Geisterbild ohne die Diode ziemlich auffällig, aber das Hinzufügen der Diode zum Stromkreis für jede Reihe entfernt das Geisterbild erheblich.

RGB-LEDs sind anfällig für ein weiteres Phänomen, das als parasitäre Kapazität bezeichnet wird. Die Ursache dafür ist die Tatsache, dass jede der drei Farb-LEDs in der RGB-LED-Einheit jeweils unterschiedliche Durchlassspannungen hat. Dieser Unterschied in den Durchlassspannungen kann den Effekt der elektrischen Kapazität zwischen jeder der einzelnen LED-Farben verursachen. Da sich beim Einschalten eine elektrische Ladung in der LED-Einheit aufbaut, muss beim Abschalten der Stromversorgung die parasitäre Kapazität entladen werden. Wenn die LED-Spalte ansonsten für die Stromversorgung einer anderen Zeile eingeschaltet ist, entlädt sich die parasitäre Ladung durch diese Spalten-LED und lässt sie kurz aufleuchten. Dieser Effekt wird in diesem Artikel schön erklärt. Die Lösung besteht darin, einen anderen Entladepfad für diese parasitäre Ladung als durch die LED selbst hinzuzufügen und der LED dann Zeit zum Entladen zu geben, bevor die Säule wieder mit Strom versorgt wird. In meinem Hardware-Design wird dies erreicht, indem der Stromleitung jeder Reihe ein Widerstand hinzugefügt wird, der die Stärke mit Masse verbindet. Dies führt dazu, dass mehr Strom gezogen wird, wenn die Reihe mit Strom versorgt wird, stellt jedoch einen Entladungspfad für die parasitäre Kapazität bereit, wenn die Reihe nicht mit Strom versorgt wird.

Es ist jedoch erwähnenswert, dass ich in der Praxis den Effekt der parasitären Kapazität als kaum wahrnehmbar empfinde (wenn Sie danach suchen, können Sie es finden), und daher halte ich das Hinzufügen dieses zusätzlichen Widerstands für optional. Der Effekt der langsamen Auszeit für gesättigte Transistoren ist viel stärker und spürbar. Wenn Sie sich jedoch die drei Fotos in diesem Abschnitt ansehen, können Sie feststellen, dass die Widerstände alle Geisterbilder, die über die langsamen Ausschaltzeiten des Transistors hinaus auftreten, vollständig entfernen.

Schritt 5: Endgültige Herstellung und nächste Schritte

Image
Image

Die letzte Phase dieses Projekts bestand für mich darin, eine Leiterplatte (PCB) zu erstellen. Ich habe das Open-Source-Programm Fritzing verwendet, um meine Leiterplatte zu entwerfen. Obwohl es viele sich wiederholende Aufgaben gab, um 100 LEDs auf einer 10x10-Platine zu platzieren, fand ich diese Phase des Projekts tatsächlich seltsam zufriedenstellend. Herauszufinden, wie jeder elektrische Pfad angelegt werden würde, war wie ein Rätsel, und das Lösen dieses Rätsels führte zu einem Erfolgserlebnis. Da ich nicht in der Lage bin, die Leiterplatten herzustellen, habe ich eine der vielen Online-Ressourcen verwendet, die kleine Auflagen von kundenspezifischen PCBs herstellen. Das Zusammenlöten der Teile war ziemlich einfach, da mein Design alle Durchgangslochteile verwendet.

Zum Zeitpunkt des Schreibens dieses Instructable habe ich die folgenden Pläne für meine RGB-LED-Matrix-Projekte:

  1. Verbessern Sie den Treiber auf der API-Ebene weiter, um dem Programmierer mehr Funktionen auf hoher Ebene zu ermöglichen, insbesondere das Scrollen von Text.
  2. Erstellen Sie größere Matrixdesigns wie 16x16 oder sogar 16x32.
  3. Erkunden Sie die Verwendung von MOSFETs anstelle von BJTs für die Reihenstromschaltung
  4. Erkunden Sie die Verwendung von DM13As-Konstantstromtreibern anstelle von 74HC595s für die Spaltenumschaltung
  5. Erstellen Sie Treiber für andere Mikrosteuerungsplattformen wie Teensy, ODROID C2 oder Raspberry Pi.

Beachten Sie, dass sowohl das Hardwaredesign als auch der Treiber unter der GPL v3-Open-Source-Lizenz in diesem GitHub-Repository veröffentlicht wurden. Außerdem bekomme ich, obwohl die PCB-Hersteller "kleine Auflagen" meines PCB-Designs herstellen, immer noch viel mehr, als ich persönlich brauche. Daher verkaufe ich komplette Kits für meine verschiedenen RGB-LED-Matrix-Designs (PCB und alle Teile enthalten) von meiner Website hier.

Empfohlen: