fritzler-avr.de
Tipps
LEDs Multiplexen

Ein AVR hat natürlich nicht eine unbegrenzte Anzahl an Portpins und somit lohnt sich bei mehr als einer 7 Segment Anzeige fast immer das Multiplexing.
Bevor es zur Berechnung der Komponenten geht, erstmal ein paar Grundschaltungen.

Hier die Minimalbeschaltung für ein 4 fach Multiplexing. Der ULN2803 ist ein Transistorarray, dieser wird benötigt da ein AVR Portpin nur 40mA liefern kann, bzw ein gesamter Port 200mA. Diser heißt ab jetzt Zeilentreiber. Die PNP Transistoren sind die Spaltentreiber und werden direkt vom AVR angesteuert.

Nun wird nicht immer die volle Dröhnung bei der Helligkeit benötigt, also sollte die gesamte Anzeige per PWM gedimmt werden können. Wenn die PWM synchron zu den Ziffern umgeschalten wird, dann lassen sich natürlich auch unterschiedlich helle Ziffern realisieren. Dafür hängen die Spaltentreiber nicht mehr direkt an der Versorgungsspannung, sondern an einem weiteren PNP Transistor, welcher mit der PWM gespeist wird. Ein Dimmen über den GND Pin des Zeilentreibers ist hier nicht möglich. Durch die internen Schutzdioden des ULN2803 würden dann andere Segmente mit aufleuchten.

Das Dimmen ist besonders wichtig, wenn die Software für den AVR noch in Entwicklung ist. Durch die Stromüberhöhung (dazu später mehr), würde die Anzeige durchbrennen, wenn das Programm sich aufhängt. Bei einem 4fach Multiplexing also maximal 25% PWM oder bei 8fach 12%.

Beim 4fach Multiplexing mit Transistorendirektansteuerung werden 8+4 Pins benötigt, aber es geht mit noch weniger! Dafür wird allerdings ein externes Logik IC benötigt (74HC42). Dies ist ein BCD zu Dezimaldekoder und invertiert auch gleich noch die Ausgänge für die PNP Spaltentreiber. Damit werden nurnoch 8+2 Pins benötigt, klingt jetzt nach keiner großen Ersparnis. Bei 8fach Multiplexing wird da aber schon eine Menge eingespart: 8+8 Pins für direkt und 8+3 Pins für die Logik IC Variante. Weiterhin muss man jetzt nicht mehr mit Bitoperatoren arbeiten (Ausgang löschen und setzen), sondern die Ausgabe der Spaltenzahl genügt.

Natürlich lässt sich auch hier mit PWM arbeiten, dazu die PWM an Eingang D anschließen.

Und wie funktioniert das jetzt?
Der Trick dahinter ist, dass immer nur eine Anzeige leuchtet und dann auf die nächste umgeschalten wird. Also das Programm legt am Zeilentreiber das Bitmuster für eine 1 an und schaltet den Spaltentreiber für die linke Anzeige durch. Die 1 leuchtet auf, nach einer gewissen Zeit wird der Spaltentreiber abgeschalten und zB das Bitmuster für eine 2 angelegt und der Spaltentreiber für das Display neben dem Linken eingeschalten. Somit leuchtet dort die 2 auf.
Eine Gewisse Zeit: Alle Displays leuchten nur für 1/4 der Zeit auf durch das weiterschalten. Da immer nur ein Display leuchtet, muss dieser Vorgang schnell wiederholt werden damit es nicht flimmert. Zu empfehlen sind 50Hz Aufwwärts, also 200mal weiterschalten pro Sekunde.

Es müssen nicht unbedingt 7 Segment Anzeigen verwendet werde, es sind auch einzel LEDs so MUltiplexbar und damit ergeben sich viele Muster.

Vorwiderstandsberechnung:
Normalerweise wird der Vorwiderstand auf 20mA pro LED berechnet, doch das geht hier schief. Denn jede LED leuchtet nur zu 1/4 der Zeit auf, hat also auchnurnoch 1/4 der Helligkeit. Wie wirds wieder heller? Strom aufdrehen! Ein Blick ins Datenblatt der LED (Anzeige) verrät, dass diese einen höheren Impulsstrom vertragn. Genau das wird für Multiplexing benötigt. Beim 4fach Multiplex wird der 4 fache Strom benötigt, also 80mA.

Bei der Berechnung des Vorwiderstands fällt auch langsam der Spannungsabfall über die Treiber ins gewicht. Also mal vorrechnen:

Über dem BC327 fällt laut Datenblatt bei 80mA bis 560mA (es leuchtet ja eine variable Anzahl an Segmenten) eine Spannung von ca 0,8V ab = U1, (bei der PWM-Variante natürlich das doppelte).

Der ULN2803 verbrät 0,9 V bei 80 mA = U4. Hier wieder die Betrachtung eines einzelnen Segmentes, der PNP Transistor versorgt eine gesamte 7 Segment Anzeige (Spalte) und der ULN2803 nur eine LED/Segment (Zeile).

Die LED will 2,2V sehen = U2

Also müssen 5V-U1-U2-U4 = 1,1V am Vorwiderstand abfallen.

Das macht nach dem ohmschen Gesetz: 1,1 V/80 mA = 13,75 Ohm. Solch einen Widerstand gibt es natürlich nicht, also nehmen wir 14 oder 16 Ohm.

Die Kollektor-Emitter Spannung (= der Spannungsabfall) der Transistoren aus dem ULN2803 und dem BC327 lässt sich aus dem Datenblatt entnehmen.
Genauer gesgat bei den Diagrammen wie Collector-Emitter Saturationvoltage.

Nun zur Software
Der Zeilentreiber hängt an PORTB und der Spaltentreiber an PORTD, Variante ohne Logik IC.
Die Buffer lassen sich natürlich auch in ein Array packen.

  1. //ATmega16
  2.  
  3. //7seg Ausgabebuffer für Multiplex
  4. //wird vom Hauptprogramm beschrieben
  5. volatile uint8_t Buffer_1 = 0;
  6. volatile uint8_t Buffer_2 = 0;
  7. volatile uint8_t Buffer_3 = 0;
  8. volatile uint8_t Buffer_4 = 0; 
  9.  
  10. //Timer einstellen (alle 1ms ein ISR)
  11. TIMSK = (1<<OCIE0); //Overflow ISR
  12. TCCR0 = (1<<WGM01)|(1<<CS02); //CTC Mode
  13. OCR0 = 16; //64 bei 16MHz
  14. sei();
  15.  
  16. ISR (TIMER0_COMP_vect) { //7seg anzeigen multiplexen
  17.     static uint8_t stelle = 1;
  18.     PORTD |= 0b01000111; //Alle Spaltentreiber aus
  19.     switch(stelle){
  20.         case 1:
  21.             PORTB = Buffer_1;   //Buffer ausgeben
  22.             stelle = 2;         //neue Stelle
  23.             PORTD &= ~(1<<PD6); //Spalte aktivieren
  24.             break;
  25.  
  26.         case 2:
  27.             PORTB = Buffer_2;
  28.             stelle = 3;
  29.             PORTD &= ~(1<<PD2);
  30.             break;
  31.        
  32.         case 3:
  33.             PORTB = Buffer_3;
  34.             stelle = 4;
  35.             PORTD &= ~(1<<PD0);
  36.             break;
  37.            
  38.         case 4:
  39.             PORTB = Buffer_4;
  40.             stelle = 1;
  41.             PORTD &= ~(1<<PD1);
  42.             break;
  43.        
  44.         default:
  45.             break;
  46.     }
  47. }
  48.  

Oder mit Arrays statt einem Switchcase:

  1. //ATmega16
  2.  
  3. //7seg Ausgabebuffer für Multiplex
  4. //wird vom Hauptprogramm beschrieben
  5. volatile uint8_t Buffer[4] = {0, 0, 0, 0};
  6.  
  7. //Angaben an welchem Pin der Anodentransistor hängt
  8. const uint8_t anoden[4] = {1<<PD6, 1<<PD2, 1<<PD0, 1<<PD1};
  9.  
  10.  
  11. //Timer einstellen (alle 1ms ein ISR)
  12. TIMSK = (1<<OCIE0); //Overflow ISR
  13. TCCR0 = (1<<WGM01)|(1<<CS02); //CTC Mode
  14. OCR0 = 16; //64 bei 16MHz
  15. sei();
  16.  
  17. ISR (TIMER0_COMP_vect) { //7seg anzeigen multiplexen
  18.     static uint8_t stelle = 0;
  19.     PORTD |= 0b01000111; //Alle Spaltentreiber aus
  20.    
  21.     PORTB = Buffer[stelle];     //Buffer ausgeben
  22.     PORTD &= ~anoden[stelle];   //Spalte aktivieren
  23.     stelle = (stelle+1)%4;      //neue Stelle
  24. }
  25.  

Abschließend noch ein Zeichensetz:

  1. #include <avr/pgmspace.h>
  2.  
  3. //Sollen nur Zahlen angezeigt werden -> 0
  4. //Hexadezimal -> 1
  5. //so viel Buchstaben wie möglich -> 2
  6. #define OUT 1
  7. //Pin für das entsprechende Segment angeben
  8. #define pa PC0
  9. #define pb PC1
  10. #define pc PC2
  11. #define pd PC3
  12. #define pe PC4
  13. #define pf PC5
  14. #define pg PC6
  15. #define dp PC7
  16.  
  17. #if (OUT == 0)
  18. #define LENGTH 10
  19. #endif
  20. #if (OUT == 1)
  21. #define LENGTH 16
  22. #endif
  23. #if (OUT == 2)
  24. #define LENGTH 45
  25. #endif
  26.  
  27. const uint8_t segm[LENGTH] PROGMEM = {
  28. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf), //0,0
  29. (1<<pb)|(1<<pc), //1,1
  30. (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pg), //2,2
  31. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pg), //3,3
  32. (1<<pb)|(1<<pc)|(1<<pf)|(1<<pg), //4,4
  33. (1<<pa)|(1<<pc)|(1<<pd)|(1<<pf)|(1<<pg), //5,5
  34. (1<<pa)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //6,6
  35. (1<<pa)|(1<<pb)|(1<<pc), //7,7
  36. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //8,8
  37. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pf)|(1<<pg) //9,9
  38. #if (OUT)
  39. ,
  40. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pe)|(1<<pf)|(1<<pg), //10,A
  41. (1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //11,b
  42. (1<<pd)|(1<<pe)|(1<<pg), //12,c
  43. (1<<pa)|(1<<pa)|(1<<pa)|(1<<pa), //13,d
  44. (1<<pa)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //14,E
  45. (1<<pa)|(1<<pe)|(1<<pf)|(1<<pg) //15,F
  46. #endif /*OUT*/
  47. #if (OUT == 2)
  48. ,
  49. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pg), //16,a
  50. (1<<pa)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf), //17,G
  51. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pf)|(1<<pg), //18,g
  52. (1<<pb)|(1<<pc)|(1<<pe)|(1<<pf)|(1<<pg), //19,H
  53. (1<<pc)|(1<<pe)|(1<<pf)|(1<<pg), //20,h
  54. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe), //21,J
  55. (1<<pd)|(1<<pe)|(1<<pf), //22,L
  56. (1<<pe)|(1<<pf), //23,l
  57. (1<<pa)|(1<<pb)|(1<<pc)|(1<<pe)|(1<<pf), //24,N
  58. (1<<pc)|(1<<pe)|(1<<pg), //25,n
  59. (1<<pc)|(1<<pd)|(1<<pe)|(1<<pg), //26,o
  60. (1<<pa)|(1<<pb)|(1<<pe)|(1<<pf)|(1<<pg), //27,P
  61. (1<<pe)|(1<<pg), //28,r
  62. (1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf), //29,U
  63. (1<<pc)|(1<<pd)|(1<<pe), //30,u
  64. (1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //31,t
  65. (1<<pb)|(1<<pc)|(1<<pd)|(1<<pf)|(1<<pg), //32,y
  66. (1<<pg), //33,-
  67. (1<<pd), //43,_
  68. (1<<pb)|(1<<pf) //44,"
  69. #endif /*(OUT == 2)*/
  70. };
  71.  

Home - Tipps

Kontakt - Haftungsausschluss - Impressum