Hallo Leute,
ich versuche gerade auf meinem LaunchPad mit einem MSP430G2231 den Timer
A so einzustellen, dass eine LED an P1.0 mit 1Hz blinkt. Nettes Beispiel
um die Peripherie kennen zu lernen.
Normalerweise schreibe ich nicht sofort und studiere erstmal die
Datasheets. Aber ich wusste gar nicht, was man alles falsch machen kann,
oder wie überhauptnicht man die Architektur kapieren kann.
Ich hoffe, Ihr könnt mich der Sache etwas näher bringen.
Generell blinkt die LED schon mal, wenn ich eine Zählschleife bis 20.000
oder so laufen lasse.
Aber um auf 1Hz zu kommen wollte ich den Timer benutzen.
Wenn man auf das LaunchPad schaut, sieht man einen 12MHz Oszillator, ich
hoffe, dass dann auf ACLK undgeteilt rausläuft, ob dem so ist, konnte
ich bisher auch im Kapitel Basic Clock Module+ nicht genau herauslesen.
Ich hoffe, Ihr könnt an meinem Beispielprogramm sagen was und warum es
falsch ist.
Interrupts
Polling ist bei Timer recht unpraktisch, aber Interrupts funktionieren
hier nicht richtig. signal.h habe ich zwar inkludiert, aber dennoch kann
mein CCSv5 nichts mit dem Schlüsselwort interrupt anfangen.
Und das obwohl ich es direkt aus den Codebeispielen kopiert hatte:
http://www.mikrocontroller.net/articles/MSP430_Codebeispiele#Initialisierung_des_Timers_A
.
Auch mit dem Vektor komme ich nicht ganz klar.
Der TIMERA0_VECTOR = 9*1u, also 0x09. Dabei kann es gar keine
ungeraden Zahlen annehmen, wenn man sich mal den TAIV-Register (Seite
381) ansieht.
Welcher der 3 Vektoren ist das nun und wie lauten die anderen beiden?
Wo steht das im Datenblatt?
Code
TACTL|=MC_2;// start; Counts TAR from 0 up to TACCR0;
37
38
39
while(1){
40
41
for(i=0;i<12;i++)
42
{
43
while(!(TACTL&TAIFG));// till TAIFG is set
44
TACTL&=~TAIFG;// reset TAIFG;
45
46
}
47
P1OUT^=0x01;// Toggle P1.0 using exclusive-OR
48
}
49
}
Im wesentlichen läuchtet P1.0 nur konstant. Was ist falsch?
Es gibt ja neben STOP drei Modi in dem der Timer laufen kann.
UP.. Der Timer Register TAR wird hochgezählt bis es den Wert von TACCR0
erreicht, danach wird der Interrupt ausgelöst und wieder auf 0 zurück
gesetzt. Genau das nutze ich.
CONTINUOUS.. Zählt TAR von 0x0000-0xFFFF. Könnte ich auch nutzen, wenn
ich TAR nach jedem interrupt preinitialisiere.
UP/DOWN.. Ist ganz nett. Aber hier nicht verwendbar.
Macro
Aus den Macros werde ich auch nicht ganz schlau.
Für das TACTL zum Beispiel gibt es die Macros:
TASSEL0: 0x0100
TASSEL1: 0x0200
TASSEL_0: 0*0x100u
TASSEL_1: 1*0x100u
TASSEL_2: 2*0x100u
TASSEL_3: 3*0x100u
Warum gibt es zwei verschiedene Nomenklaturen und warum bedeuten sie
nicht das selbe? Warum bedeutet TASSEL0 == TASSEL_1 und TASSEL1 ==
TASSEL_2?
Das gleiche gild für IDx:
ID0: 0x0040
ID1: 0x0080
ID_0: 0*0x0040u
ID_1: 1*0x0040u
ID_2: 2*0x0040u
ID_3: 3*0x0040u
So, das ist wieder mal ausschweifend geworden. Aber ich wollte, wenn
dann schon, alle Klarheiten beseitigt haben.
Wer mir aber einen einfachen Code mit Erklärungen posten kann der mit
1Hz arbeitet, dem wäre ich auch sehr dankbar.
Vielen Dank
Fabian
Aber ist schon krass.
Da will man mal was anderes sehen außer einen ATMEL schon findet man
kaum noch gute Tuts und kommt gänzlich durcheinander. :(
Dabei will ich nur ein Timer nutzen um eine LED blinken zu lassen.
Ich bin schon gespannt, wenn ich das UART nutzen will. Denn das habe ich
in dem Datasheet gar nicht gefunden.
Uff. Dabei ist es doch nur so ein kleines Steinchen.
TASSEL0 und 1 brauchst du nicht nutzen. Das ist intern. Für dich ist
hierbei nur der Wert mit dem "_" interessant. Und das _0 und _1 das
selbe sind steht doch auch im User's Guide. Ist beides SMCLK (wenn ich
mich richtig erinnere, hab's jetzt nicht nachgeguckt). Die Werte mit dem
Unterstrich erleichtern dir die Sache nur, weil sie mit den
Datenblattangaben übereinstimmen. Dahinter verbergen sich halt nur die
zwei Bits 0x0100 und 0x0200, welche durch TASSEL0 und 1 definiert sind.
Die kannst du auch selber direkt setzen, z.B. durch (TASSEL0 | TASSEL1).
Aber das brauchst du nicht, indem du einfach TASSEL_3 setzt.
Analog dazu mit ID und FAST allen anderen Bitkombinationen. Es gibt
manche, bei denen man wirklich selber die einzelnen Bits setzen muss,
z.B. beim SVS (istbaber vielleicht auch abhängig von der Header-Datei).
Der 12MHz Quarz ist natürlich NICHT für deinen Controller, sondern für
den anderen MSP auf dem Launchpad, welcher über USB die Verbindung zu
deinem eigentlichen Controller herstellt. Einen 1Hz Takt bekommst du am
ehesten, indem du den mitgelieferten 32k Quarz einlötest.
Dennis schrieb:> TASSEL0 und 1 brauchst du nicht nutzen. Das ist intern. Für dich ist> hierbei nur der Wert mit dem "_" interessant.
Danke.
> Und das _0 und _1 das
Du meinst sicher 0 und _1, oder? Denn das hatte ich gesagt.
> selbe sind steht doch auch im User's Guide. Ist beides SMCLK (wenn ich> mich richtig erinnere, hab's jetzt nicht nachgeguckt).
Nein! (Seite 378)
00 TACLK
01 ACLK
10 SMCLK
11 INCLK
Was diese bedeuten kann ich mir bis jetzt noch nicht erklären.
Ich dachte ja erst, das sei sowas die die Generelle Clock, die CPU
Clock, die Periphery Clock, usw. Aber so scheint das nicht zu sein.
Das einzige, dass ich glaube verstanden zu haben aus dem Kapitel "Basic
Clock Module+" ist, dass die Generelle Clock das MCLK ist. Das ist aber
nicht Thema hier.
> Die Werte mit dem> Unterstrich erleichtern dir die Sache nur, weil sie mit den> Datenblattangaben übereinstimmen. Dahinter verbergen sich halt nur die> zwei Bits 0x0100 und 0x0200, welche durch TASSEL0 und 1 definiert sind.
Moment!
Wieso ergibt sich z.B. der Wert des TASSEL_0 durch TASSEL0? Zumal die
auch inhaltlich nicht die gleichen sind, da 0x0100 != 0*0x100u!
In TASSEL0 steht 512 und in TASSEL_0 steht 0.
> Die kannst du auch selber direkt setzen, z.B. durch (TASSEL0 | TASSEL1).> Aber das brauchst du nicht, indem du einfach TASSEL_3 setzt.
Stimmt, so mache ich das ja auch bei den ATmegas und ATtinys.
Jetzt habe ich grundsätzlich den Unterschied zwischen X und _X
verstanden.
>> Analog dazu mit ID und FAST allen anderen Bitkombinationen. Es gibt> manche, bei denen man wirklich selber die einzelnen Bits setzen muss,> z.B. beim SVS (istbaber vielleicht auch abhängig von der Header-Datei).Dennis schrieb:> Der 12MHz Quarz ist natürlich NICHT für deinen Controller, sondern für> den anderen MSP auf dem Launchpad, welcher über USB die Verbindung zu> deinem eigentlichen Controller herstellt. Einen 1Hz Takt bekommst du am> ehesten, indem du den mitgelieferten 32k Quarz einlötest.
Der ist eingelötet. Aber mit welcher Frequenz wird denn der MSP430 im
Werkszustand betrieben/wie kann ich das einstellen?
Was ist ACLK/TACLK?
Wie wenn nötig kann ich denn auf den externen Quarz zugreifen, der
längst eingelötet ist?
Erstmal vielen Dank
Fabian
Dennis schrieb:> Und ja: Pollen bei nem Timer ist Schwachsinn :)
Klar, das weiß ich. Wie aber ändern, wenn der Beispielcode nicht
funktioniert?
Der Witz ist, auf http://inventortown.com wo man seine Projekte online
compilieren lassen kann, funktioniert es. Mit 8 Warnings zwar, aber es
geht. Wenn auch die Seite gerade down ist.
Muss ich sonst noch was inkludieren außer der signal.h?
Gruß und Danke
Fabian
Fabian Hoemcke schrieb:> Dennis schrieb:>> Der 12MHz Quarz ist natürlich NICHT für deinen Controller, sondern für>> den anderen MSP auf dem Launchpad, welcher über USB die Verbindung zu>> deinem eigentlichen Controller herstellt. Einen 1Hz Takt bekommst du am>> ehesten, indem du den mitgelieferten 32k Quarz einlötest.> Der ist eingelötet. Aber mit welcher Frequenz wird denn der MSP430 im> Werkszustand betrieben/wie kann ich das einstellen?
Der MSP430 im Launchpad arbeitet nach einem Reset immer mit dem internen
RC-Oszillator (DCO) und einer Taktfrequenz von etwa 1 MHz. Der DCO lässt
sich auch auf andere Frequenzen einstellen, wie das geht, steht im
Family User's Guide und ist auch in den Codebeispielen von TI zu finden.
Dort (also an beiden Stellen) ist auch beschrieben, wie mit einem
externen Quarz vorzugehen ist.
Der DCO ist bei einigen MSP430-Varianten werksseitig auf verschiedene
Frequenzen kalibriert, die Kalibrierdaten dafür sind im Info-Memory
abgelegt. Werden diese in die zugehörigen Register übertragen, läuft der
Controller halbwegs genau mit der jeweiligen Taktfrequenz.
Auch wenn ich sie schon erwähnt habe:
Sieh Dir die Codebeispiele von TI an, und sieh Dir dazu passend genau
die Dokumentation der jeweiligen Peripheriebausteine im Family User's
Guide an, insbesondere die Registerbeschreibung.
Mit den Informationen solltest Du Deine Fragen zum Timer_A selbst klären
können.
Danke rufus.
Müsste dann aber nicht einfach die LED mit 6Hz blinken anstatt mit 1Hz
wenn die Frequenz nur ein 12tel ist?
Warum leuchtet sie bei mir einfach konstant?
Franz schrieb:> 1/12tel? Bist du dir sicher, dass du weißt, was in deinem Programm> passiert?
Nein, sonst würde ich ja nicht fragen.
Aber wenn ich von einer Frequenz von 12MHz ausgegangen bin und mir aber
plausibel erklärt wurde dass und warum es aber 1MHz sind, dann dürfte
das Programm wohl nur mit 1/12tel der Geschwindigkeit laufen, oder?
Also die LED, die mit 1Hz blinken sollte wechselt aller 6s ihren
zustand.
Was ich versucht hatte der Maschine klar zu machen war folgendes:
1. Port1 Pin1 als Ausgang
2. TimerA Einstellungen löschen
3. ACLK als Taktquelle auswählen; ihn durch 8 teilen und den Timer im
StandBy halten
4. Den Counterregister TAR auf 0 setzen
5. Den Vergleichswert auf 62500 setzen (TACCR0)
6. Den Timer im UP Modus starten. TAR wird bis zum TACCR0 hochgezählt
der Interrupt ausgelöst und auf 0 zurückgesetzt.
7. 12 Mal wird der Interrupt abgewartet und dann die LED getoggelt.
Denn
Wenn dem nicht so ist, dann bitte nicht einfach süffisant fragen,
sondern sagen wo der Fehler ist.
Danke Nichtschläfer, schaue ich mir Morgen an.
Gruß
Fabian
Nichtschläfer schrieb:> http://processors.wiki.ti.com/index.php/MSP430_LaunchPad_LED_Timer
Dazu habe ich erstmal 2 Fragen:
1. Muss das mit Capture&Compare gemacht werden? Oder kann ich das nicht
einfach so machen wie ich es mir dache? (Oder wäre das, so wie ich es
mir dachte CC?)
2, Warum heißt im Beispiel das TACCTL0 Register nur CCTL0? Also anders
als im Datenblatt?
Danke
Fabian
TACTL|=MC_2;// start; Counts TAR from 0 up to TACCR0;
16
17
18
while(1){
19
20
while(!(TACCTL0&CCIFG));// till CCIFG is set
21
TACCTL0&=~CCIFG;// reset CCIFG;
22
23
P1OUT^=0x01;// Toggle P1.0 using exclusive-OR
24
}
25
}
Hatte wohl CC und Overflow vermischt.
Und mit ACLK die falsche (da viel langsamere) Clock ausgewählt.
Wird eigentlich nach einem Compare TAR automatisch zurück gesetzt oder
muss man das noch von Hand machen?
(Ich glaube nein, denn ich glaube aus diesem Grund funktionierte meine
Flagabfrage gar nicht.)
Wenn nein, könnte ich bei Modus Continuous sowohl Compare als auch
Overflow nutzen?
Danke alle
Fabian
Fabian Hoemcke schrieb:> Ich habe es hinbekommen
Wie? Wo? Was? Ohne Interrupt?
Da geht doch noch etwas. Also bitte noch einmal einen Blick auf das
Beispiel im TI Wiki werfen.
MSP430 schrieb im Beitrag #2855769:
> Fabian Hoemcke schrieb:>> Ich habe es hinbekommen>> Wie? Wo? Was? Ohne Interrupt?> Da geht doch noch etwas. Also bitte noch einmal einen Blick auf das> Beispiel im TI Wiki werfen.
Ja klar, würde ich ja gerne.
Immerhin bin ich jetzt generell durch den TimerA durchgestiegen und was
die Value Line da so bietet.
Was die Interrupts angeht, bin ich echt verwirrt.
Das Beispiel hier auf Mikrocontroller.net funktioniert leider nicht:
LED_DIR|=(LED_0+LED_1);// Set P1.0 and P1.6 to output direction
16
LED_OUT&=~(LED_0+LED_1);// Set the LEDs off
17
18
CCTL0=CCIE;
19
TACTL=TASSEL_2+MC_2;// Set the timer A to SMCLCK, Continuous
20
// Clear the timer and enable timer interrupt
21
22
__enable_interrupt();
23
24
__bis_SR_register(LPM0+GIE);// LPM0 with interrupts enabled
25
26
}
27
28
29
// Timer A0 interrupt service routine
30
#pragma vector=TIMERA0_VECTOR
31
__interruptvoidTimer_A(void)
32
{
33
timerCount=(timerCount+1)%8;
34
if(timerCount==0)
35
P1OUT^=(LED_0+LED_1);
36
}
http://processors.wiki.ti.com/index.php/MSP430_LaunchPad_LED_Timer
Das funktioniert zwar, aber ich kenne #pragma nicht und ich weiß auch
nicht, wie das mit dem Vector zusammen spielt.
Noch nicht, zu mindest.
Auch wenn ich es noch nicht verstehe, die generelle Struktur ist wohl
diese:
1
#pragma vector=INTERRUPT_VECTOR
2
__interruptvoidIrgendeinFunktionsname(void)
?
Und da bin ich wieder bei einer Frage vom Anfang des Threads, wenn diese
auch nicht so wichtig ist, wie ist es möglich, dass TIMERA0_VECTOR = (9
* 1u) also 0x0009 ist?
Dieser Wert ist doch gar nicht in der TAIV auslesbar!?
Gruß und Danke
Fabian
Fabian Hoemcke schrieb:> Das funktioniert zwar, aber ich kenne #pragma nicht und ich weiß auch> nicht, wie das mit dem Vector zusammen spielt.
Das ist die zu Deinem Compiler passende Variante, eine Interrupt-Routine
zu deklarieren. C kennt keine Interrupts, und daher erfindet jeder
Compilerhersteller eine andere Variante, so etwas zu behandeln. Für den
MSP430 sind drei Compiler relevant, IAR, CC und gcc.
Wenn Du Dir Codebeispiele ansehen willst, nimm die, die TI für die
'G2xxx-Familie veröffentlicht hat, die liegen sowohl in IAR- als auch in
CC-Syntax vor und sie sind auf die Peripheriemodule der 'G2xxx-Reihe
angepasst.
Die findest Du hier:
(für MSP430G2x53, MSP430G2x33, MSP430G2x13 und MSP430G2x03)
http://www.ti.com/litv/zip/slac485a
und hier:
(für MSP430G2x02, MSP430G2x12, MSP430G2x32 und MSP430G2x52)
http://www.ti.com/litv/zip/slac467a
Danke rufus,
ich bin aber einer, der es genau wissen muss.
Danke erstmal, für den Hinweis, dass das vom Compilerhersteller zu
Compilerhersteller unterschiedlich ist.
Die Direktive #pragma gibt es doch aber im ANSI-C. Das heißt, so könnte
mir das doch auch mit anderen Compilern so funktionieren oder?
Da Du ja viel darüber weißt, kannst Du mir folgende Fragen beantworten?
1: Wie genau funktioniert die Interruptlösung mit #pragma?
2: Hast Du einen guten Link zur Erklärung von #pragma?
3: Wird die ISR von TIMERA0_VECTOR immer aufgerufen wenn bei TimerA ein
Interrupt ausgelöst wird? Egal ob Overflow, CaptureCompare1 oder 2?
4: Diese Interruptdefinition bezieht sich auf welchen Compiler?
In den Beispielen steht ja IAR, ich kompiliere aber mit CCSv5 und da
steckt meines Wissens MSPGCC in der Toolchain.
Im Zweifel kann ich ja einfach die Struktur übernehmen, egal ob ich sie
verstehe. Aber ich würde es halt gerne nachvollziehen können.
Vielen Dank
Fabian
Fabian Hoemcke schrieb:> Die Direktive #pragma gibt es doch aber im ANSI-C. Das heißt, so könnte> mir das doch auch mit anderen Compilern so funktionieren oder?Nein. Die Direktive #pragma ist eingeführt worden, damit jeder
Compilerhersteller damit sein eigenes Süppchen kochen kann.
#pragma heißt soviel wie "Achtung, hier kommt was compilerspezifisches
nichtportables"
Fabian Hoemcke schrieb:> 1: Wie genau funktioniert die Interruptlösung mit #pragma?
Das weist den Compiler an, Informationen für den Linker im Objektcode zu
hinterlassen, die wiederum den Linker dazu bringen, die Adresse der auf
das #pragma folgenden ISR in die Interrupttabelle einzutragen.
Fabian Hoemcke schrieb:> 3: Wird die ISR von TIMERA0_VECTOR immer aufgerufen wenn bei TimerA ein> Interrupt ausgelöst wird?
Ja. In der ISR kann die genaue Interruptquelle noch weiter
aufgeschlüsselt werden, indem das Register TAIV untersucht wird.
Siehe "Family User's Guide", und siehe Codebeispiele von TI -- da steht
das alles drin.
Nachtrag:
Weitere Codebeispiele:
(für MSP430G2x01, MSP430G2x11, MSP430G2x21 und MSP430G2x31)
http://www.ti.com/litv/zip/slac463a
Rufus Τ. Firefly schrieb:> Das weist den Compiler an, Informationen für den Linker im Objektcode zu> hinterlassen, die wiederum den Linker dazu bringen, die Adresse der auf> das #pragma folgenden ISR in die Interrupttabelle einzutragen.
Kurz um, wenn ein Interrupt ausgelöst wird, wird in die entsprechende
Stelle des Programmspeichers (Interruptvektor?) gesprungen, in der der
Call zu dieser Funktion steht.
Und damit das dort eingetragen wird, diese Struktur?
Und genauer kann man es nicht verstehen?
Entschuldige bitte diese Frage. Den restlichen Code und anderen Code
kann ich ja verstehen. Bei dieser Funktion weiß ich zwar was sie macht,
aber warum sie es macht ist mir noch nicht ganz klar.
Was ist vector = genau? Was bedeutet __interrupt? Oder ist das so von
außen gar nicht zu verstehen, weil sich der Hersteller einfach was dabei
gedacht hat und im Compiler/Linker implementiert hat wie das zu lesen
und zu verstehen ist und mich das im Grunde gar nichts angeht?
Rufus Τ. Firefly schrieb:> Ja. In der ISR kann die genaue Interruptquelle noch weiter> aufgeschlüsselt werden, indem das Register TAIV untersucht wird.> Siehe "Family User's Guide", und siehe Codebeispiele von TI -- da steht> das alles drin.
Das heißt also, die Flags (TAIFG, CCIFG, ...) werden zurückgesetzt, in
der ISR kann man aber die Interrupts in der TAIV Bit1-Bit3 auslesen? Und
wie das geht, steht im User's Guide? Das habe ich dort leider nicht
gefunden. Hast Du ein gutes Beispiel (also von TI) dass das mal zeigt?
Denn
1
__interrruptvoidISR()
2
{
3
if(TAIV&TIMERA0_VECTOR==TIMERA0_VECTOR)// geht sicher viel besser
4
{
5
// do
6
}
7
}
kann nicht funktionieren, da TAIV Bit0 immer 0 ist und das untere
Nibble des TIMERA0_VECTOR (0x0009) /1001/b ist. Somit ergibt die Abfrage
immer false.
Oder verstehe ich das falsch?
Danke aber soweit.
Hast mir richtig geholfen.
Gruß
Fabian
Fabian Hoemcke schrieb:> Kurz um, wenn ein Interrupt ausgelöst wird, wird in die entsprechende> Stelle des Programmspeichers (Interruptvektor?) gesprungen, in der der> Call zu dieser Funktion steht.
So funktionieren Interrupts nun mal. Auf jedem Prozessor, der so etwas
hat.
> Und damit das dort eingetragen wird, diese Struktur?
Genau.
> Und genauer kann man es nicht verstehen?
Was soll man da genauer verstehen?
Der Prozessor hat eine hardwaremäßig vorgegebene Tabelle mit
Interruptvektoren, und wenn ein Interrupt ausgelöst wird, wird die dort
gespeicherte Adresse angesprungen.
So macht das (annähernd) jeder Prozessor, völlig unabhängig von der
verwendeten Programmiersprache.
> in> der ISR kann man aber die Interrupts in der TAIV Bit1-Bit3 auslesen? Und> wie das geht, steht im User's Guide? Das habe ich dort leider nicht> gefunden. Hast Du ein gutes Beispiel (also von TI) dass das mal zeigt?
Beispielsweise der Code in msp430g2xx1_ta03.c (aus den von mir
verlinkten TI-Beispielen) zeigt das:
1
#pragma vector=TIMERA1_VECTOR
2
__interruptvoidTimer_A(void)
3
{
4
switch(TAIV)
5
{
6
case2:
7
break;// CCR1 not used
8
9
case4:
10
break;// CCR2 not used
11
12
case10:
13
P1OUT^=0x01;// overflow
14
break;
15
}
16
}
Die Bedeutung von TAIV ist im "Family User's Guide" (slau144i.pdf) auf
Seite 381 aufgeschlüsselt.
Da ist eine Tabelle der möglichen Inhalte und der zugeordneten
Bedeutungen.
In TAIV steht also nicht der Interruptvektor drin (wozu sollte das
auch gut sein?), sondern eben ein numerischer Wert. Und wenn Du Dir
obiges Codefragment ansiehst, wirst Du die drei Werte, die hier eine
Bedeutung haben, wiedererkennen.
Wird es jetzt klarer?
Rufus Τ. Firefly schrieb:> Wird es jetzt klarer?
Ja, woran ich mich nur gestoßen hatte war, wie sind denn alle Interrupts
dahinein codiert. Aber anscheinend steht da immer nur einer, der höchst
priorisierte Interrupt drin.
Danke!
Ich glaube, jetzt habe ich alles.
Fabian Hoemcke schrieb:> Ja, woran ich mich nur gestoßen hatte war, wie sind denn alle Interrupts> dahinein codiert. Aber anscheinend steht da immer nur einer, der höchst> priorisierte Interrupt drin.
Der Interrupt wird durch ein Ereignis (z. B. Timer Overflow) ausgelöst.
Die CPU sichert ein paar Register, ändert ein paar interne Stati und
springt an die vorgesehene Adresse in der Interruptvektortabelle. Dort
steht meistens ein Sprung zur Interrupt Service Routine. Mit dem
besonderen Rücksprung - RETI - wird alles wieder aufgeräumt, alte Stati
eingestellt, Register restauriert und das Programm fortgesetzt.
Manchmal teilen sich verschiedene Ereignisse einen Interruptvektor. Dann
wird über Flags unterschieden, was die Ursache war. Die Flags werden oft
sinnvoll in einem Register zusammen gefasst. So wie im TAIV...
...und wenn sie nicht gestorben sind...