Forum: Compiler & IDEs Timer-Interrupt ohne Funktion ?


von Franz Wudy (Gast)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

Wenn Du globale Variablen, die in Interrupt Handlern verändert werden,
nicht als 'volatile' deklarierst, kann alles Mögliche passieren...

von johnny.m (Gast)


Lesenswert?

Sorry, Blindheit... Ist ja tatsächlich volatile... Sorry, noch zu früh
am morgen

von Franz Wudy (Gast)


Lesenswert?

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

von Franz Wudy (Gast)


Lesenswert?

das ging jetzt aber gleichzeitig! ;-)

anderer tip?

von johnny.m (Gast)


Lesenswert?

>  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...

von Franz Wudy (Gast)


Lesenswert?

was schlägst du dann vor den prescaler auf eins zu bekommen?

von johnny.m (Gast)


Lesenswert?

Ne, das stimmt ja auch. Sorry, bin echt noch nicht wach. Ich gebs auf...

von Franz Wudy (Gast)


Lesenswert?

net aufgeben! G

von johnny.m (Gast)


Lesenswert?

...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...

von Franz Wudy (Gast)


Lesenswert?

Nur warum wird der Interrupt niemals ausgelöst, bzw. warum ändert sich
am Wert der dummy-Variable nichts?!

Ich verstehs nicht!

von johnny.m (Gast)


Lesenswert?

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...

von Franz Wudy (Gast)


Lesenswert?

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!

von Karl heinz B. (kbucheg)


Lesenswert?

Das OCIEA Bit ist in der extended Interrupt Mask

Also:

   ETIMSK |= (1 << OCIE3A); // Interrupt für Timer einschalten

Damit gehts zumindest im Simulator

von Franz Wudy (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.