ITG-ABI 14/15

19.03.2015

Korrekturhinweise / Lösungsvorschlag

Teil 1 Aufgabe 1

 

Mikrocontroller

Verwendeter µC: ATMEL AVR 8 Bit RISC.

Interruptverhalten der AVR Systeme unterscheidet sich vom in Lösungsvorschlägen angenommenem Verhalten des 8051!

Bei Interrupts mit Interrupt-Flags wie z.B externer Interrupt oder Timerinterrupt wird in die ISR verzweigt, dabei das spezifische Interruptflag und das globale Interruptflag gelöscht. Während der ISR kann dadurch keine andere ISR aufgerufen werden. Geschiet während der ISR erneut das Interruptereignis wird das spezifische Interruptflag erneut gesetzt. Am Ende der ISR durch Rücksprung mit RETI wird das globale Interruptflag wieder gesetzt. Sollte nun bereits wieder ein Interruptflag gesetzt sein wird ein Befehl des Hauptprogramms ausgeführt und dann in die ISR gesprungen. Folge für Timer-Interrupts die schneller passieren als die Verarbeitung durch die ISR ist, dass sie zwar ständig ausgeführt werden, aber das Hauptprogramm immer noch (langsam) weiter läuft. Liegen mehrere Interrupts an wird der in der Interrupttabelle mit der kleinsten Adresse zuerst ausgeführt, Priorität nimmt mit steigender Tabellenposition ab.

1.3 Externer Interrupt

1.3.1 INT0 an Portpin PD2

  MCUCR |= (1<<ISC01);  // INT0 fallende Flanke
  GIMSK |= (1<<INT0);   // INT0 frei schalten
  sei(); // globale Interruptfreigabe 

Die globale Interruptfreigabe war aus der Aufgabenstellung nicht gefordert, es sollte nur der externe Interrupt aktiviert werden.

1.3.2

volatile unsigned char zaehler=0; // globale Variable 
ISR(INT0_vect){ // ISR für INT0
  zaehler++; // Zaehler erhoehen
  PORTB = ((zaehler/10)<<4)|(zaehler%10); // Ausgabe auf PORTB
}

1.3.3 Beim Unterprogramm (UP) wird eine Codesequenz aufgerufen, am Ende der Sequenz (in Assembler durch den RET-Befehl) wird nach der Position des Aufrufs zurückgesprungen. Bei einem Interrupt wird bei einem Interrupt-Ereignis eine Codesequenz -Interrupt Service Routine (ISR) für dessen Behandlung aufgerufen und das Interrupt-Flag gelöscht. Das laufende Programm wird dabei unterbrochen, am Ende der Sequenz (in Assembler durch den RETI-Befehl) wird das unterbrochene Programm wieder fort gesetzt. Die Rücksprungadresse wird beim Aufruf von UP oder ISR auf dem Stack-Speicher abgelegt (Push), der Stackpointer (SP) wird dabei erniedrigt. Beim Rücksprung werden die Rücksprungadresse vom Stack in den Programm-Counter (PC) übertragen (Pop), der SP wird dabei wieder erhöht.

1.3.4 Der Stack-Speicher befindet sich im SRAM und wird über den Stackpointer (SP) verwaltet. Typischerweise wird bei der Initalisierung der SP auf die höchste RAM-Adresse gesetzt. Der Stack wächst von hohen nach niedrigen Adressen. Bei einem Interrupt wird die Adresse des nächsten auszuführenden Befehls des unterbrochenen Programmteils auf den Stack gepusht, SP wird dabei erniedrigt. Nach Ende der ISR wird der Programmcounter (PC) vom Stack geladen, der SP wird wieder erhöht.

1.4 Timerinterrupt

1.4.1 Auch bei Verwendung der maximalen Vorteilung 1024 und eines 16-Bit Zählers lassen sich maximal 65536*1024*1µs = 67,1s als ISR-Zeit realisieren.
Für die 10 Minunten muss ein weiterer Zähler in der ISR verwendet werden. Zwei Timer-Interrupt Möglichkeiten stehen zur Auswahl: Overflow-Interrupt mit Timer vorspannen oder CTC-Interrupt mit Vergeichsregister.

1.4.2 Als ISR-Zeit sei 50ms angenommen. 16-Bit Timer1. Die globale Interruptfreigabe mittels sei() ist aus der Aufgabenstellung nicht unbedingt herleitbar, da nur die spezifischen Einstellungen des Timer-Interrupts gefordert waren.

  Overflow-Interrupt CTC-Interrupt
Pflichtcode TCCR1B |= 1; // Vorteiler 1: Phi/1;
TIMSK |= 1<<TOIE1; // TimerOverflowInterruptEnable1
TCCR1B |= 1<<WGM12; // Timer im CTC-Mode mit OCR1A als Top
TCCR1B |= 1; // Vorteiler 1: Phi/1;
TIMSK |= 1<<OCIE1A; // Timer/Counter1 Output Compare Match A Interrupt Enable
OCR1A = 49999; // Wert bei dem der Timer wieder auf 0 gesetzt wird
Optional TCNT1=65536-50000; // muss vor allem in ISR
sei(); // globale Freigabe nur klar gefordert bei main()
sei(); // globale Freigabe nur klar gefordert bei main()

1.4.3 Das bei den Lösungsvorschlägen für 8051 enthaltene Anhalten, Reload und Starten des Timers beim Overflow-Interrupt in der ISR ist für den AVR-µC Unfug. Es gibt für den 16-Bit Timer ein Schattenrerister für das High-Byte, das zuerst beschrieben wird und dann beim Schreiben des Low-Byte werden beide zeitgleich übertragen.

1.4.4 Der 8-Bit Timer/Counter0 könnte als Zähler verwendet werden, dazu wird die Lichtschranke an PD4 angeschlossen und in TCCR0B durch den Wert 6 der Modus "Counter mit fallender Flanke an T0" eingestellt. Der Vorteil dann keine ISR für das Zählen der Autos durch den externen Interrupt mehr zu benötigen wird durch den Nachteil eine andere Konstruktion für die Aktualisierung der Anzeige etwa durch Pollen im Hauptprogramm aufgehoben.