Hallo zusammen, ich bin gerade verzweifelt, weil mich ein Mega128 und WinAVR 20060125 bei einer simplen Timerinterrrupt-Routine ärgert. Das folgende Beispielprogramm soll einfach auf dem USART den Wert der globalen Variable dummy ausgeben. Diese wird vom Timer-ISR hochgezählt. Also sollte am USART 0\n 0\n 0\n 0\n 2\n 2\n 2\n 2\n .... ausgegeben werden. Klapppt aber nicht, ich komme nie bei der 2 an! Ich habe den Eindruck, der Handler wird nie aufgerufen. Der Vector-Name sollte stimmen, IRQ ist aktiviert, Controller funktioniert ansonsten brav. Bin ich blind oder warum funktioniert das nicht ? #define MAXINTEXT 101 #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #define F_CPU 16000000UL #include <util/delay.h> #include <stdlib.h> // für itoa, strtod #include <string.h> // für strcat #include <math.h> #include "Mega128RS232.h" // Strings für Input/Outputverwaltung und allgemeine Flags char outtext[MAXINTEXT], string[21]; // für Ausgaben auf LCD und RS232 char usbintext[MAXINTEXT]; char ictext[MAXINTEXT]; unsigned char command_done; // Variablen aus anderen C-Dateien extern volatile unsigned char command_complete; // aus rs232.c extern volatile unsigned char dataready; // aus rs232.c volatile unsigned int dummy = 0; int main(void) { USART_Init(1); // initialisiert die serielle Schnittstelle sei(); TCCR3A = 0; TCCR3B = (1 << WGM32); // WGM32: Timermode Normal TCCR3B |= (1 << CS30) & ~(1 << CS32) & ~(1 << CS31); // Prescaler = 1 OCR3A = 512; // gibt rund 60 µs TIMSK |= (1 << OCIE3A); // Interrupt für Timer einschalten while(1) { _delay_us(10); utoa(dummy, outtext, 10); strcat(outtext, "\n"); USART1_Transmit_string(outtext); // an den PC rausschreiben } return(0); // :-) } ISR(TIMER3_COMPA_vect) // wird aufgerufen, wenn der Timer-IRQ auftritt { dummy += 2; } Ciao - Franz
Wenn Du globale Variablen, die in Interrupt Handlern verändert werden, nicht als 'volatile' deklarierst, kann alles Mögliche passieren...
Sorry, Blindheit... Ist ja tatsächlich volatile... Sorry, noch zu früh am morgen
Danke Johnny.m für deine Antwort, jedoch: Wie in der letzten Zeile vor der main{...} zu ersehen ist, ist die Variable dummy als volatile deklariert. Daher kann ich deinen Einwand nicht verstehen! Liebe Grüße - Franz
> TCCR3B |= (1 << CS30) & ~(1 << CS32) & ~(1 << CS31);
Was ist das denn? Das kann so nicht wirklich funktionieren, zumindest
wahrscheinlich nicht so, wie Du Dir das vorstellst. Mit der Anweisung
setzt Du alle Bits in TCCR3B, bis auf CS32 und CS31. Ich glaube, das
ist nicht in Deinem Sinn...
Ne, das stimmt ja auch. Sorry, bin echt noch nicht wach. Ich gebs auf...
...Wobei, die &-Verknüpfungen bringen einfach nix. Lass sie der Übersichtlichkeit halber einfach weg... Deshalb auch meine Verwirrnis. Schreib einfach TCCR3B = (1 << WGM32) | (1 << CS30); Dann sind automatisch alle Bits bis auf WGM32 und CS30 '0'. Auch wenn das wahrscheinlich nicht der gesuchte Fehler ist. 'Falsch' in dem Sinne ist es ja nicht...
Nur warum wird der Interrupt niemals ausgelöst, bzw. warum ändert sich am Wert der dummy-Variable nichts?! Ich verstehs nicht!
Mir ist da noch was aufgefallen (jetzt, wo ich langsam wach werde): Du schreibst, der Wert soll alle 60 µs erhöht werden. Wie soll denn in 60µs der ganze Rest inkl. serieller Ausgabe funktionieren? Je nachdem, mit welcher Baudrate Du arbeitest, sind das einige ms. Ich vermute mal (ohne den Rest des Programms zu kennen) dass es da ein Timing-Problem geben dürfte. Den Fehler an sich sehe ich aber immer noch nicht...
naja... das rausschreiben wird ja auch gehörig verzögert, der interrupt zum hochzählen sollte also schon mal ausgeführt werden, bzw. dummy erhöht werden. ich werd noch wahnsinnig!
Das OCIEA Bit ist in der extended Interrupt Mask Also: ETIMSK |= (1 << OCIE3A); // Interrupt für Timer einschalten Damit gehts zumindest im Simulator
Wunderprächtig, da bin ich auch gerade drauf gekommen! Herzlichen Dank trotzdem. Da zieht man vom Interrupt1 auf den Dreier um und ersetzt einfach die Ziffern, und schon gehts nimmer! Gemein! Franz
Daher haben die neuen AVRs auch ein eigenes TIMSKx-Register für jeden Timer. Da sollte das dann offensichtlich sein.
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.