Charlieplexing

Aufgabenstellung

    1. Informieren Sie sich über die Funktionsweise des “Charlieplexing” (erste Anlaufstelle: Hintergrundinfos weiter unten).
    2. Wie viele LEDs können Sie mit drei IO-Pins ansteuern?
    3. Bauen Sie diese LEDs auf einem Breadboard so auf, dass sie in einer Reihe hintereinander stehen und verschalten Sie diese so, dass die LEDs mittels Charlieplexing angesteuert werden können.
    4. Testen Sie die Schaltung indem Sie manuell Spannung an die drei Anschlusspunkte (dort wo später die IO-Pins angeschlossen werden) geben.
    5. Entwerfen Sie ein VI in LabVIEW, so dass stets eine LED für eine Sekunde an ist. Wenn diese dunkel wird soll die nächste LED leuchten. Dies soll permanent weiterlaufen.
    6. Ändern Sie das VI so ab, dass stets zwei LEDs gleichzeitig angehen. Nach einer Sekunde sollen die nächsten beiden LEDs leuchten, usw. Dies soll endlos so weiterlaufen.
    7. Dokumentieren Sie die erstellte Soft- und Hardware (nutzen Sie dafür z.B. die Software von Fritzing.org).

Hintergrundinfos

Grundsätzliches

Charlieplexing ist eine Erweiterung des Multiplexings. Damit ist es möglich sehr viele LEDs mit nur wenigen Portpins anzusteuern.

Es wurde – wie der Name vermuten lässt – von einem gewissen Charlie Allen entwickelt und ist eigentlich eine Erweiterung des Multiplexing-Verfahrens. Beim Charlieplexing wird sich einerseits zu Nutze gemacht, dass LEDs den Strom nur in eine Richtung leiten und erst ab einer gewissen Flussspannung anfangen Strom zu leiten. Andererseits, dass das IC, das die LEDs ansteuert – beispielsweise ein Mikrocontroller – fähig ist, seine Ausgänge sowohl auf “High”, “Low” als auch “Hochohmig” zu schalten.

Funktionsprinzip

Das ganze funktioniert folgendermaßen:
Angenommen IO1 ist High, dann können IO2, IO3 und IO4 auf Low sein um die LEDs A, C und E zum leuchten zu bringen. Ist einer von diesen drei Pins nicht Low dann dürfen sie auch nicht High sein sondern müssen auf Hochohmig geschaltet werden.

Angenommen IO2 wäre ebenfalls High, dann könnte von dieser Leitung aus Strom über die LEDs G und I nach IO3 bzw IO4 fließen. Das war der erste von vier Multiplexschritten.

Im nächsten Schritt wird IO2 auf High geschaltet. Nun können IO1, IO3 und IO4 auf Low geschaltet sein und somit die LEDs B, G und I zum Leuchten gebracht werden.

Und so funktioniert das auch in den beiden nächsten Schritten mit IO3 und IO4. In einem Schritt können immer 3 LEDs gleichzeitig leuchten, wir haben also 4 Multiplexingschritte. Ein Pin ist in jedem Schritt immer High, die anderen entweder auf Low (womit die jeweilige LED leuchtet) oder auf Hochohmig geschaltet.

Soll bei vier Portpins jeweils nur eine LED leuchten, so ergibt sich nebenstehende Wahrheitstabelle (wobei “L” für Low, “H” für High und “I” für Input steht).

Natürlich lässt sich das ganze nun noch durch mehr Portpins erweitern. Generell gilt, dass mit n Portpins im Gesamten n*(n-1) LEDs angesteuert werden können. Stehen also 5 Portpins zur Verfügung, so können 20 LEDs angesteuert werden.

Strombegrenzung

So kann man das noch nicht verwenden. Warum?
Die IO-Pins begrenzen normalerweise nicht den Stromfluss, d.h. es werden noch Widerstände benötigt. Man könnte nun an jedem IO-Pin einen Widerstand einbauen. Dieser begrenzt den Strom womit weder die LEDs noch der Controller gehen kaputt.

