Multiplexing

Aus Fingers Wiki
Version vom 26. Dezember 2013, 22:04 Uhr von Arndt (Diskussion | Beiträge) (→‎7 Segment: Zeilennummern eingefügt)
Zur Navigation springen Zur Suche springen

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 und zur Programmierung, erstmal ein paar Grundschaltungen.

Funktionsweise

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.

Schaltungen

Grundschaltung

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.

Multiplex Grundschaltung

Grundschaltung - Dimmen

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%

Multiplex Grundschaltung mit PWM

weitere Pins sparen

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.

Multiplex Pins sparen mit BCD

weitere Pins sparen - Dimmen

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

Multiplex Pins sparen mit BCD mit PWM

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 BF421 fällt laut Datenblatt bei 80mA eine Spannung von ca 0,6V ab = U1, (bei der PWM Variante natürlich das Doppelte.

Der ULN2803 verbrät 0,9V bei 80mA = U4

Die LED will 2,2V sehen = U2

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

Das macht nach dem ohmschen Gesetz: 1,3V/80mA = 16 Ohm.

Strompfad

Programmierung

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.

Das weiterschalten der Spalten erfolgt in einem Timerinterrupt und die Buffer werden irgndwann/irgendwie im Hauptprogramm gefüllt. Somit ist beides voneinander unabhängig.

<source line lang="c" > //ATmega16

//7seg Ausgabebuffer für Multiplex //wird vom Hauptprogramm beschrieben volatile uint8_t Buffer_1 = 0; volatile uint8_t Buffer_2 = 0; volatile uint8_t Buffer_3 = 0; volatile uint8_t Buffer_4 = 0;

//Timer einstellen (alle 1ms ein ISR) TIMSK = (1<<OCIE0); //Overflow ISR TCCR0 = (1<<WGM01)|(1<<CS02); //CTC Mode OCR0 = 16; //64 bei 16MHz sei();

ISR (TIMER0_COMP_vect) { //7seg anzeigen multiplexen static uint8_t stelle = 1; PORTD |= 0b01000111; //Alle Spaltentreiber aus switch(stelle){ case 1: PORTB = Buffer_1; //Buffer ausgeben stelle = 2; //neue Stelle PORTD &= ~(1<<PD6); //Spalte aktivieren break;

case 2: PORTB = Buffer_2; stelle = 3; PORTD &= ~(1<<PD2); break;

case 3: PORTB = Buffer_3; stelle = 4; PORTD &= ~(1<<PD0); break;

case 4: PORTB = Buffer_4; stelle = 1; PORTD &= ~(1<<PD1); break;

default: break; } } </source>

Zeichensatz

7 Segment

<source line lang="c" >

  1. include <avr/pgmspace.h>

//Sollen nur Zahlen angezeigt werden -> 0 //Hexadezimal -> 1 //so viel Buchstaben wie möglich -> 2

  1. define OUT 1

//Pin für das entsprechende Segment angeben

  1. define pa PC0
  2. define pb PC1
  3. define pc PC2
  4. define pd PC3
  5. define pe PC4
  6. define pf PC5
  7. define pg PC6
  8. define dp PC7
  1. if (OUT == 0)
  2. define LENGTH 10
  3. endif
  4. if (OUT == 1)
  5. define LENGTH 16
  6. endif
  7. if (OUT == 2)
  8. define LENGTH 45
  9. endif

