Forum: Mikrocontroller und Digitale Elektronik Rückwärts zählen in C, von n bis 0 in n'er schritten.


von Hercules (hercules)


Lesenswert?

Hallöchen Zusammen,

ich programmieren grade meinen AtTiny85 und stelle mich selber bisschen 
auf die Probe. Ich bin Anfänger und versuche durch Praktische Übung zu 
lernen. Nun, ich habe eine kleine LED Schaltung aufgebaut die mithilfe 
des Tiny beleuchtet werden sollen. Dabei sind alle 5 Ports belegt und 
übernehmen eine bestimmte reihe. Einige schöne Sachen konnte ich bisher 
damit anstellen, doch bei meiner nächsten Idee hapert es ein bisschen. 
Die LED´s sollen nach jeder Runde immer schneller leuchten und wieder 
ausgehen. Also: Die LED`s fangen an eine Sekunden lang zu leuchten. 
Danach gehen sie aus und sofort danach leuchtet die nächste reihe. Auch 
diese leuchtet eine Sekunde lang auf und geht danach wieder aus. Das 
geschieht mit allen 5 Reihen. Dann ist eine ganze Periode zu ende. Bei 
dem nächsten Start der Periode sollen die LED`s nicht eine Sekunde lang 
leuchten sondern z.b nur 800ms. Das ganze geht dann so lange weiter bis 
man bei etwas 1ms ist. Mit der Zeit wird es dann so scheinen als würden 
die LED´s durchgehend leuchten, obwohl das ja eigentlich nicht der Fall 
ist, sie gehen nur so extrem schnell an und aus das wir das nicht 
merken. Nun das Problem ist das runterzählen. Das kriege ich noch nicht 
gebacken. Meinen Code habe ich mit der for schleife so verfasst dass es 
bei einer Sekunde anfängt, und in 100ms schritten immer weiter 
runterläuft.
1
# define F_CPU 1000000UL
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
6
int main (void)
7
{
8
  DDRB |=(1 << PB0);
9
  DDRB |=(1 << PB1);
10
  DDRB |=(1 << PB2);
11
  DDRB |=(1 << PB3);
12
  DDRB |=(1 << PB4);
13
  DDRB |=(1 << PB5);
14
  
15
  for (int i=1000; i>=1; i-100)
16
  {
17
    PORTB |= (1 << PB0);
18
    _delay_ms(i);
19
    PORTB &=~ (1 << PB0);
20
    
21
    PORTB |= (1 << PB2);
22
    _delay_ms(i);
23
    PORTB &=~ (1 << PB2);
24
    
25
    PORTB |= (1 << PB4);
26
    _delay_ms(i);
27
    PORTB &=~ (1 << PB4);
28
    
29
    PORTB |= (1 << PB1);
30
    _delay_ms(i);
31
    PORTB &=~ (1 << PB1);
32
    
33
    PORTB |= (1 << PB3);
34
    _delay_ms(i);
35
    PORTB &=~ (1 << PB3);
36
    
37
    PORTB |= (1 << PB5);
38
    _delay_ms(i);
39
    PORTB &=~ (1 << PB5);
40
  }
41
  return 1;
42
}

: Verschoben durch Moderator
von devzero (Gast)


Lesenswert?

Deine for Loop ist falsch.
Du veraenderst das i nicht.

for (int i=1000; i>=1; i-100)

Du musst den Wert wieder zuweisen, also z.B.

for (int i=1000; i>=1; i=i-100) oder for (int i=1000; i>=1; i-=100)

von Mario M. (thelonging)


Lesenswert?

for (int i=1000; i>=1; i=i-100)

von Werner P. (werner4096)


Lesenswert?

Hercules H. schrieb:
> for (int i=1000; i>=1; i-100)

nicht i-100 sondern i-=100

Hercules H. schrieb:
> _delay_ms(i);

das geht nicht. _delay_ms geht nicht mit variablen. Dafür eine Funktion 
schreiben und aufrufen.
1
void my_delay_ms(int counter)
2
{
3
  while(counter) {
4
    _delay_ms(1);
5
    counter--;
6
  }
7
}

von lambda (Gast)


Lesenswert?

Als letzten Teil im for-Statement willst du eine Anweisung die nach 
jeden Schleifendurchlauf ausgeführt wird. Das ist üblicherweise eine 
Zuweisung an die Zählvariable. Also in deinem Fall
i = i - 100
Sonst bleibt i einfach immer gleich.

von Michael D. (nospam2000)


Lesenswert?

Hercules H. schrieb:
>   for (int i=1000; i>=1; i-100)

Da fehlt ein "=" :
1
for (int16_t i=1000; i>=1; i -= 100)

oder ausführlicher:
1
for (int16_t i=1000; i>=1; i = i - 100)

