Hallo, ich hab ein kleines Problem mit den Interrupts bei meinem Atmega48. Und zwar sprinngt mir das Programm nach einem Timerinterrupt nicht mehr zurück in die main Funktion. Ist das normal? Ich hab auch schon versucht mit reti() wieder zurück zu springen, aber dann land ich wieder ganz am Anfang von main, also noch vor der Initialisierung der Timer und Interrupts. Das ist dann auch nicht Sinn der Sache. Gibt es da eine andere Lösung oder muss ich mich irgendwie von Interrupt zu Interrupt durchmogeln? Was passiert eigentlich wenn ein Interrupt von einem Anderen unterbrochen wird? Hab keine Prio für die Interrupts gefunden. Vor allem springt er dann wenigstens in die unterbrochene Funktion zurück oder ist da dann das gleiche Problem? Danke im Voraus für die Mühe p.s. ich programmier in C mit avrstudio 4
Hi Hans, ohne Code wird das nur ein Ratespiel. Deine Fragen versuche ich trotzdem mal zu beantworten: > Und zwar sprinngt mir das Programm nach einem Timerinterrupt nicht mehr > zurück in die main Funktion. Ist das normal? Das hängt davon ab, was in der ISR steht (z.B. eine Endlosschleife?). > Ich hab auch schon versucht mit reti() wieder zurück zu springen, aber > dann land ich wieder ganz am Anfang von main, also noch vor der > Initialisierung der Timer und Interrupts. "reti" solltest Du in einer ISR in C auch nicht hinzufügen. > Gibt es da eine andere Lösung oder muss ich mich irgendwie von Interrupt > zu Interrupt durchmogeln? Durchmogeln? Der uC macht nur, was Dein Programm ihm sagt. > Was passiert eigentlich wenn ein Interrupt von einem Anderen > unterbrochen wird? Hab keine Prio für die Interrupts gefunden. Verwendest Du "ISR()"? Dann wird nichts unterbrochen. Wenn während der ISR ein weiterer Interrupt gesetzt wird, kehrt das Programm zunächst zu dem Punkt+1 zurück, wo es unterbrochen wurde, dann zur zweiten ISR. Mehr kann ich ohne Code nicht helfen. Gruß Fred
Danke Fred im code steht eignetlich noch nix interresantes drin. also nur die paar haeder, die main funktion, eine init() zur Belegung der register für Timer und Interrupts und die paar ISR() Funktionen. int Zeitbasis; int main(void){ init(); while(1) { // hier solln noch viel entstehn :) while(Zeitbasis < 98){} // warten bis 10 ms vergangen sind // HIER KOMM ICH NICHT MEHR HIN Zeitbasis = 0; } return 0; } ISR(TIM0_vect){ Zeitbasis++; } die init() und die header spar ich mir mal, sind ja normal standard
Hallo Hans, nur eben mal auf die Schnelle: 1. Wo ist denn Dein TIM0_vect definiert? Welche WinAVR Version verwendest Du? Für den ATmega48 kenne ich nur die folgenden Timer0-Interrupt-Vektoren: TIMER1_OVF_vect TIMER0_COMPA_vect TIMER0_COMPB_vect TIMER0_OVF_vect 2. Zeigst Du uns bitte die Initialisierung des Timers? Viele Grüße Fred
hast recht hab den code ausm Gedächtnis geschrieben, heißt natürlich TIMER0_OVF_vect und steht in iomx.h TCCROA=0x00; TCCR0B=0x02; //2500kHz TCNT0=0X00; OCR0A=0x00; OCR0B=0x00; TIMSK0=0x01; hab aber auch schon viel langsamer versucht, hat auch nix gebracht
Zeitbasis ist nicht volatile deklariert, wird aber in main und in der ISR benutzt. Da wird der Optimizer reinhauen... BTW: Nächstes Mal bitte nur einmal posten...
Zusätzlich zu den Fragen von Fred S. fällt mir das fehlende volatile
bei int Zeitbasis; auf. Ohne volatile Kennzeichnung geht der Compiler
davon aus, dass sich Zeitbasis in main nie ändert. Möglicherweise
hat Sven Pauli das gemeint mit dem Optimierer.
> die init() und die header spar ich mir mal, sind ja normal standard
Standard hin oder her. Den obenstehenden Code kann man jedenfalls nicht
in der eigenen Toolchain übersetzen oder für den Atmega48 simulieren.
Aber wie du meinst - du suchst Hilfe, nicht "wir" ;-)
die init ist mit der Timerkonfiguration eigentlich schon fast komplett, da fehlt nur noch sei(); und Zeitbasis=0; zu den Headern <stdint.h> <avr/interrupt.h> <avr/io.h> <inttypes.h> wo muss das volatile eigentlich genau hin hab alle positionen ausprobiert, ohne Erfolg. Zeitbasis wird auch hochgezählt, es zählt aber über die 98 drüber ohne aus der while zu fliegen
> wo muss das volatile eigentlich genau hin hab alle positionen > ausprobiert, ohne Erfolg. In die Deklaration: volatile int Zeitbasis; > Zeitbasis wird auch hochgezählt, es zählt aber über die 98 drüber ohne > aus der while zu fliegen Bitte poste mal den echten Code, entweder als Anhang oder per Cut&Paste, und keine aus dem Gedächtnis hingeschriebene Fragmente.
#include <stdint.h> #include <avr/interrupt.h> #include <avr/io.h> #include <inttypes.h> volatile int Zeitbasis; void init() { //Variablen initialisieren Zeitbasis=0; //Timer 0 TCCR0A=0x00; TCCR0B=0x02; TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; TIMSK0=0x01; sei(); } int main (void) { init(); while(1) { while(Zeitbasis < 98) { } } return 0; } ISR (TIMER0_OVF_vect) { Zeitbasis++; }
Hallo Hans, die Deklaration und Verwendung von "Zeitbasis" ist in Ordnung. Woran kannst Du aber überhaupt erkennen, dass der Programmzeiger in der ISR stecken bleibt, wie Du im ersten Posting geschrieben hast? Übrigens: Schöner wäre es, wenn Du den Code mit symbolischen Bitnamen und Kommentaren schriebst, z.B.:
1 | TCCR0B=1<<CS01; // F_CPU/8 = 2,5MHz |
Gruß Fred
Passt. In der Simulation funktioniert der Code (er macht nur nicht viel).
1 | #include <stdint.h> |
2 | #include <avr/interrupt.h> |
3 | #include <avr/io.h> |
4 | #include <inttypes.h> |
5 | |
6 | volatile int Zeitbasis; |
7 | |
8 | void init() |
9 | {
|
10 | //Variablen initialisieren
|
11 | Zeitbasis=0; |
12 | |
13 | //Timer 0
|
14 | TCCR0A=0x00; // Normal Mode |
15 | TCCR0B=0x02; // 0x02 = (1<<CS01) = Prescaler 8 |
16 | TCNT0=0x00; // 0..255 |
17 | OCR0A=0x00; // unwichtig da Normal Mode |
18 | OCR0B=0x00; // unwichtig da Normal Mode |
19 | TIMSK0=0x01; // 0x01 = 1<<TOIE0) |
20 | |
21 | sei(); |
22 | }
|
23 | |
24 | int main (void) |
25 | {
|
26 | init(); |
27 | |
28 | while(1) |
29 | {
|
30 | // F_CPU in MHz Schleifendauer
|
31 | // 1 201 ms
|
32 | // 8 25 ms
|
33 | // 16 12,5 ms
|
34 | while(Zeitbasis < 98) |
35 | {
|
36 | }
|
37 | |
38 | // Zeitbasis zurücksetzen
|
39 | cli(); // Interrupts sperren |
40 | Zeitbasis = 0; |
41 | sei(); // Interrupts freigeben |
42 | |
43 | PORTD ^= (1<<PD1); // zu meiner Info, weil sonst nicht viel passiert |
44 | }
|
45 | |
46 | return 0; |
47 | }
|
48 | |
49 | |
50 | ISR (TIMER0_OVF_vect) |
51 | {
|
52 | // F_CPU in MHz Aufruf ca. alle (EDIT)
|
53 | // 1 2 ms 1/(1000000 / 8 / 256) Sekunden
|
54 | // 8 0,256 ms 1/(8000000 / 8 / 256) Sekunden
|
55 | // 16 0,128 ms 1/(16000000 / 8 / 256) Sekunden
|
56 | Zeitbasis++; |
57 | }
|
ich hab einen Haltepunkt im Interrupt und beobachte wie die zeitbasis hochgezählt wird. OHH mist mir ist bei der ganzen testerrei eine codezeile verloren gegangen. nach der while ( Zeitbasis <98){} war mal Zeitbasis = 0; ok dann wars doch das volatile danke an alle, war echt super von euch nur noch eine kleine frage wenn ich schonmal dabei bin. Muss ich operationen iin der ISR vor Unterbrechungen schützen z.b. mit atomic?
Hallo Hans, na also -- ging doch! > nur noch eine kleine frage wenn ich schonmal dabei bin. Muss ich > operationen iin der ISR vor Unterbrechungen schützen.... Nein, ist bei der ISR nicht nötig... es sei denn, Du hast ein ein "sei();" in der ISR! Gruß Fred
Nein, du musst aber beim Zurücksetzen von Zeitbasis Unterbrechungen verhindern. Ich habe es gerade in das Listing eingebaut.
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.