Das hat nur einen Nachteil:
Angenommen IO1 ist auf High und IO2 auf Low (alle anderen IOs sind hochohmig), so leuchtet LED A und es fließt ein Strom über R1 und R2. Nun wird zusätzlich noch IO3 auf Low geschalten. In der Folge leuchtet nun zusätzlich noch LED C. Deren Betriebsstrom fließt durch R1 und R3. Somit ist der Stromfluss durch R1 doppelt so hoch wie an R2 bzw. R3. Natürlich verdoppelt sich damit auch der Spannungsfall an R1 gegenüber dem ersten Betriebsfall (als nur LED A leuchtet).

Das bedeutet: wird nur eine LED angesteuert, so leuchtet diese heller, als wenn mehrere LEDs gleichzeitig angesteuert werden.
Sollte die Höhe der Ausgangsspannung der IOs hoch genug sein, kann es vorkommen, dass dieser Effekt vom Benutzer gar nicht bemerkt würde. Das liegt daran, dass das Auge den Helligkeitsunterschied dann einfach nicht mehr wahrnehmen kann.

Ist die Ausgangsspannung jedoch gerade so ausreichend um eine LED zu betreiben, so muss man eine alternative Beschaltung wählen. In diesem Fall muss jede LED einen eigenen Vorwiderstand erhalten. Damit wird das Problem umgangen.

Code-Beispiel

C-Code aus dem Arduino-Kochbuch für 4 IO-Pins:

  1. byte pins[] = {1,2,3,4}; //Mit den LEDs verbundene Pins
  2. //Die nächsten beiden Zeilen ermitteln die Anzahl der Pins und der LEDs aus dem obigen Array
  3. const int NUMBER_OF_PINS = sizeof(pins)/sizeof(pins[0]);
  4. const int NUMBER_OF_LEDS = NUMBER_OF_PINS * (NUMBER_OF_PINS-1);
  5. //Die nächste Zeile enthält die Array-Indizes für “pins[]”. Zwischen welchen zwei Pins hängt ein LED-Pärchen?
  6. byte pairs[NUMBER_OF_LEDS/2][2] = { {0,1}, {0,3}, {0,4}, {1,2}, {1,3}, {2,3} };
  7. void setup()
  8. {
  9. /* Keine Einstellungen notwendig */
  10. }
  11. void loop()
  12. {
  13. for(int i=0; i < NUMBER_OF_LEDS; i++) {
  14. lightLed(i); //Alle LEDs nacheinander einschalten
  15. delay(1000);
  16. }
  17. }
  18. //Diese Funktion schaltet die angegebene LED ein, Die erste LED ist 0
  19. void lightLed(int led) {
  20. //Die nachfolgenden vier Zeilen wandeln die LED-Nummern in Pin-Nummern um
  21. int indexA = pairs[led/2][0];
  22. int indexB = pairs[led/2][1];
  23. int pinA = pins[indexA];
  24. int pinB = pins[indexB];
  25. //Schaltet alle Pins aus, die nicht mit der LED verbunden sind
  26. for(int i=0; i < NUMBER_OF_PINS; i++) {
  27. if(pins[i] != pinA && pins[i] != pinB) {
  28. //Ist der Pin nicht einer unsere Pins,
  29. pinMode(pins[i], INPUT); //als Eingang festlegen
  30. digitalWrite(pins[i], LOW); // und Pullup ausschalten
  31. }
  32. }
  33. //Nur die Pins für die angegebene LED einschalten
  34. pinMode(pinA, OUTPUT);
  35. pinMode(pinB, OUTPUT);
  36. if( led%2 == 0) {
  37. digitalWrite(pinA, LOW);
  38. digitalWrite(pinB, HIGH);
  39. } else {
  40. digitalWrite(pinA, HIGH);
  41. digitalWrite(pinB, LOW);
  42. }
  43. }