www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Warteschleife


Autor: Jens1993 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  while (flag = 0);

* das ist kein Vergleich sondern eine Zuweisung

* sieh dir den kleinen ; am Ende der Zeile an :-)

Autor: Jens1993 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?!?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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++

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie und wo hast Du die Variabeln "flag", "timer" und "counter" 
deklariert?

Autor: Jens1993 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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!

Autor: Jens1993 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine ziemliche 1:1 Umsetzung in C wäre
void warten()
{
  uint8_t merker = 36;
  uint8_t counter = 200;

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

  do
  {
    while( TCNT0 != counter )
      ;

    counter += 200;
    merker--;
  } while( merker != 0 );

  TCCR0 = 0;
  TCNT0 = 0;
}

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.