Forum: Mikrocontroller und Digitale Elektronik Timerproblem


von AVRTester (Gast)


Lesenswert?

Hallo,

ich sitze gerade vor nem seltsamen Problem mit einem Tiny24A.
Den übrigen Code habe ich schon entfernt und mich an das Problem 
herangetastet. Vielleicht hat ja jemand von Euch eine Erklärung.
Im Prinzip soll eine LED einfach nur blinken. Da zwischendurch noch was 
anderes gemacht wird, habe ich die Abfrage auf >500 gemacht, was aber 
die LED unregelmäßig blinken lässt. Schreibe ich == 500, funktioniert 
das Blinken bestens. Kann es sein, daß das Carry Bit in der Abfrage 
(einzigster Unterschied im Assembler) durch einen folgenden Interrupt 
irgendwie gelöscht wird?
Hier noch der Codeausschnitt:

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

volatile unsigned int counter;

int main(void)
{
  DDRD |= (1<<PD5);
  PORTD &= ~(1<<PD5);
  TCCR0 = (1<<WGM01) | (1<<CS02);
  OCR0 = 239;
  TIMSK |= (1<<OCIE0);
  sei();

  while(1)
  {
    if (counter > 500)
   {
    counter = 0x0000;
          PORTD ^= (1<<PD5);
    }
 }
}

ISR(TIMER0_COMP_vect)
{
  counter = counter + 10;
}


Danke schon mal für alle Hinweise - irgendwie seh ich's einfach nicht...

von AVRTester (Gast)


Lesenswert?

Nachtrag: der gezeigte Code wurde auf einem ATMEGA32 ausgeführt (nur um 
Missverständnisse zu vermeiden). Wenn ich den Interrupt vor dem 
Vergleich sperre und danach wieder freigebe, dann funktioniert es auch 
bestens. Muß also damit was zu tun haben.

von Rolf M. (rmagnus)


Lesenswert?

Counter ist 16 Bit breit, d.h. der Vergleich ist nicht atomar, muß also 
in zwei Schritten durchgeführt werden. Das gleiche gilt für die 
Zuweisung. Wenn genau zwischen den beiden Teilen der Operation der 
Interrupt ausgelöst wird, komt Mist raus. Die Lösung hast du ja schon 
selbst gefunden:

AVRTester schrieb:
> Wenn ich den Interrupt vor dem
> Vergleich sperre und danach wieder freigebe, dann funktioniert es auch
> bestens. Muß also damit was zu tun haben.

: Bearbeitet durch User
von AVRTester (Gast)


Lesenswert?

Alles klar. Ich mache jetzt das Rücksetzen und Vergleichen in der ISR 
und setze dann nur noch eine 8Bit Variable mit nem Wert. So ein 
Kleinigkeit hat dann solche Auswirkungen, so daß man noch im Assembler 
schauen muß. Vielen Dank auf jeden Fall für den Hinweis!

von Karl H. (kbuchegg)


Lesenswert?

AVRTester schrieb:
> Alles klar. Ich mache jetzt das Rücksetzen und Vergleichen in der ISR
> und setze dann nur noch eine 8Bit Variable mit nem Wert.

Anstatt so kompliziert, kannst du auch gleich in der ISR den Portpin 
umschalten.

Mann kann durchaus auch in einer ISR Dinge erledigen. Vor allen Dingen 
dann, wenn sie zeitlich einigermassen genau kommen sollen oder nicht 
unterbrochen werden dürfen. Man sollte es nur nicht übertreiben.

Mit einem
1
ISR(TIMER0_COMP_vect)
2
{
3
  counter = counter + 10;
4
5
  if( counter >= 500 ) {
6
    counter = 0;
7
    PORTD ^= (1<<PD5);
8
  }
9
}

begehst du höchstens den Fopas, dass kein Mensch weiss, was das 
umschalten am PD5 eigentlich bewirkt - da wäre eine bessere Bezeichnung 
angebracht. OK, man könnte noch kritisieren, dass man nicht um 10 
erhöhen muss, sondern nur um 1, was die 16 Bit Arithmetik einsparen 
würde und 1 Byte weniger SRAM Verbauch bedeutet und man könnte die 
Variable in der ISR 'static' machen. Aber vom Prinzip her ist diese 
Lösung in dieser konkreten Situation besser, als erst mal umständlich 
ein Jobflag Variable zu bemühen, in der Hoffnung, dass in der 
Hauptschleife so zeitnah darauf reagiert werden kann, so dass keinem die 
manchmal zeitweilige Verkürzung des Intervalls auffällt.

Diese LED hier blinkt solange die Interrupts aktiviert sind wirklich im 
angestrebten Takt. Egal was in der Hauptschleife passiert.

'ISR so kurz wie möglich' bedeutet NICHT, dass man gar nichts in einer 
ISR ereldigen darf. Es bedeutet nur, dass man dort keine Zeitfresser 
einbaut. Ob du einen Portpin umschaltest oder eine globale Variable auf 
1 setzt, schenkt sich im Zeitverbrauch nichts.

: Bearbeitet durch User
von AVRTester (Gast)


Lesenswert?

Danke für die Ideen, nur leider habe ich den Code total 
heruntergebrochen. In der Ursprungsschaltung ist leider die LED nicht 
direkt am ATTINY angeschlossen. Die LED hängt an einem FPGA, der mit dem 
Tiny über eine Art Pseudo SPI Interface kommuniziert (Tiny ist Master). 
Somit kann ich leider nicht alles in die ISR bringen, sondern muß die 
LED blinken lassen, wenn genug Zeit ist. Zusätzlich gibt es noch einen 
GPIO Interrupt, der in jedem Fall Vorrang hat. Ich habe nur für meine 
Problemfindung alles herausgenommen, damit mir die Hardware nicht 
dazwischenfunkt.

von Karl H. (kbuchegg)


Lesenswert?

AVRTester schrieb:

> Zusätzlich gibt es noch einen
> GPIO Interrupt, der in jedem Fall Vorrang hat.


Das ist allerdings ein Argument.

Software SPI alleine wäre für mich noch kein Grund, den nicht direkt in 
einer ISR zu erledigen.

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.