anstatt "int" würde ich immer explizit die Typen mit der Längenangabe 
nutzen wie z.B. "int16_t2, dann weiß man immer gleich was wirklich 
gemeint ist.

  Michael

von quotendepp (Gast)


Lesenswert?

schreib dir mal auf (so mit graphit und totem baum) welche werte i 
deiner meinung nach so annimmt.
danach schaust du dir die operatoren an, die in der for schleife 
verwendet werden und was in deinem code passiert.

tipp: du kannst den schleifenkopf auch in einen c-programm für den pc 
verwenden und auf der konsole einfach die werte für i ausgeben lassen

von devzero (Gast)


Lesenswert?

Werner P. schrieb:
> das geht nicht. _delay_ms geht nicht mit variablen. Dafür eine Funktion
> schreiben und aufrufen.

Das erklaer mal, warum das nicht gehen soll.

von Werner P. (werner4096)


Lesenswert?

devzero schrieb:
> Werner P. schrieb:
>> das geht nicht. _delay_ms geht nicht mit variablen. Dafür eine Funktion
>> schreiben und aufrufen.
>
> Das erklaer mal, warum das nicht gehen soll.

ok. dachte immer das müsste eine Konstante sein. Kann mich auch irren.

Edit: wird hier z.B. auch so dargelegt.

[[Beitrag "Variable übergeben in #include <avr/delay.h>"]]

: Bearbeitet durch User
von Stefan S. (chiefeinherjar)


Lesenswert?

devzero schrieb:
> Werner P. schrieb:
>> das geht nicht. _delay_ms geht nicht mit variablen. Dafür eine Funktion
>> schreiben und aufrufen.
>
> Das erklaer mal, warum das nicht gehen soll.

Es ist ein Makro und wird beim Kompilieren berechnet und nicht zur 
Laufzeit. Daher müssen alle Parameter schon beim Compilieren fest 
stehen.

von Hercules (hercules)


Lesenswert?

Die Antowrten kamen super schnell hintereinander, und alle mit der 
selben Antwort :0. Da muss ich wohl noch bisschen was lernen :D. Danke!!

von Wer (Gast)


Lesenswert?

devzero schrieb:
> Das erklaer mal, warum das nicht gehen soll.

Was hat _delay_ms() nur an sich, dass diese Frage alle paar Tage wieder 
im Forum auftaucht... Google halt. Wurde ja oft genug beantwortet hier.

von Hercules (hercules)


Angehängte Dateien:

Lesenswert?

Also ich habe jetzt probiert die Antworten als Lösungsansatz zu 
verwenden, allerdings kommt nur eine Fehlermeldung. Arbeite übrigens mit 
Atmel Studio7. Von der Fehlermeldung habe ich ein Screenshot gemacht. 
Wisst ihr vielleicht was das Problem hierbei ist? Zuvor war die Meldung 
nicht da, hat alles funktioniert, bis ich dann... i-100) mit... i=i-100) 
ersetzt habe. :/

von Mario M. (thelonging)


Lesenswert?

Hercules H. schrieb:
> Wisst ihr vielleicht was das Problem hierbei ist?

Siehe oben.

von Wer (Gast)


Lesenswert?

Hercules H. schrieb:
> Wisst ihr vielleicht was das Problem hierbei ist?

Lies doch wenigstens die Antworten, wenn du schon fragst. So viele sinds 
nicht.

von Hercules (hercules)


Lesenswert?

Ich bin, wie bereits Anfangs erwähnt, Anfänger in diesem Gebiet. Von 
einem Anfänger zu erwarte dass er versteht was bei einer Error Ausgabe 
gemeint ist, und im besten Fall auch noch weiß was zu tun ist, ist ja 
wohl absurd. Einige Antworten zu der Hauptfrage kann ich weder richtig 
zuordnen noch verstehen. Entschuldigt mein Interesse und mein Streben 
nach einer Lösung...

von Wer (Gast)


Lesenswert?

Hercules H. schrieb:
> Von einem Anfänger zu erwarte dass er versteht was bei einer Error
> Ausgabe gemeint ist, und im besten Fall auch noch weiß was zu tun ist,
> ist ja wohl absurd

Hat auch keiner verlangt. Nur die Antworten in diesem Thread zu lesen.

von Dirk B. (dirkb2)


Lesenswert?


von Harry L. (mysth)


Lesenswert?

for (i=1000; i; i-=100)

von Werner P. (werner4096)


Lesenswert?

Harry L. schrieb:
> for (i=1000; i; i-=100)

jetzt bring ihn nicht komplett durcheinander. Außerdem ist das nicht 
sein Problem.

von Georg M. (g_m)


Lesenswert?

