Rückwärts zählen in C, von n bis 0 in n'er schritten.

OP #6401165
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
}
Gast #6401174
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)
Gast #6401179
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.
Gast #6401182
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
OP #6401269
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. :/
Angehängte Dateien:
OP #6401280
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...
#6401315
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.
Gast #6401329
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.
#6401331
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
#6401418
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?
Gast #6401438
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.
OP #6401549
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
}
Gast #6401551
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?
OP #6401555
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.
#6401556
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.
#6401564
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.
#6401631
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren