Hallo Henk,
Doch! Das ist ohne Probleme möglich!Vom (SIGNAL) interrupt heraus lasst sich keine function anrufen denn dann functioniert die interrupt function nicht richtig mehr.
Hier benutzt der Compiler ein Register. Das steht dann in der Interrupt-Routine nicht zur Verfügung.unsigned char MeinVar;
MeinVar=0x33;
volatile unsigned char MeinVar;:
hier wird ein Speicherplatz im Heap angelegt, wenn die Variable außerhalb einer Funktion (auch main()) deklariert wird. Auf den Heap kann man von jeder Stelle aus zugreifen.
Beispiel (aus asuro.c):
volatile unsigned char count72kHz;
/* uses timer2 (36kHz for IR communication */
/* counts falling and rising edge => 36kHz*2 = 72kHz */
SIGNAL (SIG_OUTPUT_COMPARE2)
{ count72kHz ++;
}
void dummy(int p){} // Damit der Compiler nicht optimieren kann.
int main(void)
{ while (count72kHz < 100)
dummy(count72kHz);
return 0;
}
Sowohl die Interrupt-Routine als auch 'main()' greifen korrekt auf 'count72kHz' zu.
------------------------------------
Interrupts erfolgen immer(!) asynchron zum Hauptprogramm, d.h. zu unvorhersehbaren Zeitpunkten. In der Interruptroutine weiß der Compiler deshalb nicht, welche Belegung die Register gerade haben.
Zum Beginn einer Interruptroutine werden deshalb zuerst alle Register, die in der Routine benutzt werden, gesichert (auf dem Stack) und am Ende wieder zurückgespeichert. Dies betrifft z.B. r24 im Beispiel:
**** SIGNAL (SIG_OUTPUT_COMPARE2)
push __zero_reg__
push __tmp_reg__
in __tmp_reg__, __SREG__
push __tmp_reg__
clr __zero_reg__
push r24
**** count72kHz ++;
lds r24, count72kHz
subi r24, lo8(-(1))
sts count72kHz, r24
pop r24
pop __tmp_reg__
out __SREG__, __tmp_reg__
pop __tmp_reg__
pop __zero_reg__
reti
**** void dummy(int p){}
ret
**** int main(void)
**** { while (count72kHz < 100)
.....
lds r24,count72kHz
cpi r24,lo8(100)
brsh .L26
.L24:
**** dummy(count72kHz);
lds r24,count72kHz
clr r25
rcall dummy
lds r24,count72kHz
cpi r24,lo8(100)
brlo .L24
Hier wird r24 mit dem Inhalt (Wert) von 'count72kHz' geladen. Das passiert auch, obwohl in 'main()' ebenfalls 'count72kHz' ins r24 geladen wird. r24 kann an anderer Stelle anderweitig benutzt worden sein. Der Compiler weiß eben nicht, ob der Interrupt nicht an dieser Stelle eintritt.
In 'main()' wird r24 zunächst für den Vergleich mit 'count72kHz' geladen. Kurz darauf für die Rarameterübergabe an 'dummy()' noch einmal, obwohl der Wert doch eigentlich schon in r24 steht. Da neue Laden ist aber notwendig, da eventuell zwischendurch der Interrupt eingetroffen sein könnte. Dieser würde den Inhalt von 'count72kHz' verändern. Theoretisch könnte es sein, dass der Vergleich (count72kHz < 100) und der Aufruf von Dummy mit unterschiedlichen Werten von 'count72kHz' erfolgen kann. Wenn man dies verhindern will, muss man 'count72kHz' in eine nicht als volatile deklarierte Variable zwischenspeichern:
unsigned char x;
x = count72kHz;
while ( x < 100)
{ dummy(x);
x = count72kHz;
}
----------------------------------------
Wenn eine Variable als volatile gekennzeichnet ist, benutzt der Compilier kein Register!Was ist met der Wert gemeint? Die Wert vom C-variabele oder die Wert vom Register die fur die C-variabele vom Assembler dafur benutzt wird?
Gruß Red Baron
Lesezeichen