const uint8_t segm[LENGTH] PROGMEM = { (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf), //0,0 (1<<pb)|(1<<pc), //1,1 (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pg), //2,2 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pg), //3,3 (1<<pb)|(1<<pc)|(1<<pf)|(1<<pg), //4,4 (1<<pa)|(1<<pc)|(1<<pd)|(1<<pf)|(1<<pg), //5,5 (1<<pa)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //6,6 (1<<pa)|(1<<pb)|(1<<pc), //7,7 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //8,8 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pf)|(1<<pg) //9,9

  1. if (OUT)

, (1<<pa)|(1<<pb)|(1<<pc)|(1<<pe)|(1<<pf)|(1<<pg), //10,A (1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //11,b (1<<pd)|(1<<pe)|(1<<pg), //12,c (1<<pa)|(1<<pa)|(1<<pa)|(1<<pa), //13,d (1<<pa)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //14,E (1<<pa)|(1<<pe)|(1<<pf)|(1<<pg) //15,F

  1. endif /*OUT*/
  2. if (OUT == 2)

, (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pg), //16,a (1<<pa)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf), //17,G (1<<pa)|(1<<pb)|(1<<pc)|(1<<pf)|(1<<pg), //18,g (1<<pb)|(1<<pc)|(1<<pe)|(1<<pf)|(1<<pg), //19,H (1<<pc)|(1<<pe)|(1<<pf)|(1<<pg), //20,h (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe), //21,J (1<<pd)|(1<<pe)|(1<<pf), //22,L (1<<pe)|(1<<pf), //23,l (1<<pa)|(1<<pb)|(1<<pc)|(1<<pe)|(1<<pf), //24,N (1<<pc)|(1<<pe)|(1<<pg), //25,n (1<<pc)|(1<<pd)|(1<<pe)|(1<<pg), //26,o (1<<pa)|(1<<pb)|(1<<pe)|(1<<pf)|(1<<pg), //27,P (1<<pe)|(1<<pg), //28,r (1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf), //29,U (1<<pc)|(1<<pd)|(1<<pe), //30,u (1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //31,t (1<<pb)|(1<<pc)|(1<<pd)|(1<<pf)|(1<<pg), //32,y (1<<pg), //33,- (1<<pd), //43,_ (1<<pb)|(1<<pf) //44,"

  1. endif /*(OUT == 2)*/

};

</source>

16 Segment

<source lang="c" >

  1. include <avr/pgmspace.h>

//Bit für das entsprechende Segment angeben

  1. define pa 14
  2. define pb 15
  3. define pc 11
  4. define pd 5
  5. define pe 0
  6. define pf 2
  7. define pg 6
  8. define ph 8
  9. define pk 10
  10. define pm 12
  11. define pn 13
  12. define pp 9
  13. define pr 3
  14. define ps 1
  15. define pt 4
  16. define pu 7