Hercules H. schrieb:
> Ich bin, wie bereits Anfangs erwähnt, Anfänger in diesem Gebiet. Von
> einem Anfänger zu erwarte dass er versteht was bei einer Error Ausgabe
> gemeint ist, und im besten Fall auch noch weiß was zu tun ist, ist ja
> wohl absurd. Einige Antworten zu der Hauptfrage kann ich weder richtig
> zuordnen noch verstehen. Entschuldigt mein Interesse und mein Streben
> nach einer Lösung...

_delay_ms() ist kein Arduino delay(), und im Unterschied zu Arduino 
funktioniert nur mit Zahlen und nicht mit Buchstaben.

von Zeno (Gast)


Lesenswert?

lambda schrieb:
> Als letzten Teil im for-Statement willst du eine Anweisung die nach
> jeden Schleifendurchlauf ausgeführt wird. Das ist üblicherweise eine
> Zuweisung an die Zählvariable. Also in deinem Fall
> i = i - 100
> Sonst bleibt i einfach immer gleich.

Nöö will er nicht, das macht die for-Schleife ganz allein. Was meinst Du 
wozu i-=100 (an Stelle des falschen i-100) gut ist? Wenn er das so macht 
wie Du schreibst dekrementiert er in jedem Durchlauf um 200.

von Werner P. (werner4096)


Lesenswert?

Zeno schrieb:
> lambda schrieb:
>> Als letzten Teil im for-Statement willst du eine Anweisung die nach
>> jeden Schleifendurchlauf ausgeführt wird. Das ist üblicherweise eine
>> Zuweisung an die Zählvariable. Also in deinem Fall
>> i = i - 100
>> Sonst bleibt i einfach immer gleich.
>
> Nöö will er nicht, das macht die for-Schleife ganz allein. Was meinst Du
> wozu i-=100 (an Stelle des falschen i-100) gut ist? Wenn er das so macht
> wie Du schreibst dekrementiert er in jedem Durchlauf um 200.

das mit i = i - 100 ist doch nicht falsch. Zur Sicherheit hab ich das 
mal getestet. Warum sollte das auch um 200 dekrementieren?
1
for (int i = 1000; i > 0; i = i - 100) {
2
  console_printf("i: %i\r\n",i);
3
}

i: 1000
i: 900
i: 800
i: 700
i: 600
i: 500
i: 400
i: 300
i: 200
i: 100

: Bearbeitet durch User
von G. H. (schufti)


Lesenswert?

@zeno: lambda schrieb
"im letzten Teil des for-statement"
nicht
"im letzten Teil der for-Schleife"

allerdings ist die Frage "..von n bis 0 in n*er schritten" wohl unnötig 
kompliziert mit "for" gelöst, da kann man auch gut den einen Durchlauf 
ohne Schleife als Klammer ausprogrammieren.
Oder wie oft könnt ihr n von n abziehen bis es 0 ergibt?

: Bearbeitet durch User
von Zeno (Gast)


Lesenswert?

G. H. schrieb:
> @zeno: lambda schrieb
> "im letzten Teil des for-statement"
> nicht
> "im letzten Teil der for-Schleife"
Hast recht, da habe ich aus dem Statement irgendwie eine Schleife 
gemacht. Sorry! Hab jetzt gerade nochmal Lambda's Post gelesen, alles 
korrekt wie er es geschrieben hat - war mein Fehler. Ist halt immer 
wieder das Gleiche, wer lesen kann ... .

G. H. schrieb:
> allerdings ist die Frage "..von n bis 0 in n*er schritten" wohl unnötig
> kompliziert mit "for" gelöst, da kann man auch gut den einen Durchlauf
> ohne Schleife als Klammer ausprogrammieren.
Wie willst Du eine mehrfache Wiederholung ohne Schleife machen?
Man könnte es auch mit while lösen, das ist aber auch eine Schleife.
Es ginge auch mit goto, aber das ist ja böse.

von Dirk B. (dirkb2)


Lesenswert?

Zeno schrieb:
> Es ginge auch mit goto, aber das ist ja böse.

Das wäre auch eine Schleife.

von Hercules (hercules)


Lesenswert?

Also ich habe mir den Tipp von Werner P. zu herzen genommen und 
folgendes in mein Programm Eingebaut, aber irgendwie klappt es trotzdem 
nicht. Davon mal ganz abgesehen das ich gar nicht verstehe was da steht. 
und warum ...i=i-100) mein Problem plötzlich löst habe ich auch nicht 
ganz gerafft. Hatte vorher ja nur ...i-100).
1
void my_delay_ms(int counter)
2
{
3
  while(counter) {
4
    _delay_ms(1);
5
    counter--;
6
  }
7
}

: Bearbeitet durch User
von Wer (Gast)


Lesenswert?

Hercules H. schrieb:
> Davon mal ganz abgesehen das ich gar nicht verstehe was da steht. und
> warum ...i=i-100) mein Problem plötzlich löst habe ich auch nicht ganz
> gerafft. Hatte vorher ja nur ...i-100).

Du hast eine Schleife gebaut, die läuft, solange i>=1 ist.
Zu Anfang ist i = 1000.
Du änderst i niemals wieder.

Wann denkst du hört die Schleife auf?

von Hercules (hercules)


Lesenswert?

Sie hört nie auf, das war mir spätestens dann klar als mein ...i-100) 
durch ...i=i-100) verbessert wurde. Ich wusste zuvor nicht das der Wert 
bei jeden Neuanfang sich dadurch ändert. Meine Idee am Anfang war es den 
aktuellen Wert irgenwie zwischen zu speichern, und beim neu anfangen 
dieser Wert mit -100ms anfängt. Was ich nicht so ganz verstehe ich 
folgender Punkt: Die schleife fängt bei 1000ms an. Beim nächsten Lauf 
zieht die Schleife 100ms ab. Und das bei jedem Lauf bis i>=1 ist. Aber 
wie weiß die Schleife denn das nach dem ersten Lauf die Zeit nicht mehr 
1000ms sondern 900ms. Schließlich fängt es doch von vorne an, und der 
Wert wird nirgends zwischengespeichert. Stutzig macht mich das langsam.

von N. M. (mani)


Lesenswert?

Hercules H. schrieb:
> Davon mal ganz abgesehen das ich gar nicht verstehe was da steht. und
> warum

Das ist dein Hauptproblem. Du solltest zwingend Mal ein vernünftiges C 
Buch durcharbeiten damit du verstehst was hier passiert. Ansonsten 
machst du dir nur das Leben schwer. Du musst verstehen was eine Funktion 
ist, was man mit einer Schleife machen kann und was eine Konstante ist.

In deinem Eingangspost hat sich i nicht verändert. Der Compiler hat das 
erkannt und dafür eine Konstante eingesetzt.
Deshalb gab es keine Fehlermeldung bei _delay_ms(i).

_delay_ms ist wie gesagt ein Makro das eine Konstante erwartet. Dadurch 
dass du in deinem berichtigten Code eine Zuweisung machst (i=i-1) wird 
aus i eine wirkliche Variable. Deshalb meckert der Compiler. Zu Recht.

Werner P. hat dieses Problem einfach umgangen indem er eine Konstante 
für _delay_ms eingesetzt. Nämlich 1. Damit die Zeit einstellbar ist, 
macht er noch eine Schleife darum. Die Funktion my_delay_ms wartet also 
bei einem Aufruf counter*1ms.

von Teo D. (teoderix)


Lesenswert?

Hercules H. schrieb:
> Aber
> wie weiß die Schleife denn das nach dem ersten Lauf die Zeit nicht mehr
> 1000ms sondern 900ms.

Hercules H. schrieb:
> i=i-100

von N. M. (mani)


Lesenswert?

Hercules H. schrieb:
> Aber wie weiß die Schleife denn das nach dem ersten Lauf die Zeit nicht
> mehr 1000ms sondern 900ms.

Indem sie eine temporäre Variable i hält die sie bei jedem 
Schleifendurchlauf um die angegebene Operation verändert (i=i-1).

Hercules H. schrieb:
> Schließlich fängt es doch von vorne an,Hercules H. schrieb:
> und der Wert wird nirgends zwischengespeichert
Doch in i.

Nimm Mal einen Debugger deiner Wahl.
Entweder direkt auf dem uC (du hast aber wahrscheinlich keinen Debugger 
dafür) oder in einer C Applikation auf dem PC.
Da kannst du die Einzelschritte einer For Schleife Mal Schritt für 
Schritt durchsteppen und sehen wie sie abgearbeitet wird.

von Zeno (Gast)


Lesenswert?

Dirk B. schrieb:
> Das wäre auch eine Schleife.

Goto muß nicht unbedingt eine Schleife sein, in diesem Fall wäre es aber 
schon so.

von Dirk B. (dirkb2)


Lesenswert?

Die for-Schleife hat 4 Teile:
for(Initialisierung;Laufbedingung;Änderung) Schleifenkörper

Die Initialisierung wird vor dem Schleifenbeginn einmal aufgerufen
Die Laufbedingung wird vor jedem Durchlauf geprüft.
Die Änderung wird nach dem Durchlauf des Schleifenkörpers aufgerufen.
Der Schleifenkörper enthält die Anweisungen, die wiederholt werden.


Du kannst eine for-Schleife auch als while-Schleife schreiben.

Initialisierung;
while(Laufbedingung) {
  Schleifenkörper
  Änderung;
}

Beitrag #6401763 wurde von einem Moderator gelöscht.
Beitrag #6401765 wurde von einem Moderator gelöscht.
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.