Frage von DProgrammingR, 79

LED's ansteuern mit Arduino?

Dieses Programm habe ich als Anfänger (15 Jahre) geschrieben, da es mein Hobby ist. Beim Kompilieren gab es mir keine Fehler an, die Hardware funktioniert einwandfrei. Mein Ziel ist es drei LED's(Siehe Bild) immer nacheinander Blinken zu lassen, aber so das wenn die dritte LED aufleuchtet, die ersten zwei immer noch leuchten. Erst wenn die dritte LED für eine halbe Sekunde aufleuchtet, sollen alle LED's aufhören zu leuchten und es beginnt wieder von vorn. Vielleicht kennt sich da einer ein bisschen besser aus und könnte mir behilflich sein wo denn da mein Fehler liegt. Danke im Voraus :).

int i = 1;

void setup() {

pinMode(13, OUTPUT);

pinMode(12, OUTPUT);

pinMode(11, OUTPUT);

pinMode(10, OUTPUT);

pinMode(9, OUTPUT);

pinMode(8, OUTPUT);

}

void loop() {

digitalRead(i);

if(i = 0){

digitalWrite(13, LOW);

digitalWrite(12, LOW);

digitalWrite(11, LOW);

}

if(i > 0){

digitalWrite(13, HIGH);

}

if(i > 1){

digitalWrite(12, HIGH);

}

if(i > 2){

digitalWrite(11, HIGH);

}

if(i = 4){

int i = 0;

}

i++;

delay(500);

}

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von JuicyLuisian, 39

int zeit = 500;

void setup() {

pinMode(13, OUTPUT);

pinMode(12, OUTPUT);

pinMode(11, OUTPUT);

}

void loop() {

digitalWrite(13, LOW);

digitalWrite(12, LOW);

digitalWrite(11, LOW);

delay(zeit);

digitalWrite(13, HIGH);

delay(zeit);

digitalWrite(12, HIGH);

delay(zeit)

digitalWrite(11, HIGH);

delay(zeit);

}

So wäre mein Lösungsansatz. Was habe ich verändert und warum?

Bisher gingen deine LEDs nur an und wieder aus und zwar alle gleichzeitig, richtig? Das Problem war dass du keine Wartezeit zwischen deinen If-Bedingungen hattest und die LEDs mit der Prozessorrechengeschwindigkeit eingeschalten wurden.

Ich habe "digital.read(i)" herausgenommen, da diese Funktion nichts bewirkt hat. Die Variable 'i' wurde bei jeder if-Bedingung gelesen.

Deine Idee eine Variable zu deklarieren (einzubinden), aufwärtszuzählen und mit If abzufragen ist, zum großteil, richtig. Allerdings benötigst du diese nicht, vieleicht wenn dein Programm komplexer wird, aber hierfür noch nicht.

Ich habe noch dazu eine Variable 'zeit' eingelesen um die Zeit zwischen dem schalten in "delay()" einzusetzen.

Frage wenn du Fragen hast und wenn deine If-Methode doch wichtig war kann ich dir da auch nochmal helfen.

Kommentar von DProgrammingR ,

Danke vielmals für die Antwort. Da ich das Programm am liebsten noch ein bisschen erweitern würde, mit 3 Weiteren LED's in einer eigenen Reihe.  * * * (die ersten 3 LED's)  * * *(mit ein bisschen Abstand von den anderen LED's  die nächsten 3). Die ersten 3 LED's laufen nach ihrem Programm. Wenn dann das dritte LED in der erstem Reihe aufleuchtet, soll das erste LED in der zweiten Reihe zu leuchten beginnen. Man könnte also sagen die erste Reihe läuft dreimal so schnell wie die zweite Reihe. Da ich nicht einfach alles nacheinander mit delay auflisten wollte, dachte ich mir ich könnte das Programm "vereinfachen" mit if/switch Anweisungen. z.B : Wenn das dritte LED(erste Reihe) Leuchtet, soll ein weiteres LED(zweite Reihe) leuchten. Dieses Programm ist für mich nur zur Übung, da ich mich gerne verbessern möchte. :)

Kommentar von ralphdieter ,

Da passt mein Kommentar ja perfekt! (Der hat sich mit Deinem überschnitten, weil mein Telefon geklingelt hat).

Ich würde die LEDs für jeden Zustand als String ablegen, z.B. "111000" für die ersten drei an, die anderen aus. Dafür kannst Du eine Funktion schreiben:

void setLED (char const mode){
/* geht viel eleganter als Schleife */
digitalWrite(11, mode[0]=='1'?HIGH:LOW);
 digitalWrite(12, mode[1]=='1'?HIGH:LOW);
 digitalWrite(13, mode[2]=='1'?HIGH:LOW);
 digitalWrite(14, mode[3]=='1'?HIGH:LOW);
 digitalWrite(15, mode[4]=='1'?HIGH:LOW);
 digitalWrite(16, mode[5]=='1'?HIGH:LOW);
}

