Anschluss von Peripherien
Transcription
Anschluss von Peripherien
Anschluss von Peripherien 2008 Jiri Spale, Programmierung eingebetteter Systeme 1 Tastenmatrix Anschluss von vielen Tasten → zyklische Abfrage im Zeitmultiplexverfahren Anordnung der Tasten: m x n Matrix, angestrebt: m ≈ n Spaltentreiber Spaltentreiber = Ausgabeport Zeilerleser = Eingabeport pull-up-Widerstände: extern oder intern (zuschaltbar in MCU) netX: interne nicht-zuschaltbare Zeilen- pull-down-Widerstände leser !!! Erkennung von max. 2 Tasten! (braun=log.0) 2008 Jiri Spale, Programmierung eingebetteter Systeme 2 Abfrage mit Interrupts #1 1. PIOs des Spaltentreibers auf log.0 2. Taste gedrückt → Int durch log.0 ausgelöst, ISR startet. Für jeden Eingangs-PIO eigene ISR Bei MCUs mit Tiefschlafmodus sogar ruhestromfreie Abfrage möglich (Fernbedienungen): Erst durch Int weckt der MCU aus dem Schlaf und startet den Oszi 2008 Jiri Spale, Programmierung eingebetteter Systeme 3 Abfrage mit Interrupts #2 3. PIOs des Spaltentreibers gehen in log.1 4. Abfrage beginnt: PIO1 PIO2 PIO3 PIO4 5. Taste erkannt 6. Erkennen des Loslassens aller Tasten: Alle PIOs der Spaltentreibers log.0 Losgelassen:alle PIOs des Zeilentreibers log.1 Während der Abfrage müssen andere PIOs des Spaltentreibers hochohmig sein (keine „harte“ log. 1), oder müssen in Einganbemodus geschaltet werden Treiberausgänge darf man nicht kurzschließen! 2008 Jiri Spale, Programmierung eingebetteter Systeme 4 2 gedrückte Tasten erkennen a) Beide Tasten in einer Spalte: mehr als 1 Zeile aktiv b) Beide Tasten in einer Zeile: fortwährende Spaltenabfrage c) 2 Zeilen und 2 Spalten aktiv: 2 Tasten können noch erkannt werden, eine 3. Taste nicht mehr Bsp: (2,2) und (3,3) gedrückt Falls die 3. Taste (2,3) oder (3,2) wäre, könnte sie nicht erkannt werden, da Spalte 2 und 3 sowir Zeile 2 und 3 kurzgeschlossen 2008 Jiri Spale, Programmierung eingebetteter Systeme 5 3 beliebige Tasten gleichzeitig Keine Kurzschlüsse durch mehrfache Tastendrücke möglich Ein reines Ausgabeport als Spaltentreiber möglich (tri-state unnötig) In der Software kann entschieden werden, ob tatsächlich alle Tastenkombinationen ausgewertet werden Entkopplungsdioden 2008 Jiri Spale, Programmierung eingebetteter Systeme 6 Bei zu wenig PIOs Abfrageschema wie oben, nur dass Die gerade aktivierte Spalte immer als aktive Zeile zurückkommt. Folge: Sie muss ausmaskiert werden. Nur die restlichen Spalten dürfen Ausgewertet werden Verzicht auf Hauptdiagonale Begrenzungen: • Nur 1 Taste kann erkannt werden • Schlafmodus geht nicht 2008 Jiri Spale, Programmierung eingebetteter Systeme 7 Bei zu wenig PIOs ohne Dioden Zwischen jeder Kombination von Portpins sowie nach Masse gibt es genau 1 Taste Zustände: 1. Keine log.0 geschickt: 1 Taste der 1. Spalte kann erkannt w. 2. Log.0 auf die 1 Zeile geschickt: 1 Taste der 2. Spalte kann erkannt w. 3. usw. Verzicht auf halbe Matrix Begrenzungen: • Nur 1 Taste kann erkannt werden • Schlafmodus geht nicht 2008 Jiri Spale, Programmierung eingebetteter Systeme 8 Entprellung Mechanische Schalter "prellen" beim Ein- und Ausschalten. Zur Beseitigung gibt es unterschiedliche Ansätze 2008 Jiri Spale, Programmierung eingebetteter Systeme 9 Hardware-Entprellung Möglichkeiten z.B. • Tiefpassfilter mit nachgeschaltetem Schmitt-Trigger • Umschaltkontakt + RS-Flipflops (aus zwei NAND-Gattern) Der Schalter muss vom Typ "nicht kurzschließend" sein. 2008 Jiri Spale, Programmierung eingebetteter Systeme 10 Software-Entprellung: Flankenerkennung#1 Bei einem Taster gibt es insgesamt 4 Zustände: 1. war nicht gedrückt und ist nicht gedrückt 2. war nicht gedrückt und ist gedrückt (steigende Flanke) 3. war gedrückt und ist immer noch gedrückt 4. war gedrückt und ist nicht mehr gedrückt (fallende Flanke) Diese einzelnen Zustände lassen sich jetzt bequem abfragen/durchlaufen. Die Entprellung geschieht dabei durch die ganze Laufzeit des Programms. Taster als Active-Low angeschlossen, Pull-Ups genutzt. 2008 Jiri Spale, Programmierung eingebetteter Systeme 11 Flankenerkennung #2 für den Zustand "steigende Flanke" wird Wert "1" zurückgegeben, sonst "0" char taster(void) { static unsigned char zustand; char rw = 0; //Taster wird gedrueckt (steigende Flanke) if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT))) { zustand = 1; rw = 1; } //Taster wird gehalten else if (zustand == 1 && !(TASTERPORT & (1<<TASTERBIT))) { zustand = 2; rw = 0; } //Taster wird losgelassen (fallende Flanke) else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT))) { zustand = 3; rw = 0; } //Taster losgelassen else if (zustand == 3 && (TASTERPORT & (1<<TASTERBIT))) { zustand = 0; rw = 0; } return rw; } 2008 Jiri Spale, Programmierung eingebetteter Systeme 12 SW-Entprellung: Warteschleifenverfahren /* Einfache Funktion zum Entprellen eines Tasters */ UINT8 debounce(volatile UINT8 *port, UINT8 pin) { if ( ! (*port & (1<<pin)) ){//Falls Pin auf Masse gezogen,100ms warten _delay_ms(100); if ( *port & (1 << pin) ){ //Falls Pin wieder high, warten /* Anwender Zeit zum Loslassen des Tasters geben */ _delay_ms(100); return 1; } } return 0; } int main(void) { PORTCONF &= ~( 1 << PB0 ); // PIN PB0 auf Eingang (Taster) if (debounce(&PINB, PB0)) // Falls Taster an PIN PB0 gedrueckt.. PORTD = PIND ^ (1<<PD7);//..LED an Port PD7 an- bzw. ausschalten } 2008 Jiri Spale, Programmierung eingebetteter Systeme 13 SW-Entprellung: Interruptverfahren Schnell, kurzer Code, zuverlässig ISR( TIMER0 ) // every 10ms { static UINT8 ct0, ct1, rpt; UINT8 i; TCNT0 = ... // preload for 10ms i = key_state ^ ~KEY_PIN; // key changed ? (^…XOR) ct0 = ~( ct0 & i ); // reset or count ct0 ct1 = ct0 ^ (ct1 & i); // reset or count ct1 i &= ct0 & ct1; // count until roll over ? key_state ^= i; // then toggle debounced state key_press |= key_state & i; // 0->1: key press detect if( (key_state & REPEAT_MASK) == 0 ) // check repeat function rpt = REPEAT_START; // start delay if( --rpt == 0 ){ rpt = REPEAT_NEXT; // repeat delay key_rpt |= key_state & REPEAT_MASK; } } 2008 Jiri Spale, Programmierung eingebetteter Systeme 14 7-Segment-LEDs Ziffernkodierung z.B. 00011000 // 0 11011110 // 1 00110010 // 2 01010010 // 3 11010100 // 4 01010001 // 5 00010001 // 6 11011010 // 7 00010000 // 8 01010000 // 9 • Zeitmultiplexverfahren via Warteschleifen oder Interrupts • Ganze Ziffern mit log.0 aktiviert, einzelne Segmente ebenfalls mit log.0. • Flackern vermeiden: ganze Zahl min. 50 mal pro Sekunde wiederholen • Empfohlen: alle 4 ms zur nächsten Anzeigestelle weiterschalten 2008 Jiri Spale, Programmierung eingebetteter Systeme 15 Schrittmotoren Arten: • Bipolar 4 Anschlüsse (mittlere Anschl. nicht vorhanden) • Unipolar 6 Anschlüsse • Im Bild: 1 Schritt=90°, 4 Vollschritte oder 8 Halbschritte für ganze Umdrehung • Oft: 1 Schritt = 1,8°, 200 Vollschritte oder 400 Halbschritte pro Umdrehung • Im Praktikum: 1 Schritt = 0,9°, 400 Vollschritte oder 800 Halbschritte pro Umdrehung Oft eingesetzt: Robotik 2008 Jiri Spale, Programmierung eingebetteter Systeme 16 Schrittmotoren: Arten 2008 Jiri Spale, Programmierung eingebetteter Systeme 17 Bipolare Schrittmotoren: Ansteuerung 2008 Jiri Spale, Programmierung eingebetteter Systeme Voll A B C D Schritt 1 + - + - Schritt 2 - + + - Schritt 3 - + - + Schritt 4 + - - + Halb A B C D Schritt 1 + - Schritt 2 + - + - Schritt 3 frei frei + - Schritt 4 - + + - Schritt 5 - + Schritt 6 - + - + Schritt 7 frei frei - + Schritt 8 + - - + 18 frei frei frei frei Unipolare Schrittmotoren: Ansteuerung Voll A B common C D common Schritt 1 + frei - frei + - Schritt 2 + frei - + frei - Schritt 3 frei + - + frei - Schritt 4 frei + - frei + - 2008 Jiri Spale, Programmierung eingebetteter Systeme 19 C-Spezialitäten für embedded Welt #1 Modifizierer volatile Benutzung: volatile typ name; Mitteilung an Compiler: Variable name kann durch Ereignisse außerhalb der Kontrolle des Programms verändert werden kann, z.B. Lesen von Ports. volatile-Variablen werden: • vor jedem Zugriff neu aus dem Hauptspeicher eingelesen • Compiler-Optimierung bei volatile abgeschaltet • Zwischenspeicherung von volatile-Variablen in Registern (was sonst den Ablauf beschleunigt) ist verboten 2008 Jiri Spale, Programmierung eingebetteter Systeme 20 C-Spezialitäten für embedded Welt #2 #define –Direktive mit Argumenten (genannt auch Makro) #define POKE(addr, val)(*(volatile unsigned int *)(addr) = (val)) Bsp. Präprozessorbefehl POKE (REG1, 0xFFEFU) (U für unsigned) wird ersetzt durch *(volatile unsigned int *)REG1 = 0xFFEFU Bedeutet: • REG1 ist Zeiger, gecastet in volatile unsigned int * • Die Dereferenz von diesem Zeiger erhält neuen Wert von 0xFFEFU Ähnlich: #define POKE_AND(addr,val)(*(volatile unsigned int*)(addr)&=(val)) #define POKE_OR(addr,val)(*(volatile unsigned int*)(addr)|=(val)) #define PEEK(addr)(*(volatile unsigned int*)(addr)) 2008 Jiri Spale, Programmierung eingebetteter Systeme 21 C-Spezialitäten für embedded Welt #3 Datentypen benutzt vom StartEasy Für Registeradressen: #define REG8 (volatile unsigned char*) #define REG16 (volatile unsigned short*) #define REG32 (volatile unsigned int*) Für Registerwerte: #define UI32 unsigned int 2008 Jiri Spale, Programmierung eingebetteter Systeme 22 C-Spezialitäten für embedded Welt #4 Bitmanipulationen i-tes Bit von rechts im Register REG löschen (andere Bits unverändert): POKE_AND(REG, ~(1 << i)); oder *REG &= ~(1 << i)); i-tes Bit von rechts im Register REG setzen (andere Bits unverändert): POKE_OR(REG, 1 << i); oder *REG &= 1 << i; 2008 Jiri Spale, Programmierung eingebetteter Systeme 23