Warteschleife

Gast #1509902
Hallo Leute,
ich habe seither nur ein wenig Assembler programmiert. Will jetzt aber 
auf C umsteigen.
Ich versuche seit einer Weile eine Warteschleife von Assembler in C 
umzusetzen. Mit wenig Erfolg....
Bin im Forum schon auf die delay funktion gestoßen, möchte es aber erst 
mit meiner Variante probiern.

void warten()
{
  TCCR0 = ((1<<CS00)|(1<<CS02));
  while (flag = 0);
  {
    timer = TCNT0;
    if(timer == 255)
    {
      ++counter;
    }
    if(counter == 30)
    {
      flag = 1;
    }
  }
}
Ich rufe warten als Unterprogramm auf. Nachdem die Schleife abgearbeitet 
ist (falg = 1) soll wieder zurück zum Hauptprogramm gesprungen werden.
Ich benutze einen Atmega 8L 8PU. "timer" und "counter" sind jeweils als 
uint8_t deklariert.
Über Hinweise zu meinem Fehler würd ich mich freuen.
Gast
Hallo Karl Heinz,
danke für deine Antwort!

void warten()
{
  TCCR0 = ((1<<CS00)|(1<<CS02));
  while (flag == 0)
  {
    timer = TCNT0;
    if(timer == 255)
    {
      ++counter;
    }
    if(counter == 30)
    {
      flag = 1;
    }
  }
}

so wäre es dann wohl besser?!?
Jens1993 schrieb:

> so wäre es dann wohl besser?!?

In Bezug auf das eine Detail ja, insgesamt aber eher nein.
Du hast einen Prescaler von 1024, da wird der Timer mehrere 
Schleifendurchläufe lang 255 sein. Wahrscheinlich wird counter sogar 
schon beim ersten Mal Timer=255 bis auf 30 hochgehen.

Besser wäre folgendes Vorgehen:
  Warte auf Overflow-Flag
  Overflow-Flag zurücksetzen
  counter++
Dazu kommt:

Der Timer läuft weiter.
Auch nachdem die Funktion verlassen wurde.
Wird die Funktion das nächste mal aufgerufen, so wird zwar der Timer 
wieder eingeschaltet, was allerdings nichts bewirkt, den ein 
eingeschalteter Timer macht dann einfach .... nichts weiter. Er ist ja 
schon eingeschaltet.
Aber: Welchen Zählerstand hat dann der Timer?
Gut, wenn du 30 Overflow abzählst, ist das jetzt nicht so der große 
Fehler, wenn der Timer bei Eintritt in warten() schon einen Zählerstand 
von 200 auf dem Buckel hat. Aber Fehler bleibt Fehler.
Und warum sind eigentlich 'flag' und 'counter' keine funktionslokale 
Variablen? Und wer setzt 'flag' und 'counter' wieder auf 0, damit bei 
einem erneuten Aufruf von warten() die Schleife überhaupt einmal 
abgearbeitet wird?
Gast
Danke für eure Hinweise!
Komme aber igendwie doch nich so recht vorran...
Hier noch ein weiterer Versuch:

void warten()
{

  uint8_t counter = 0;
  uint8_t timer = 0;
  uint8_t flag = 0;

  TCCR0 = ((1<<CS00)|(1<<CS02));  //Timer starten
  TIMSK = (1<<TOIE0);             //Overflow Flag enable

  while (flag == 0)
  {
    timer = TCNT0;

    if(TOV0 == 1)                  //Abfragen auf Overflow
    {
      TIFR = (1<<TOV0);            //Overflow Flag zurücksetzen
      ++counter;
    }
    if(counter == 10)
    {
      flag = 1;
    }
  }
  TCCR0 = ((0<<CS00)|(0<<CS02));  //Timer stoppen
  timer = 0;                      //timer rücksetzen
  counter = 0;                    //counter rücksetzen
}

Kann ich "TOV0" überhaupt so auf "1" abfragen? Oder muss ich zur 
Auswertung eine Interrupt Routine benutzen?
Danke schon mal.
Jens1993 schrieb:
> Danke für eure Hinweise!
> Komme aber igendwie doch nich so recht vorran...
> Hier noch ein weiterer Versuch:
>
> void warten()
> {
>
>   uint8_t counter = 0;
>   uint8_t timer = 0;
>   uint8_t flag = 0;
>
>   TCCR0 = ((1<<CS00)|(1<<CS02));  //Timer starten
>   TIMSK = (1<<TOIE0);             //Overflow Flag enable

Warum aktivierst du die Ausführung einer Interrupt Service Routine beim 
Overflow. Du hast keine ISR, die sich darum kümmern würde! Das Overflow 
Flag musst du nicht enablen. Das dir ein Overflow vom Timer mit dem Flag 
angezeigt wird, kannst du gar nicht disablen. Das passiert sowieso 
immer!

>
>   while (flag == 0)
>   {
>     timer = TCNT0;
>
>     if(TOV0 == 1)                  //Abfragen auf Overflow

TOV0 ist ein Bit in einem Register.
Das frägst du genauso ab, wie jedes andere Bit auch.

>     {
>       TIFR = (1<<TOV0);            //Overflow Flag zurücksetzen

Siehst du.
Hier greifst du richtig auf das TOV0 Bit im TIFR Register zu.

>       ++counter;
>     }
>     if(counter == 10)
>     {
>       flag = 1;
>     }
>   }
>   TCCR0 = ((0<<CS00)|(0<<CS02));  //Timer stoppen

Nö.
So kann man keine Bits löschen.
Eine 0 kannst du nach links schieben, sooft du willst. Die bleibt immer 
eine 0.

    TCCR0 &= ~((1<<CS00)|(1<<CS02));  //Timer stoppen


>   timer = 0;                      //timer rücksetzen
>   counter = 0;                    //counter rücksetzen

Da das jetzt lokale Variablen sind, kannst du dir das sparen.
Nach Funktionsende gibt es diese Variablen nicht mehr und beim nächsten 
Funktionsaufruf werden sie sowieso neu erzeugt.

> }
>
> Kann ich "TOV0" überhaupt so auf "1" abfragen? Oder muss ich zur
> Auswertung eine Interrupt Routine benutzen?

Nein, musst du nicht.
Gast
>Ich versuche seit einer Weile eine Warteschleife von Assembler in C
>umzusetzen. Mit wenig Erfolg....

Wie sah den die Warteschleife in Assembler aus? Die sollte eigentlich 
1:1 in C umsetzbar sein!
Gast
Ich seh schon, ich komm da momentan irgendwie nicht klar...
hier die Warteschleife in Assembler

warten:
  ldi    temp,0b00000101
  out    TCCR0,temp
  ldi    merker,36
  ldi    counter,200

warten_1:

  in    temp,TCNT0
  cp    temp,counter
  brne          warten_1

  subi          counter, -200
  dec    merker
  brne          warten_1

  clr    temp
  out    TCCR0,temp
  out    TCNT0,temp

Danke.
Eine ziemliche 1:1 Umsetzung in C wäre
1
void warten()
2
{
3
  uint8_t merker = 36;
4
  uint8_t counter = 200;
5

6
  TCCR0 = ( 1<<CS02 ) | ( 1<<CS00 );
7

8
  do
9
  {
10
    while( TCNT0 != counter )
11
      ;
12

13
    counter += 200;
14
    merker--;
15
  } while( merker != 0 );
16

17
  TCCR0 = 0;
18
  TCNT0 = 0;
19
}

Du solltest aber trotzdem deinen ursprünglichen Ansatz mit dem Overflow 
Flag noch weiter verfolgen. Du kannst dabei nur lernen.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.