Diese Strings liegen in einem Array, ein Eintrag je Zustand. Das macht action() besonders einfach:

char const LEDstate[6][64] = {
"000000", "100000", "110000", "111000",
 "000100", "100100", "110100", "111100",
// ...
};

void action (int state){
setLED( LEDstate[state} );
}

Fürs erste ist das etwas mehr Tippaufwand. Aber das Herumspielen und Erweitern wird dadurch wesentlich leichter.

Kommentar von ralphdieter ,

Fehlerteufel:

void setLED (char const mode[6]){
Kommentar von JuicyLuisian ,

Hier ein Muster wie man es machen kann. Es wird immer noch kein If verwendet, da es immer noch nicht sinnvoll ist.

Die Idee mit dem Strings von "ralphdieter"  ist auch sehr nützlich. Wenn ich die Zeit finde werde ich dir den Code von ihm auch noch mal erstellen.
http://codepad.org/yNU3gHCC

Kommentar von JuicyLuisian ,

Dieser Code bedient sich einer String-Liste, in der du eingibst wie die LEDs leuchten sollen. Naja, in wirklichkeit sind es Array-Listen, da C keine Strings beherscht. Man kann zwar Strings verwenden, da Arduino auch C++ beherscht, aber es ist eher schlecht als recht.

http://codepad.org/ZJjMxFle

Ich habe den Code noch nicht ausprobiert, vieleicht ist auch ein fehler drin. Würde mich über feedback freuen.

Kommentar von ralphdieter ,

Sieht gut aus! jetzt muss man zum Spielen nicht mehr programmieren, sondern kann die gewünschte LED-Folge als Daten eingeben. Gut ist auch das Array ledPin: so kann man frei bestimmen, welche LED an welcher String-Position gemeint ist.

Nur zwei Dinge sind mir im Code aufgefallen:

In Zeile 20:

  while(lauf[i] != NULL) 

Dazu muss man in der Definition von lauf[] unbedingt als letztes Element NULL eintragen. Schöner geht's mit:

 for(i=0; i<sizeof lauf; ++i)

Und in Zeile 34:

  if(liste[i] == 1) ...

Hier muss man natürlich mit dem Zeichen '1' (bzw. '0') vergleichen.

Kommentar von JuicyLuisian ,

'NULL' oder auch '\0' oder Wert 0 im ASCII-Code ist bei einem Array immer angehangen von seiten des Kompilers. Der Rest ist aber richtig, es sieht schöner aus wenn man "sizeof(lauf)" verwendet und die If-bedingung ist falsch formuliert. Mein Fehler.

Kommentar von ralphdieter ,

0 [...] ist bei einem Array immer angehangen

Das passiert nur bei konstanten Zeichenketten (in doppelten Anführungszeichen). Selbst bei char str[] = {'a', 'b', 'c', '\0'} muss man sich selbst drum kümmern.

es sieht schöner aus wenn man "sizeof(lauf)" verwendet

Schöner ist nicht immer besser: sizeof liefert die Größe in Bytes. Man muss also "sizeof lauf/sizeof lauf[0]" schreiben. Mein Fehler.

P.S.: sizeof ist keine Funktion. Dahinter steht entweder ein Datenyp in runden Klammern oder ein Ausdruck, den man eigentlich nie einklammern muss. Ich vermeide die Klammern bei Ausdrücken aus gutem Grund: Definiert irgendein fremder Header einen Typ namens "lauf" (large array of user functions?), verhält sich sizeof(lauf) anders als erwartet. Solche Fehler sind extrem schwer zu finden.

Kommentar von JuicyLuisian ,

Das passiert nur bei konstanten Zeichenketten (in doppelten
Anführungszeichen). Selbst bei char str[] = {'a', 'b', 'c', '\0'} muss
man sich selbst drum kümmern.

Ungläubig wie ich bin habe ich´s selbst ausprobiert und doch, der Kompiler hängt die NULL in jeden Fall hinten dran.

Das mit sizeof hab ich dir blind geglaubt :) jetzt finde ich die while-NULL Methode sauberer.

Kommentar von ralphdieter ,
da C keine Strings beherscht

Und woher kommt dann "string.h"? In C ist ein String einfach ein null-terminiertes char-Array (aka NTBS).

Kommentar von JuicyLuisian ,

string.h ist eine Bibliothek die Funktionen beinhaltet die man oft für Strings benötigt, allerdings besitzt C kein Typ String. Es kann lediglich mit hilfe von Arrays Charakter aneinander hängen und so tun als ob.

Kommentar von ralphdieter ,

Dein Ansatz ist anders strukturiert: loop() erledigt bei Dir einen kompletten Zyklus und dauert 2 Sekunden (statt 0.5s). Für wenige Zyklen ist das sicher lesbarer.

