Forum: Mikrocontroller und Digitale Elektronik Timer0 Overflow Flag ohne Interrupt auslesen


von Remo G. (scar)


Lesenswert?

Hallo Leute,
bin neu im Forum und ich finde es eine super Sache!

Ich arbeite mit einem ATtiny2313 und versuche das TOV0 ohne Interrupt 
auszulesen. Der Timer0 arbeitet im normal Mode.

Hier mein Code:
if((TIFR&(1<<TOV0))==on)
    {
    TIFR=TIFR&0x01;
    PORTB^=(1<<PB0);
    }

Leider passiert nichts:-(
Wenn ich es aber mit der Interruptroutine versuche funktioniert es.

Kann mir jemand sagen wo der Fehler ist?

von Felix P. (fixxl)


Lesenswert?

1
if((TIFR&(1<<TOV0))==on)
Wie genau hast du "on" definiert? Das TOV0-Bit sitzt an 2. Stelle, d.h. 
wenn es gesetzt ist, ergibt die Abfrage für die if-Bedingung den Wert 2, 
wenn es nicht gesetzt ist, kommt 0 heraus.
1
TIFR=TIFR&0x01;
Um das Flag zu löschen, musst du eine 1 ins entsprechende Bit schreiben 
- und zwar mit der Anweisung TIFR=1<<TOV0.

von chris (Gast)


Lesenswert?

Hi,

das Problem dürfte wohl sein, dass du auf "== on" abfragst.
Je nachdem, wie du "on" definiert hast, wird das evtl. nie wahr sein.
(TIFR & (1<<TOV0)) ist nämlich 0, wenn TOV0 gelöscht ist, und 2, wenn 
TOV0 gesetzt ist ( weil TOV0 Bit1 ist, also sieht das Ergebnis so aus 
0b00000010 bzw 0x02)
Wenn du jetzt "on" als 1 definierst, kann das natürlich nie stimmen, 
denn 1 != 2

Lass das "on" daher weg und frag einfach auf "ungleich 0" ab.

also:
if (TIFR&(1<<TOV0))
    {
    mach_was();
    }

außerdem:
damit
TIFR=TIFR&0x01;
löschst du OCF0A: Output Compare Flag 0 A (weil das Bit0 ist) falls es 
vorher gesetzt war.

Ich nehme an, du willst eigentlich TOV0 löschen

Das Overflow Flag löschst du so:

TIFR = (1<<TOV0);

Da es ein Interrupt Flag ist, muss es durch schreiben einer 1 gelöscht 
werden (zumindest beim Atmega8 usw., nehme an, dass das beim Tiny2313 
genauso ist)

von chris (Gast)


Lesenswert?

da war ich wohl zu langsam^^

von Remo G. (scar)


Lesenswert?

Hi,
Manchmal sieht man den Wald voller Bäume nicht;-)

Genau das sind die Fehler.

Ihr seid super, besten Dank!

von Harry (Gast)


Lesenswert?

Hallo....ich hab das selbe Problem...nur dass ich das Flag genau so 
abfrage wie oben beschrieben ....if (TIFR&(1<<TOV0))...das funktioniert 
nicht...wenn ich dagegen genau so das ICF des Timer1 zum einfangen eines 
Signals am IC-Pin abfrage läuft alles super.

Wenn ich mit der Interupt-Routine arbeite funktioniert es. Das heißt das 
Flag wird tatsächlich gesetzt, sonst würde ja auch kein Interupt 
ausgelöst.

ich steh da schon ziemlich an...

von c-hater (Gast)


Lesenswert?

Harry schrieb:

> Wenn ich mit der Interupt-Routine arbeite funktioniert es. Das heißt das
> Flag wird tatsächlich gesetzt, sonst würde ja auch kein Interupt
> ausgelöst.

Du versuchst wahrscheinlich beides gleichzeitig zu tun. Das geht nicht, 
weil  der ausgeführte Interrupt automatisch das Flag zurücksetzt. Dein 
Polling in main() sieht also niemals ein gesetztes Flag...

