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.
1 | while (flag = 0); |
* das ist kein Vergleich sondern eine Zuweisung * sieh dir den kleinen ; am Ende der Zeile an :-)
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?
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.
>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!
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.