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 | __interrupt void CurrentMeasurementComplete() |
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...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.