Forum: Compiler & IDEs mega8 Timer Interrupt funktioniert nicht.


von Dominik S. (dominik-s)


Lesenswert?

Hallo zusammen. Habe ein kleines Problem. Die ISR des Timers 0 wird 
einfach nicht aufgerufen. Ich weiß einfach nicht wo der Fehler sein 
soll.

Hier mein Code:
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <avr/interrupt.h>
4
5
ISR(TIMER0_OVF_vect)
6
{
7
  PORTD = 0x00;
8
}
9
10
int main(void)
11
{
12
  DDRC = 0b00111100;
13
  DDRD = 0b11111111;
14
15
  TCCR0 |= (1 << CS00) | (1 << CS01);
16
  TIMSK |= TOIE0;
17
  sei();
18
19
  PORTD = 0xFF;
20
21
  while(1);
22
}

Zur Info: An Port D hängen LEDs. Sie werden testweise am Anfang 
eingeschaltet und sollten durch die erste ISR wieder aus gehen.

Wo steckt der Fehler??

Gruß, Dominik

von Johannes M. (johnny-m)


Lesenswert?

Bist Du sicher, dass die LEDs low-side an den Pins hängen? Nur dann 
schaltest Du sie aus, wenn Du eine Null in das Portregister schreibst. 
Wenn die LEDs high-side dranhängen (wie z.B. beim STK500), dann ist es 
genau andersrum.

von Dominik S. (dominik-s)


Lesenswert?

Ich bin mir zu 1000% ganz sicher, dass ich sie Lowside angelötet habe 
und sie funktionieren auch alle acht.

von loetkolben (Gast)


Lesenswert?

Die Zeile ist falsch:
1
  TIMSK |= TOIE0;

sollte so sein, da TOIE0 das Bit 0 ist.
1
  TIMSK |= (1 << TOIE0);

gruß,
Loetkolben

von Dominik S. (dominik-s)


Lesenswert?

Vielen Dank, das wars. Keine Ahnung warum ich das an der Stelle falsch 
geschrieben habe...

von Heiko H. (mail23)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe auch mal noch eine Frage zur Timerverwendung. Und zwar habe ich 
versucht dieses Beispiel ( 
http://www.mikrocontroller.net/mc-project/Pages/AVR/Software/timer_bsp_interrupts.c 
) auf meinen Atmega8 und AVR-Studio 4 anzupassen.

Es wird zwar ohne Fehler compiliert, aber der Simulator meckert: AVR 
Simulator: Uninitialized stack pointer used at 0x0061 ... und ähnliche 
Fehler (screen01)

Auch wenn ich den Code übertrage, tut sich am PortB nicht. Was mache ich 
falsch? Stimmt evtl. etwas mit den Fuse-Bits nicht (screen02)?



Hier mein Code:

#include <avr/io.h>
#include <avr/interrupt.h>

volatile char count, i;

int main (void) {
  DDRB = 255;
  TIMSK = (1<<TOIE0);
  TCNT0 = 0;
  TCCR0 = (1<<CS00) | (1<<CS01);
  sei();
  while (1) {
  i=1;
  }
  return 0;
}

ISR (TIMER0_OVF_vect) {
  if (count == 1) {
    PORTB = 255;
    count--;
    return;
  }
  if (count == 0) {
    PORTB = 0;
    count++;
    return;
  }
}

von Heiko H. (mail23)


Angehängte Dateien:

Lesenswert?

Hier noch screen02

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@  Heiko B.

Ich kann den Fehler mit AVR-Studio 4.12 SP2 und WinAVR 20071222 
nicht nachvollziehen.

Die Adresse 0x000061 liegt bei meinem Disassembler-Listing in der ISR 
und in der Nähe des 1. return. Probiere mal die ISR so umzuschreiben, 
dass die ISR nur an einer Stelle verlassen wird z.B. so:
1
ISR (TIMER0_OVF_vect) {
2
  if (count == 1) {
3
    PORTB = 255;
4
    count--;
5
  }
6
  else if (count == 0) {
7
    PORTB = 0;
8
    count++;
9
  }
10
}

von Hmm... (Gast)


Lesenswert?

1
ISR (TIMER0_OVF_vect) {
2
  if (count == 1) {
3
    PORTB = 255;
4
    count--;
5
    return;
6
  }
7
  if (count == 0) {
8
    PORTB = 0;
9
    count++;
10
    return;
11
  }
12
}

Das ginge bei den neueren AVRs auch einfacher:
1
ISR (TIMER0_OVF_vect) {
2
  PINB = 0xff;
3
}

Damit lassen sich Optimierungs-Bedingte Fehler einfacher ausschliessen 
wenn man eh nur einen Pin toggeln möchte.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