Sprich: du musst dich entscheiden: Polling oder Interrupt. Oder du musst 
ein Hilfsflag im SRAM benutzen, welches du in der ISR setzt und in 
main() pollst.

von Harry (Gast)


Lesenswert?

hatte ich ursprünglich auch geglaubt. Aber das ist nicht so. Schließlich 
hab ich eine eigenes kleines Testprogramm geschrieben, um der Sache auf 
den Grund zu gehen. Mit Interrupt klappt es. Ohne Interrupt gehts nicht. 
Dann dachte ich, dass eventuell der Timer0 einen Fehler hat. Also hab 
ich auf den Timer1 gewechselt -  mit dem selben Ergebnis. Dann ganz 
genau kontrolliert ob der Timer im normalen Modus läuft - aber das Flag 
wird nicht erkannt.
Bin ziemlich ratlos.

von Marco (Gast)


Lesenswert?

Dann zeig doch mal den ganzen Code her.

von Harry (Gast)


Lesenswert?

uint8_t testovf (void)    / Testprogramm  Timerüberläufen
{
  uint16_t i;
  i = 0;        //allgemeine Zählervariable


  TCCR0 |= (1<<CS00) ;
  TCCR0 &= ~((1<<CS10) | (1<<CS20)); // Timer0 im CPU Takt gestartet

while(1)
{


  while (!(TIFR & (TOV0)))  // Schleife bis das overflowFlag erkannt
  {
  }
    i++;      // Zähler wird hochgezählt
    TIFR |= (1<<TOV0);  // Zurücksetzen des ÜberlaufFlags



  if (i > 60000)      // nach ca 0,7sek
  {
    if (PIND & (1<<PD3))  // Abrage von D3 (LED GRÜN)
    {
      PORTD &= ~(1<<PD3); // Toggeln des Ausganges LED
    }
    else
    {
      PORTD |= (1<<PD3);
    }

    i = 0;      //Zurücksetzen des zählers
  }


}



return(1);
}

von Thomas E. (thomase)


Lesenswert?

Harry schrieb:
> while (!(TIFR & (TOV0)))

while (!(TIFR & (1 << TOV0))

von Marco (Gast)


Lesenswert?

Du schreibst die Abfrage sehe wie iben aus, also so
if (TIFR&(1<<TOV0))

Ich lese aber folgendes
while (!(TIFR & (TOV0)))

Musste meiner Meinung nach so aussehen
while (!(TIFR & (1<<TOV0)))

von Harry (Gast)


Lesenswert?

Ist eine Warteschleife die so lange durchlaufen wird, bis das Flag 
gesetzt wird. Statt dieser Schleife kann ich auch die if-Abfrage 
einfügen. Dann werden alle restlichen Abfragen halt auch ständig 
abgefragt. Egal...es funktioniert trotzdem nicht. Das gesetzte Flag wird 
nicht erkannt

von Falk B. (falk)


Lesenswert?

Harry schrieb:
> uint8_t testovf (void)    / Testprogramm  Timerüberläufen
> {
>   uint16_t i;
>   i = 0;        //allgemeine Zählervariable
>
>   TCCR0 |= (1<<CS00) ;
>   TCCR0 &= ~((1<<CS10) | (1<<CS20)); // Timer0 im CPU Takt gestartet

Was soll der Käse? Schreibb gescheite Werte DIREKT in das Register. 
SO!!!
1
TCCR0 = (1<<CS00);  // Prescaler 1 und los

> while(1)
> {
>
>   while (!(TIFR & (TOV0)))  // Schleife bis das overflowFlag erkannt

FALSCH! Siehe Bitmanipulation! Eher so
1
while (!(TIFR & (1<<TOV0)) )

>   {
>   }
>     i++;      // Zähler wird hochgezählt
>     TIFR |= (1<<TOV0);  // Zurücksetzen des ÜberlaufFlags

Auch falsch!  Die Flags werden durch ein Schreiben einer EINZIGEN '1' 
gelöscht, NICHT durch eine Oder-Verknüpfung mit dem aktuellen Inhalt.
1
TIFR = (1<<TOV0);

Denn mit der ODER-Verknüpfung kann man im Zweifelsfall andere, aktive 
IRQ-Flags löschen. Das mag HIER keine Rolle spielen, allgemein aber 
schon! Solche Fehler sind "nett", denn sie treten in komplexeren 
Programmen sehr sporadisch auf und man wird bei der Fehlersuche 
wahnsinnig!

>
>   if (i > 60000)      // nach ca 0,7sek
>   {
>     if (PIND & (1<<PD3))  // Abrage von D3 (LED GRÜN)
>     {
>       PORTD &= ~(1<<PD3); // Toggeln des Ausganges LED
>     }
>     else
>     {
>       PORTD |= (1<<PD3);
>     }
>
>     i = 0;      //Zurücksetzen des zählers
>   }

Viel zu aufwändig. Das geht deutlich einfacher, XOR ist dein Freund, 
siehe Bitmanipulation.
1
if (i > 60000)        // nach ca 0,7sek
2
{
3
  PORTD ^= (1<<PD3);  // Toggeln des Ausganges LED
4
  i = 0;              // Zurücksetzen des zählers
5
}

von Harry (Gast)


Lesenswert?

ohh...alles zurück....grad erkannt. sorry

von Harry (Gast)


Lesenswert?

...und wieder dazugelernt, dass ich in Zukunft keinen Code mehr poste

von Falk B. (falk)


Lesenswert?

Harry schrieb:
> ...und wieder dazugelernt, dass ich in Zukunft keinen Code mehr poste

Deine Logik muss man nicht verstehen, oder?

https://de.wikipedia.org/wiki/Generation_Snowflake

von Marco (Gast)


Lesenswert?

Hättest du denn die Fehler ohne das Posten des Codes selber 
herausgefunden ?

von Peter D. (peda)


Lesenswert?

Harry schrieb:
> ohh...alles zurück....grad erkannt. sorry

Harry schrieb:
> ...und wieder dazugelernt, dass ich in Zukunft keinen Code mehr poste

Erst nen uralten Thread kapern und dann nichts zur Lösung zu sagen. 
Bitte noch mehr unnütze Posts.

Früher gab es mal die Sitte, die Lösung nochmal zusammen zu fassen und 
sich für die Hilfe zu bedanken.

von Karl B. (gustav)


Angehängte Dateien:

Lesenswert?

Hi,
glaube, in "asm" ist man bei sowas näher an der "Maschine" dran.
Die Hochsprachen bringen - für mich jedenfalls - in dem Zusammenhang
IMHO keine wesentlichen Vorteile.
Jedenfalls habe ich 'mal ein Progrämmchen geschrieben, mit dem
der Zustand der seriellen Schnittstelle überprüft werden sollte.
Dabei werden dann Nullen bzw. Einsen auf dem 2 x 16 LCD angezeigt.
Der Zustand der UART-Register.

Also die wichtigsten Zeilen sind,
evtl. erst Interrupts sperren mit "cli"
Statusregister retten mit "in"
Kopie des jeweiligen Registers auf "temp" mit "in"
Dann Ausgaberoutinen mit Umrechnungsroutinen. etc.
und Statusregister wiederherstellen mit "out"
Interrupts wieder erlauben mit "sei"
etc. etc.

Prinzipiell könnte man auch die anderen Register auf die Art auslesen,
also auch das TimerOverflow-Flag.
Wichtig ist nur, dass man unter Umständen wie bei "atomic action" 
verfährt, um das eigentliche Programm nicht zu stören.

Viel Spaß

ciao
gustav

von Maxim B. (max182)


Lesenswert?

c-hater schrieb:
> Oder du musst
> ein Hilfsflag im SRAM benutzen, welches du in der ISR setzt und in
> main() pollst.

Hallo,
ich finde das auch als eine bessere Lösung.
AVR haben GPIOR0-2, dabei sitzt GPIOR0 bei manchen AVR so, daß man den 
mit sbi-cbi erreichen kann. So kann ISR sehr kurz sein:
Z.B. so:
1
#define FLAGG      GPIOR0
2
#define FL_ISR2    7  // ISR 2 
3
4
ISR(INT2_vect,ISR_NAKED){
5
  FLAGG |= (1<<FL_ISR2);
6
  reti();
7
}
Compiler macht daraus:
1
sbi  0x1e, 7
2
reti

Danach kann man mit FL_ISR2 in Hauptprogramm alles Mögliche machen, ISR 
und Hauptprogramm stören einander nicht.

von Karl B. (gustav)


Angehängte Dateien:

Lesenswert?

Hi,
Ergänzung:

http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2543-AVR-ATtiny2313_Datasheet.pdf

Seite 85.
Auslesen funktioniert dann entsprechend.
Seite 86.

ciao
gustav

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Karl B. schrieb:

>Seite_85.png
>8,79 KB, 4 Downloads

Selten so einen schlechten Screenshot gesehen! Wie schafft man das? 
Vorher ein Dutzend mal faxen?

von Karl B. (gustav)


Lesenswert?

Falk B. schrieb:
> Selten so einen schlechten Screenshot gesehen! Wie schafft man das?
> Vorher ein Dutzend mal faxen?

Hi,
sollte das Auffinden der entsprechenden Grafik auf dem Link erleichtern. 
Mehr nicht.
Dazu reicht es allemal.

ciao
gustav

von Falk B. (falk)


Lesenswert?

Karl B. schrieb:
> Hi,
> sollte das Auffinden der entsprechenden Grafik auf dem Link erleichtern.
> Mehr nicht.
> Dazu reicht es allemal.

Dazu reicht ein Link auf Datenblatt bzw. eine Angabe der Seite!

www.dummeausrede.de

von Thomas E. (thomase)


Lesenswert?

Maxim B. schrieb:
> Danach kann man mit FL_ISR2 in Hauptprogramm alles Mögliche machen,

Kann man mit dem Interrrupt-Flag auch.

> ISR und Hauptprogramm stören einander nicht.

Keine ISR und Hauptprogramm auch nicht.

von Maxim B. (max182)


Lesenswert?

Thomas E. schrieb:
> Kann man mit dem Interrrupt-Flag auch.

Mit ISR-Flag muß man vorsichtiger umgehen, um andere Flags nicht zu 
berühren. Hier aber besteht solche Gefahr nicht.

Man kann auch eine andere Variante benutzen: statt Flag einen Zähler. In 
ISR incrementiert, in Hauptprogramm auf 0 geprüft und wenn nicht, 
decrementiert und entsprechende Handlungen vorgenommen.
Vorteil von dieser Variante: wenn diese Handlungen ab und zu, von 
laufenden Bedingungen abhängig, länger dauern als die Zeit zwischen ISR, 
gehen sie nicht verloren. Z.B. wenn gleichzeitig etwas kommt, was jede 1 
ms gemacht wird und was jede 250 ms. Natürlich sollten die Handlungen im 
Durchschnitt statistisch kürzer sein als die Zeit zwischen ISR.
Nachteil: kein ISR NAKED mehr möglich, da Register benutzt werden.

Wenn Zähler mehr als 1 byte hat, sollte man ISR_BLOCK benutzen.

Noch eine noch bessere Variante: Aufgabenreihe, evtl. zusammen mit 
Timerdienst. ISR stellt die Aufgabe auf die Reihe, dann wird die Aufgabe 
(irgendwann, wenn CPU die Zeit hat) gemacht.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Maxim B. schrieb:
> Mit ISR-Flag muß man vorsichtiger umgehen, um andere Flags nicht zu
> berühren. Hier aber besteht solche Gefahr nicht.

Ja ne, is klar.

von Karl B. (gustav)


Lesenswert?

Falk B. schrieb:
> Dazu reicht ein Link auf Datenblatt bzw. eine Angabe der Seite!

Hi,
steht doch da:
Karl B. schrieb:
> Hi,
> Ergänzung:
>
> 
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2543-AVR-ATtiny2313_Datasheet.pdf
>
> Seite 85.
> Auslesen funktioniert dann entsprechend.
> Seite 86.

Doppelt gemoppelt hält besser. ;-)

ciao
gustav

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.