Forum: Mikrocontroller und Digitale Elektronik AVR, 16-Bit Timer tickt nicht


von Hegy (Gast)


Lesenswert?

Hi,

viel rumprobiert, gemacht, getan, nix......dabei ist's nicht viel. Ein
16-Bit Timer soll ein/zwei LEDs zum blinken bewegen, nur versuchsweise.
Soweit ich weiß, wird die ISR nicht abgearbeitet.

Der kurze Code dazu, der nicht geht und ich nicht weiß warum nicht.
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/wdt.h>
5
// Quarz 4MHz, CTC-Modus, ATmega48
6
7
int main(void)
8
{
9
  //TCCR1B = (1<<WGM12) | (1<<CS10);             // Prescaler = 1
10
  //TCCR1B = (1<<WGM12) | (1<<CS11);             // Prescaler = 8
11
  TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10); // Prescaler = 64
12
  //TCCR1B = (1<<WGM12) | (1<<CS12);             // Prescaler = 256
13
  //TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10); // Prescaler = 1024
14
  
15
  OCR1A  = 2000;
16
  TIFR1  = 1<<ICF1;
17
  TIMSK1 = (1<<OCIE1A) | (1<<TOIE1);
18
  DDRB = 0x07; // Port PB0, PB1, PB2 Output
19
  PORTB = 0xFF; // Port PB0, PB1 aus
20
   
21
  wdt_disable();
22
23
  sei();
24
25
  while(1)
26
    PORTB = 0xFD; // eine LED an
27
28
  return 0;
29
}
30
31
ISR(SIG_OUTPUT_COMPARE1A)
32
{
33
  PORTB = ~PORTB;
34
}

totmüde
  Hegy

von ruepel (Gast)


Lesenswert?

Sieht eigentlich von der ISR - Initialisierung ganz ok aus.
Das TOIE1 ist ueberfluessig.

Es geht nicht, weil in Deiner while-Schleife in Zeile 25/26 der PortB
sofort nach dem Ausfuehren des Interrupts wieder mit 0xFD gesetzt
wird.
Wenn Du Zeile 26 weglaesst und hinter das while in Zeile 25 ein
Semikolon machst, koennte es evtl. gehen. Probiert habe ich's aber
nicht.

von Dominik T. (dom) Benutzerseite


Lesenswert?

Wenn du den Overflow - Interrupt durch setzen des Bits TOIE1 aktivierst,
solltest du auch eine dazugehörige Interrupt-Service-Routine
implementieren. Es könnte ja sein, dass der Timer oberhalb des
Compare-Wert startet, da du ihn ja nicht initialisierst. Dann will er
irgendwann in den Overflow Interrupt und landet im Nirvana.

von johnny.m (Gast)


Lesenswert?

Der landet nicht im Nirvana, sondern im Spurious Interrupt Handler, der
einen Reset verursacht...

Ansonsten hat ruepel recht. Wenn man PORTB ständig mit 0xFD beschreibt,
dann ist PORTB nur dann, wenn der Interrupt auftritt, für ein paar
wenige Taktzyklen geändert. Das ist zu wenig, um es optisch erfassen zu
können.

von Hegy (Gast)


Lesenswert?

So, ihr lieben (frei nach DJ Taucher),

ich hab's jetzt raus, so geht's. Den Fehler mit der
PORTB-Invertierung innerhalb der while-Schleife (Zeile 25/26) habe ich
gesehen, als dieses Posting gerade hier war, löschen kann ich es nicht
und auch nicht im nachhinein ändern. Aber der Tip mit der
Timer-Zählvariablen Initialisierung (TCNT1 = 0;) habe ich noch
nachgelegt und den Prescaler nochmal angepast, die Interruptfreigabe
durch TOIE1 rausgenommen und so läufts. Meßwerte unten drunter!

Ich packe es mal als Beispielcode hier hin, für den Fall, daß
irgendjemand in der Zukunft auch so'n Problem hat. Ich habe gesucht,
gesucht und nix gefunden :( .. und auf die Gefahr, daß es hier auch
wieder verschwindet, weil es ja evtl. doch in die Rubrik Codesammlung
gehört.
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
int main(void)
6
{
7
  // Timer Register
8
  TCNT1  = 0;  // Timer Startwert
9
  TCCR1B = (1<<WGM12) | (1<<CS11);  // Prescaler = 8
10
  OCR1A  = 5000; // Timer1 bis 5000 zählen lassen, dann Interrupt
11
  TIFR1  = 1<<ICF1;
12
  TIMSK1 = 1<<OCIE1A;
13
14
  // Port Register
15
  DDRB  = 0x07;  // Port PB0, PB1, PB2 Output
16
  PORTB = 0xFF;  // Port PB0....7 aus
17
18
  sei();
19
20
  PORTB = 0xFD;  // eine LED einschalten
21
  while(1)
22
    ;
23
24
  return 0;
25
}
26
27
28
ISR(SIG_OUTPUT_COMPARE1A)
29
{
30
  PORTB = ~PORTB;
31
}

Was passiert ist, daß eine LED an Port B im 50Hz-Takt blinkt. Ok, es
sind nicht exakt 50Hz, es sind (gemessen mit Keithley 2000 Multimeter)
49.99300 Hz (20,00281 ms Periodenzeit), mit einem 4MHz-Quarz an einem
ATmega48. So, feddich.

Danke an euch, endlich ist das Problem gelöst.

 - Hegy

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.