Forum: Mikrocontroller und Digitale Elektronik Warteschleife


von Jens1993 (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

1
  while (flag = 0);

* das ist kein Vergleich sondern eine Zuweisung

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

von Jens1993 (Gast)


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?!?

von Stefan E. (sternst)


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++

von Karl H. (kbuchegg)


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?

von Peter (Gast)


Lesenswert?

Wie und wo hast Du die Variabeln "flag", "timer" und "counter" 
deklariert?

von Jens1993 (Gast)


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.

von Karl H. (kbuchegg)


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.

von Peter (Gast)


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!

von Jens1993 (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

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.

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.