ADD: Disassembler-Listing im Anhang (ohne Optimierung, Atmega8, 1 Mhz)

0x0061 ist auch die Lage der Variablen count im RAM. Möglicherweise 
liegt da dein Problem begraben. Es würde vielleicht helfen, dein 
Disassembler-Listing zu sehen. An den Fuses wird dieses Problem nicht 
hängen.

von Heiko H. (mail23)


Lesenswert?

Hallo Stefan,

danke für deine unterstützung. Leider kommt ein ähnlicher Fehler, wenn 
ich mit else if arbeite. Sind deine Fuse-Bits genauso gesetzt wie meine?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du bist doch im Simulator (screen01.JPG), welche Rolle spielen da die 
Fuses? Ich habe an den Fuses nichts geändert, als ich von Build nach 
Start Debugging im Simulator gewechselt bin. Es würde vielleicht helfen, 
dein Disassembler-Listing zu sehen.

von Heiko H. (mail23)


Angehängte Dateien:

Lesenswert?

So musste jetzt erst mal gucken, wie man an das Disassambler-Listing 
dran kommt. Hier ist nun meins:

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Aufruf von main() aus dem AVR Startupcode heraus, nach den ganzen 
Initialisierungen wird mit CALL gemacht. Und das mosert der Debugger an.
1
+00000061:   940E0067    CALL    0x00000067       Call subroutine

Wenn du meine Disassembler-Listing anschaust, dort wird statt CALL ein 
RCALL gemacht und alle JMP am Anfang sind RJMPs.

Es wurde bei deinem Listing beim Kopilieren eine AVR Architektur 
benutzt, für die das (avr-lic interne) Makro _AVR_HAVE_JMP_CALL_ 
definiert ist.

Ich kann mir fast nur vorstellen, dass bei dir als Device kein Atmega8 
sondern ein anderer AVR eingestellt ist. Der Atmega8 braucht die 
Architektur avr4 und bei der ist dieses Makro nicht definiert. In 
einem korrekten Listing für Atmega8 müssen RJMP und RCALL auftauchen.

Kontrolliere bitte mal die Seite (Menü) -> Project -> Configuration 
Options in AVR-Studio, ob du wirklich den atmega8 eingestellt hast. 
Dann einmal alles sauber machen (Clean bei Build...) und neu übersetzen.

von Heiko H. (mail23)


Lesenswert?

Hallo Stefan,

danke für deine Hilfe. Es war wie du es sagtest. Ich hatte tatsächlich 
den falschen Controller eingestellt. Jetzt funktioniert das ganze 
einwandfrei.

Hier nochmal für alle die es intressiert der Code: Ich nutze das 
AVR-Studio Version 4.14. Es wird der Timer0 beim Atmega8 verwendet. 
Alles Pins des PortB blinken bei einer Prozessorfrequenz von 4 MHz mit 
ca. 0,5 Hz. Es ist lediglich ein erstes Beispielprogramm zur Verwendung 
des Timer0. Die genaue Ausgangsfreqenz habe ich nicht ermittelt.

/*Testprogramm Timer0
  Bei einer Prozessorfrequenz von 4 MHz, wird an Port B eine
  Blinkfrequenz von ca. 0,5 Hz ausgegeben*/

#include <avr/io.h>
#include <avr/interrupt.h>

volatile char count=0;
volatile char zeitvorgabe=32;    //32 => ca. 0,5 Hz bei Prozessorfreq. 4 
MHz (16 => ca. 1 Hz)
volatile char zeitvorgabe_halbe=0;

/*volatile Variablen können im Zyklischen-Programm und in
Interruptroutinen verwendet werden*/

int main (void) {    //Zyklische-Programm
  DDRB = 255;      //PortB als Ausgangsport definieren
  TIMSK = (1<<TOIE0);  //Beim Timeroverflow von Timer0 Interruptroutine 
starten
  TCNT0 = 0;      //Timer0 Register auf Null setzen
  TCCR0 = (1<<CS00) | (1<<CS02);  //Vorteiler einstellen (Prozesorfreq. 
durch 1024)
  sei();        //Globale Interrupt-Freigabe setzen
  zeitvorgabe_halbe=zeitvorgabe/2;  //Berechnung zur Zeitvorgaben
  while (1) {}      //Endlosschleife Zyklische Programm
  return 0;        //Rückgabewert der main-Funktion
}

ISR (TIMER0_OVF_vect) {  //InterruptServiceRoutine für Timeroverflow0
  if (count >= zeitvorgabe) {
   count = 0;
    return;
  }
  else if (count >= (zeitvorgabe_halbe)) {
    PORTB = 0;    //LEDs an (STK 500)
    count++;
    return;
  }
  else {
    PORTB = 255;  //LEDs aus (STK 500)
   count++;
    return;
  }
}

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.