Trotzdem würde ich in beiden Fällen die Taktschleife von den Aktionen scharf trennen. Bei Dir wäre das:

int const zeit = 500; // delay [ms]

void loop_forever(){
for (;;){
action(0);
delay(zeit);
action(1);
delay(zeit);
action(2);
delay(zeit);
action(3);
delay(zeit);
}
}

Bei DProgrammingR sähe das etwas kompakter  aus:

void loop_forever(){
for (int state=0; ;state=(state+1)%4){
action(state);
delay(500);
}
}

Für die Aktion selbst verwendet man am besten ein switch-Statement:

void action (int state){
switch(state){
case 0: digitalWrite(13, LOW);
digitalWrite(12, LOW);
digitalWrite(11, LOW);
break;
case 1: digitalWrite(13, HIGH);
break;
case 2: digitalWrite(12, HIGH);
break;
case 3: digitalWrite(11, HIGH);
break;
}
}

Diese Funktion verlässt sich allerdings auf die richtige Reihenfolge der states. Um die Schleife rückwärts auszuführen, müsste man sie neu programmieren. Besser wird's wohl sein, bei jedem state alle drei LEDs an-/auszuschalten.

Erfahrungsgemäß lohnt sich das Einsparen von Zeilen fast nie: Meist muss man sie später doch einfügen — und dabei oft noch eine halbe Stunde debuggen, bis man die richtige Stelle gefunden hat.

Kommentar von JuicyLuisian ,

Dein Kommentar hat mich sehr stark irritiert, trotz mehrmaligen lesen...

Vieleicht könntest du das etwas einfacher ausdrücken? Der Arduino-Code wird in reinem C/C++ programmiert, ich bin mir nicht 100% sicher ob du das weist? Soll nicht böse gemeint sein.

Kommentar von ralphdieter ,

Worauf ich eigentlich hinaus wollte: Dein Code ist zwar kürzer und verständlicher (und damit automatisch fehlerfreier), aber bei mehr Zuständen wird loop() immer länger und hässlicher...

Ich habe vermutet, dass DProgrammingR sein Programm noch erweitern wird und habe deshalb vorgeschlagen, die Steuer-Logik (alle halbe Sekunde wird eine Aktion ausgeführt) von der eigentlichen Arbeit (LEDs ein-/ausschalten) zu trennen. Das kann dazu führen, dass der Code leichter änderbar wird (ohne jedesmal wieder auf Fehlersuche gehen zu müssen).

Aber klar: leichte Lesbarkeit und Änderbarkeit sind subjektiv. Letztendlich muss jeder seinen eigenen Stil entwickeln, mit dem er am besten zurechtkommt. Oft hilft's, wenn man dazu fremden Code anschaut und sich das Beste daraus herauspickt.

Mein Code ist Standard-C89 (wenn nicht, kannst Du es als Fehler betrachten). Sollte er Dich verwirren, ist es höchstwahrscheinlich einfach nicht "Dein Stil".

Kommentar von JuicyLuisian ,

Alles klar, das war eindeutig für mich. Ich habe nicht vermutet das du die Arduino sprache nicht kennst, wegen deines Codes, sondern viel eher weil es sich 'wie aus dem Zusammenhang gerissen' anfühlte.

Das er es erweitern wollte habe ich schon vermutet, aber noch nicht wahrgenommen. Es ist aber nie verkehrt die Antwort eines anderen zu ergänzen. ;)

Antwort
von luksterxxxx, 35

ich würde es anders machen:

digitalWrite (13, HIGH)

delay 1000

digitalWrite(12, HIGH)

delay 1000

DigitalWrite(11, HIGH)

delay 500

digitalWrite(13, LOW)

digitalWrite(12, LOW)

digitalWrite(11, LOW)

delay 2000

ich weiß dass die semikoli fehlen. das ganze halt in die loop. außerdem stimmt glaub ich die zeile "if(i<0) nicht, weil das nicht geht ?! teste es einfach mal aus

Antwort
von ralphdieter, 32

Der Klassiker -- willkommen im  Club :-)

    if(i = 0){

Eigentlich sollte hier jeder Compiler seit 1989 eine Warnung ausgeben.

Kommentar von JuicyLuisian ,

Warum sollte das nicht gehen?

Kommentar von ralphdieter ,

Weil der Programmierer hier ganz bestimmt schreiben wollte:

    if (x==0)

Mit nur einem Gleichzeichen wird x auf 0 gesetzt und der Block nicht ausgeführt (weil 0 als false gilt).

Kommentar von JuicyLuisian ,

Das ist mir erst auf den 2. Blick aufgefallen -.- ich geh gleich los und exmatrikuliere mich an meiner Hochschule...

Keine passende Antwort gefunden?

Fragen Sie die Community