Pin-Maximierung mit Multiplexing und Charlieplexing
Eine der größten Herausforderungen bei der Auswahl eines Mikrocontrollers (MCU) besteht darin, einen Controller mit genügend Pins für die Aufgabe zu finden, das im Rahmen des Budgets liegt. In der Regel ist ein 64-Pin-Baustein teurer als ein 32-Pin-Baustein. Etwa 10 bis 15 % dieser Pins sind Stromversorgungspins. Der Rest ist eine Mischung aus digitalen und analogen Pins sowie Pins für spezielle Anwendungsfälle.
So gibt es beispielsweise einen Reset-Pin, Pins für den Quarzoszillator und vielleicht einen speziellen Pin zur Unterstützung eines Bootloaders. Und manchmal sind Pins speziell für die Verwendung mit bestimmten Peripheriegeräten wie USB oder I2C vorgesehen, weil die Schaltung um sie herum ein wenig anders ist.
Nehmen wir also an, wir haben festgestellt, dass unsere Anwendung 20 rein digitale Pins benötigt, vielleicht für Eingangsschalter und die Steuerung von LEDs für eine Mensch-Maschine-Schnittstelle. Auf einer 32-poligen MCU subtrahieren wir die Stromversorgungspins (z. B. 6), die reinen Analogpins (z. B. 8), USB und I2C (z. B. 4), und es bleiben nur 14 Pins übrig. Können man also, wenn man es von der kommerziellen Seite betrachtet, die Wahl einer teureren MCU mit einer höheren an Pins rechtfertigen, bei der nicht alle Pins verwendet werden? Oder kann man mit etwas technischer Raffinesse aus 14 Pins 20 Signale machen?
Das Multiplexing begann mit dem Telegraphen
Die Idee, mehr aus einer einzigen elektrischen Verbindung herauszuholen, begann mit dem Telegrafen. Nachdem Morse und seine Freunde herausgefunden hatten wie man Datenbits über weite Entfernungen per Draht verschicken konnte, war klar, dass das ständige Hinzufügen von Leitungen zur Erhöhung der Kapazität teuer sein würde. Und nicht nur das, es bedeutete auch mehr Arbeit für das Team, das das Netz unterhielt.
Natürlich begannen einige kluge Köpfe der damaligen Zeit darüber nachzudenken, ob diese einzelnen Leitungen von mehreren Telegrafisten gemeinsam genutzt werden könnten, so dass zwei oder mehr Nachrichten über jeden der vorhandenen Drähte gesendet werden könnten. Einer von ihnen war Émile Baudot.
Das System musste auf Empfangs- und Sendeseite synchronisiert werden. Auf der Empfangsseite drehte sich ein Typenrad, ähnlich einem Typenraddruckkopf, kontinuierlich. Auf der Senderseite wurden alle Buchstabentasten in der gleichen Reihenfolge abgetastet. Wurde eine Taste gedrückt, so wurde der entsprechende Buchstabe des Typenrads aktiviert und auf einen Papierstreifen gedruckt. Dadurch wurde die Übertragung von Nachrichten auf etwa 40 Wörter pro Minute begrenzt (ein Wort bestand im Durchschnitt aus fünf Buchstaben plus Leerzeichen).
Diese Herausforderung wurde durch ein neues Kodierungsschema gelöst, das für jeden Buchstaben die gleiche Anzahl von symbolen gleicher Länge vorsah. Sein System besteht aus fünf Bits und verwendete positive und negative Impulse, um jeden Buchstaben zu übertragen. Durch die Synchronisierung von Empfangs- mit Sendeseite konnten bis zu sechs Benutzer gleichzeitig Nachrichten über eine einzige Leitung senden. Nun, so sah es zumindest aus. In Wirklichkeit handelte es sich um ein Zeitmultiplexsystem, das jedem Telegrafisten ein Sechstel eines Zeitschlitzes für die Übertragung des nächsten Briefes zur Verfügung stellte.
Multiplexing für LEDs
Siebensegment-LEDs und Matrixtastaturen sind seit Jahrzehnten ein fester Bestandteil elektronischer Systeme. Schon bevor MCUs alltäglich wurden, suchten Elektronikingenieure nach Möglichkeiten, die Anzahl der für die Implementierung dieser Komponenten erforderlichen Signale zu verringern.Nehmen wir als erstes Beispiel LED-Anzeigen mit sieben Segmenten. Wenn man den Dezimalpunkt mitzählt, enthalten diese Bauteile acht LEDs. Will man eine Stromversorgung bauen, benötigt man wahrscheinlich insgesamt vier Ziffern (XX.YY), um die Spannung oder den Strom anzuzeigen. Das bedeutet, dass wir 8 x 4 = 32 Pins benötigen - das ist eine ganze Menge.
Wenn wir also die gleichen LED-Segmente jeder Ziffer an den gleichen MCU-Pin anschließen, können wir 24 Pins einsparen. Um zu bestimmen, welche unserer vier Siebensegment-Anzeigen angesteuert wird, benötigen wir vier Pins, um eine der gemeinsamen Kathoden mit Masse zu verbinden. Um 32 LEDs anzusteuern benötigen wir also 8 + 4 = 12 Pins - 20 weniger als ein Pin pro LED.
Multiplexing für Matrix-Tastaturen
Der gleiche Ansatz kann für eine Matrix von Drucktastern als Eingabeeinheit für ein Embedded System verwendet werden. Wenn man nur zwei oder drei Schalter hat, kann man diese wahrscheinlich mit einem Pull-Up/Down-Widerstand kombinieren und ihren Status mit der gleichen Anzahl von GPIOs erkennen, die als Eingänge konfigurierten sind.
Ab etwa sechs Schaltern kann es jedoch sinnvoll sein, eine Matrix zum Auslesen der Schalter zu implementieren. Anstatt die Schalter über Pull-up-Widerstände mit der Stromversorgung zu verbinden werden die Schalter an einen GPIO-Ausgang angeschlossen. Wenn der Ausgang High ist und der Schalter gedrückt wird, erkennt der Eingang dies als 1. Man muss die Widerstände allerdings beibehalten um zu vermeiden, dass Vcc über die GPIOs gegen Masse kurzgeschlossen wird.
Um eine Matrix zu erstellen, müssen die Schalterketten durch einige GPIO-Pins zyklisch als Ausgänge geschaltet werden.
Wir beginnen mit sechs Schaltern und gruppieren sie in zwei Dreiergruppen. Bei jeder Dreiergruppe ist eine Seite mit einem GPIO-Ausgang verbunden. Dann gruppieren wir sie in Zweiergruppen, wobei die andere Seite jedes Schalters mit einem GPIO-Eingang verbunden ist.
// INITIALIZE PINS
SET D0 as OUTPUT
SET D1 as OUTPUT
SET D0 LOW
SET D1 LOW
// SCAN BUTTONS
SET D0 HIGH
READ D2, D3, D4 and STORE STATE as BUTTON 1, BUTTON 2, BUTTON 3
SET D0 LOW
SET D1 HIGH
READ D2, D3, D4 and STORE STATE as BUTTON 4, BUTTON 5, BUTTON 6
SET D1 LOW
Es ist wichtig, die Abfrage der Spalten schnell genug zu durchlaufen, damit die Eingabemethode schnell genug reagiert. Der Mensch wertet eine Reaktionszeit von unter 200 ms als "sofort", daher sollte man die gesamte Drucktastenmatrix mindestens fünfmal pro Sekunde abfragen. Diese Methode eignet sich auch zur Erkennung von Tastenkombinationen, mit deren Hilfe mehr Benutzerschnittstellenfunktionen als Tasten zur Verfügung stehen können.
Charlieplexing mit LEDs
Multiplexing reduziert bereits die Anzahl der zur Steuerung von LEDs benötigten GPIOs, Charlieplexing benötigt noch weniger Pins! Dabei wird die Tatsache genutzt, dass MCU-GPIO Pins drei Zustände haben: High und Low als Ausgang und hohe Impedanz als Eingang. Im einfachsten Fall können wir zwei LEDs mit entgegengesetzter Polarität zwischen zwei MCU-Pins anschließen. Wenn die Pins als Ausgänge konfiguriert sind leuchtet eine der LEDs auf, wenn ein Pin auf High und der andere auf Low ist. Bei umgekehrten Ausgangspegeln leuchtet die andere LED. Um sie auszuschalten, setzt man einfach beide GPIOs als Eingänge.
// INITIALIZE PINS
SET D0 LOW
SET D1 LOW
SET D0 as INPUT
SET D1 as INPUT
// TURN ON LED 2
SET D0 as OUTPUT
SET D1 as OUTPUT
SET D1 HIGH
SET D0 LOW
// TURN ON LED 1
SET D1 LOW
SET D0 HIGH
// TURN LEDS OFF
SET D0 as INPUT
SET D1 as INPUT
SET D0 LOW
SET D1 LOW
So weit, so unspektakulär. Wir haben zwei GPIOs verwendet, um zwei LEDs zu steuern. Der Spaß beginnt erst, wenn wir einen zusätzlichen GPIO hinzufügen ... und vier weitere LEDs. Wir fügen zwei weitere LEDs mit entgegengesetzter Polarität zwischen GPIO eins und drei und zwei zwischen GPIO zwei und drei hinzu. Um eine einzelne LED zu steuern, muss ein GPIO als High-Ausgang, einer als Low-Ausgang und der dritte als Eingang konfiguriert werden.
// INITIALIZE GPIOs
SET D0 LOW
SET D1 LOW
SET D2 LOW
SET D0 as INPUT
SET D1 as INPUT
SET D2 as INPUT
// TURN ON LED1
SET D0 HIGH
SET D1 LOW
SET D0 as OUTPUT
SET D1 as OUTPUT
// TURN ON LED4
SET D0 LOW
SET D1 LOW
SET D0 as INPUT
SET D2 HIGH
SET D1 LOW
SET D2 as OUTPUT
Output Pins | LED1 | LED2 | LED3 | LED4 | LED5 | LED6 |
D0 | OUT HIGH | OUT LOW | INPUT | INPUT | OUT HIGH | OUT LOW |
D1 | OUT LOW | OUT HIGH | OUT HIGH | OUT LOW | INPUT | INPUT |
D2 | INPUT | INPUT | OUT LOW | OUT HIGH | OUT LOW | OUT HIGH |
Da zwischen den Pins 1 und 3 zwei LEDs in Reihe geschaltet sind (Arduino D0 und D2 im untenstehenden Schaltplan), kann man sich zu Recht fragen, warum diese LEDs nicht beide aufleuchten, wenn man versucht, eine einzelne LED zwischen diesen Pins einzuschalten. Dies ist ein Risiko, hängt aber von der niedrigen MCU-Versorgungsspannung und der Durchlassspannung der LEDs ab. Bei einer Versorgungsspannung von 3,3 V beträgt die Spannung an den beiden LEDs 3,3 ÷ 2 = 1,65 V, damit nicht genug, um eine LED zum Leuchten zu bringen. Der Betrieb mit 5,0 V ist daher problematisch.
Wie beim Multiplexing kann auch beim Charlieplexing die Einschaltzeit des High Ausgangspins gesteuert werden, um die Helligkeit der LED zu verändern. Dies erfordert einen Timer und dessen Interrupt sowie einige Schaltanweisungen. Da Charlieplexing so viele Möglichkeiten eröffnet, erläutert eine kleine Formel, wie viele LEDs von wie vielen Pins gesteuert werden können.
LEDs = GPIOs × (GPIOs - 1)
Für unsere vier Siebensegment-Anzeigen (32 LEDs) von vorhin bräuchten wir also sieben GPIOs und könnten immer noch bis zu 10 weitere LEDs für andere Zwecke anschließen.
Warum also Charlieplexing?
Der Begriff Charlieplexing stammt von einem Ingenieur bei Analog Devices, Charlie Allen, der sich für die Anwendung dieser Technik innerhalb des Unternehmens einsetzte. Infolgedessen wurde sein Name zu einer Art Kurzform für die Bezeichnung dieses Steuerungsansatzes. Analog Devices stellt tatsächlich einige spezielle Siebensegmenten LED-Treiber her, wie z. B. den MAX6950.Dieser 16-Pin-Chip kann bis zu fünf Siebensegment-Anzeigen oder 40 diskrete LEDs ansteuern. Nur acht der Pins werden für die Steuerung der LEDs verwendet. Die verwendete Steuermethode ist etwas anders als die oben beschriebene, wobei eine Stromquelle die LEDs versorgt und MOSFETs den Pfad zur Masse für die gemeinsame Kathode bereitstellen. Die Stromquelle ist von 2,5 mA bis 37,5 mA einstellbar und ermöglicht die Steuerung der LED Helligkeit. Eine MCU steuert den LED-Treiber über SPI. Bei Bedarf können mehrere Treiber hintereinander geschaltet werden, um weitere segmentierte Anzeigen zu steuern.