const uint16_t seg16[68] PROGMEM = { (1<<pc)|(1<<pd), //33 - ! (1<<ph)|(1<<pm), //34 - " 65535, //35 - # (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<ph)|(1<<pm)|(1<<pp)|(1<<ps)|(1<<pu), //36 - $ (1<<pa)|(1<<pd)|(1<<pe)|(1<<ph)|(1<<pm)|(1<<pn)|(1<<pp)|(1<<ps)|(1<<pt)|(1<<pu), //37 - % (1<<pb)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pm)|(1<<pn)|(1<<ps)|(1<<pt), //38 - & (1<<pn), //39 - ´ (1<<pn)|(1<<pr), //40 - ( (1<<pt)|(1<<pk), //41 - ) (1<<pk)|(1<<pm)|(1<<pn)|(1<<pp)|(1<<pr)|(1<<ps)|(1<<pt)|(1<<pu), //42 - * (1<<pm)|(1<<pp)|(1<<ps)|(1<<pu), //43 - + (1<<pt), //44 - , (1<<pp)|(1<<pu), //45 - - (1<<pf)|(1<<pg)|(1<<ps)|(1<<pu), //46 - . (1<<pn)|(1<<pt), //47 - / (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pn)|(1<<pt), //48 - 0 (1<<pc)|(1<<pd)|(1<<pn), //49 - 1 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<pu)|(1<<pp), //50 - 2 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pp), //51 - 3 (1<<pc)|(1<<pd)|(1<<ph)|(1<<pp)|(1<<pu), //52 - 4 (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<ph)|(1<<pp)|(1<<pu), //53 - 5 (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pu), //54 - 6 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd), //55 - 7 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pu), //56 - 8 (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<ph)|(1<<pp)|(1<<pu), //57 - 9 (1<<pm)|(1<<ps), //58 - : (1<<pm)|(1<<pt), //59 - ; (1<<pn)|(1<<pr), //60 - < (1<<pe)|(1<<pf)|(1<<pp)|(1<<pu), //61 - = (1<<pt)|(1<<pk), //62 - > (1<<pb)|(1<<pc)|(1<<pp)|(1<<ps), //63 - ? (1<<pa)|(1<<pb)|(1<<pc)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pm)|(1<<pp), //64 - @ (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pu), //65 - A (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pm)|(1<<pp)|(1<<ps), //66 - B (1<<pa)|(1<<pb)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph), //67 - C (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pm)|(1<<ps), //68 - D (1<<pa)|(1<<pb)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pu), //69 - E (1<<pa)|(1<<pb)|(1<<pg)|(1<<ph)|(1<<pu), //70 - F (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pp), //71 - G (1<<pc)|(1<<pd)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pu), //72 - H (1<<pa)|(1<<pb)|(1<<pe)|(1<<pf)|(1<<pm)|(1<<ps), //73 - I (1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg), //74 - J (1<<pg)|(1<<ph)|(1<<pn)|(1<<pr)|(1<<pu), //75 - K (1<<pe)|(1<<pf)|(1<<pg)|(1<<ph), //76 - L (1<<pc)|(1<<pd)|(1<<pg)|(1<<ph)|(1<<pk)|(1<<pn), //77 - M (1<<pc)|(1<<pd)|(1<<pg)|(1<<ph)|(1<<pk)|(1<<pr), //78 - N (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph), //79 - O (1<<pa)|(1<<pb)|(1<<pc)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pu), //80 - P (1<<pa)|(1<<pb)|(1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph)|(1<<pr), //81 - Q (1<<pa)|(1<<pb)|(1<<pc)|(1<<pg)|(1<<ph)|(1<<pp)|(1<<pr)|(1<<pu), //82 - R (1<<pa)|(1<<pb)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<ph)|(1<<pp)|(1<<pu), //83 - S (1<<pa)|(1<<pb)|(1<<pm)|(1<<ps), //84 - T (1<<pc)|(1<<pd)|(1<<pe)|(1<<pf)|(1<<pg)|(1<<ph), //85 - U (1<<pg)|(1<<ph)|(1<<pn)|(1<<pt), //86 - V (1<<pc)|(1<<pd)|(1<<ph)|(1<<pg)|(1<<pr)|(1<<pt), //87 - W (1<<pk)|(1<<pn)|(1<<pr)|(1<<pt), //88 - X (1<<pk)|(1<<pn)|(1<<ps), //89 - Y (1<<pa)|(1<<pb)|(1<<pe)|(1<<pf)|(1<<pn)|(1<<pt), //90 - Z (1<<pb)|(1<<pe)|(1<<pm)|(1<<ps), //91 - [ (1<<pk)|(1<<pr), //92 - backslash (1<<pa)|(1<<pf)|(1<<pm)|(1<<ps), //93 - ] (1<<pb)|(1<<pc)|(1<<pn)|(1<<pt), //94 - ^ (1<<pe)|(1<<pf), //95 - _ (1<<pk), //96 - ` (1<<pb)|(1<<pe)|(1<<pm)|(1<<ps)|(1<<pu), //123 - { (1<<pm)|(1<<ps), //124 - | (1<<pa)|(1<<pf)|(1<<pm)|(1<<pp)|(1<<ps), //125 - } (1<<pc)|(1<<pg)|(1<<pp)|(1<<pu) //126 - ~ };

uint16_t get_seg16(uint8_t chara){ //Werte außerhalb der ASCI Tabelle rausfiltern if ((chara < 33) || (chara > 126)){ return 0; } //Symbole und Großbuchstaben if (chara < 97){ return pgm_read_word(&seg16[chara-33]); } //Symbole nach Kleinbuchstaben if (chara > 122){ return pgm_read_word(&seg16[chara-59]); } //Kleinbuchstaben als Großbuchstaben anzeigen return pgm_read_word(&seg16[chara-65]); } </source>