Hallo,
ich versuche gerade die Atmel Applicationnote 444 zu verstehen.
Hier werden viele Funktionen in der Form
void Funktion(void)
{
...
}
eingeführt. Das ist mir auch verständlich.
Neu ist mir allerdings, wie hier Interruptroutinen deklariert werden.
Diese sehen z.B. so aus:
__interrupt void CurrentMeasurement()
{
...
}
Meine Frage ist, was nun der Unterschied zwischen beiden ist und warum
man manchmal Funktionen und manchmal Interrupts hernimmt.
Außerdem habe die diese Form mit "__interrupt void..." noch nicht
gesehen.
Würde ich diesen dann wie eine Funktion aufrufen, also einfach mit
CurrentMeasurement();
Bin über jegliche Hilfe sehr dankbar.
Grüße
robert wrote:
> Neu ist mir allerdings, wie hier Interruptroutinen deklariert werden.> Diese sehen z.B. so aus:>> __interrupt void CurrentMeasurement()> {> ...> }>> Meine Frage ist, was nun der Unterschied zwischen beiden ist und warum> man manchmal Funktionen und manchmal Interrupts hernimmt.
Ein Interrupt ist ein völlig anderes Konzept als eine normale
Funktion.
Eine normale Funktion wird aufgerufen, wenn in deinem Programm
ein Aufruf dazu vorkommt.
Ein Interrupt hingegen wird mit einem Ereignis gekoppelt. Wenn
dieses Ereignis eintritt, dann wird die Interrupt Funktion aufgerufen.
Die Interrupt Funktion kann also zu jedem beliebigen Zeitpunkt
ausgelöst werden, wobei das Auslösen vom Auftreten irgendwelcher
Dinge abhängt. In einem AVR sind ISR (Interrupt Service Routine)
immer an irgendwelche Dinge der Hardware gekoppelt. Ein Timer
macht zb gerade einen Überlauf und kann als Folge davon einen
Overflow-Request absetzen. Hat man eine ISR Funktion für
diesen Fall vorgesehen und diese auch entsprechend registriert,
dann wird die Funktion aufgerufen sobald der Timer einen Overflow
meldet, unabhängig davon wo sich das restliche Programm gerade
rumtreibt.
> Außerdem habe die diese Form mit "__interrupt void..." noch nicht> gesehen.
Das ist compilerspezifisch. Interrupts sind ausserhalb der
C-Norm, daher gibt es dafür kein standardisiertes Sprachkonstrukt.
> Würde ich diesen dann wie eine Funktion aufrufen, also einfach mit
Du rufst sie gar nicht auf. Du installierst sie nur und gibst
den zugehörigen Interrupt frei. Tritt das Ereignis ein, wird
die Funktion aufgerufen.
Ok, vielen Dank soweit.
Ich würde also hier
__interrupt void CurrentMeasurement()
{
...
}
nur reinschreiben, was nach dem Interruptaufruf abgearbeitet werden
soll.
Was ich allerdings nicht finde, wo und das Ereignis festgelegt wird,
welches den Interrupt aufruft.
Die Harwareroutinen sind mir klar. Z.B. Ein Timer Overflow Interrupt
wird ausgelöst, wenn ein entsprechendes Interrupt Flag gesetzt wird. In
den Atmel Datenblätter sind ja alle solchen Interrupts aufgeführt. Über
Softwareinterrupts habe ich nun die Möglichkeit, mir selber welche zu
erzeugen.
Wenn ich z.B. will, dass immer, wenn ein ADC einen Wert von 500
überschreitet, eine Interruptroutine ausgeführt wird, dann müsste ich
diese Bedingung irgendwo einführen. Wie würde dan dann aussehen ?
robert wrote:
> __interrupt void CurrentMeasurement()> {> ...> }>> nur reinschreiben, was nach dem Interruptaufruf abgearbeitet werden> soll.>> Was ich allerdings nicht finde, wo und das Ereignis festgelegt wird,> welches den Interrupt aufruft.
Normalerweise ist das Ereignis bei einem AVR in irgendeiner Form
durch den 'Funktionsnamen' oder einen Zusatz dazu festgelegt.
> den Atmel Datenblätter sind ja alle solchen Interrupts aufgeführt. Über> Softwareinterrupts habe ich nun die Möglichkeit, mir selber welche zu> erzeugen.
Von welchem Atmel Chip reden wir?
> Wenn ich z.B. will, dass immer, wenn ein ADC einen Wert von 500> überschreitet, eine Interruptroutine ausgeführt wird, dann müsste ich> diese Bedingung irgendwo einführen. Wie würde dan dann aussehen ?
Bei einem 8-Bit AVr, wie er hier im Forum gang und gäbe ist?
Gar nicht.
Welche Interrupts es gibt, ist von der Hardware (vom Prozessor)
vorgegeben.
Bei den Wald und Wiesen AVR, kann ein ADC m.W. lediglich einen
Interrupt auslösen, wenn er eine Messung fertig hat. Es steht dir
natürlich frei innerhalb der ISR den gemessenen Wert mit 500 zu
vergleichen und dann weiter darauf zu reagieren. Aber einen Interrupt
speziell für den Fall, dass der ADC Wert eine Grenze übersteigt, ist
nicht vorgesehen (*)
(*) Was nicht unbedingt heist, dass es nicht einen Prozessor auf
diesem Planeten gibt, der auch das kann. Die üblichen ATMegaXX
und ATTinyXX, mit denen wir es hier im Forum zu tun haben, können
es nicht.
robert wrote:
> Wenn ich z.B. will, dass immer, wenn ein ADC einen Wert von 500> überschreitet, eine Interruptroutine ausgeführt wird, dann müsste ich> diese Bedingung irgendwo einführen. Wie würde dan dann aussehen ?
Das geht nicht.
Du kriegst jedesmal nen Interrupt, wenn der ADC mit Messen fertig ist.
Und in dem Interrupt mußt Du dann den ADC-Wert mit 500 vergleichen und
dann die gewünschte Task ausführen.
Es gibt allerdings MCs, die sowas können, z.B. die Silabs 8051.
Peter
Ich benutze den Atmel Mega 168
Dann habe ich es wohl falsch verstanden, dass ich mir beliebige
Interruproutinen "zusammenbasteln" kann ?
Aber wann wird dann eine solche Interruptroutine überhaupt aufgerufen ?
__interrupt void CurrentMeasurement()
{
...
}
Diesen Auszug habe ich im Anhang zusammengestellt. Man findet ihn in
main.c, Seite 9
Diese Funktion musst Du Dir selber aufrufen, dann weisst Du auch wann
das passiert.
Interrupts, die an eine Hardware gekoppelt sind haben spezielle Namen
(siehe Datenblatt).
robert wrote:
> Aber wann wird dann eine solche Interruptroutine überhaupt aufgerufen ?>> __interrupt void CurrentMeasurement()> {> ...> }
In deinem ganzen Auszug gibt es keine Funktion dieses Namens,
es gibt aber eine CurrentMeasurementComplete
1
#pragma vector=ADC_vect
2
__interruptvoidCurrentMeasurementComplete()
3
{
4
shuntVoltageADC=ADCH;
5
currentUpdated=TRUE;
6
CLEAR_ALL_TIMER0_INT_FLAGS;
7
}
und da steht klar dabei
1
#pragma vector=ADC_vect
dass diese Funktion ein Interrupt Handler für den ADC Interrupt
ist, als aufgerufen wird, wenn der ADC mit einer Messung fertig
ist.
robert wrote:
> __interrupt void CurrentMeasurement()> {> ...> }
Das ist auch nur die halbe Wahrheit. Da gehört noch die Zeile mit dem
#pragma dazu, die definiert, für welchen Interrupt-Vektor der Handler
sein soll. Die Software der Appnote ist für den IAR-Compiler geschrieben
und jeder Compiler benutzt, wie Karl Heinz schon gesagt hat, eine
compilerspezifische Syntax für solche nicht-ANSI-Erweiterungen. Wenn Du
nicht mit dem IAR-Compiler arbeitest, musst Du die Definitionen der
Interrupt Handler entsprechend ändern (und auch noch einige andere Dinge
wie verwendete Bibliotheken usw.).
Generell kann ein Interrupt Handler nicht aus dem laufenden Programm
heraus aufgerufen werden, sondern ausschließlich von dem damit
zusammenhängenden Hardware-Ereignis. Und wie das generell geht, ist im
AVR-Tutorial bzw. im AVR-GCC-Tutorial ganz gut beschrieben.
EDIT:
Jetzt dachte ich ja, ich wär mal schneller als Karl Heinz, aber wieder
nix...