Hallo zusammen,
ich bin blutiger Arduino Anfänger und habe ein Problem.
Ich habe mir mit millis() einen Ablauf erstellt wie ich ihn haben
möchte. Es blinken 3 Led´s abwechselnd und durcheinander. Der Ablauf
alleine funktioniert auch super.
Mein Problem ist, dass dieser Ablauf erst starten soll, wenn ich meinen
Taster drücke und aufhören soll wenn ich ihn loslasse.
Was mach ich verkehrt??
1
unsigned long lastMillis1;
2
int ledPin1=7; // Blitzlichter oben links und unten rechts
3
int ledPin2=8; // Blitzlichter oben rechts und unten links
4
int ledPin3=4; //Blitzlichter mitte
5
6
int buttonPin=2;
7
int buttonState=0;
8
9
void setup() {
10
11
pinMode(ledPin1,OUTPUT);//setup daten Blitzlicht
12
pinMode(ledPin2,OUTPUT);
13
pinMode(ledPin3,OUTPUT);
14
15
pinMode(buttonPin,INPUT);
16
17
18
}
19
void loop() {
20
buttonState=digitalRead(buttonPin);
21
22
if(buttonState==HIGH){
23
24
25
26
27
if((millis()-lastMillis1)==0){ //Blitzlichter mitte
28
digitalWrite(ledPin3,HIGH);
29
}
30
if((millis()-lastMillis1)==160){
31
digitalWrite(ledPin3,LOW);
32
}
33
if((millis()-lastMillis1)==320){
34
digitalWrite(ledPin3,HIGH);
35
}
36
if((millis()-lastMillis1)==480){
37
digitalWrite(ledPin3,LOW);
38
}
39
if((millis()-lastMillis1)==640){
40
digitalWrite(ledPin3,HIGH);
41
}
42
if((millis()-lastMillis1)==800){
43
digitalWrite(ledPin3,LOW);
44
}
45
if((millis()-lastMillis1)==960){
46
digitalWrite(ledPin3,HIGH);
47
}
48
if((millis()-lastMillis1)==1120){
49
digitalWrite(ledPin3,LOW);
50
}
51
if((millis()-lastMillis1)==1280){
52
digitalWrite(ledPin3,HIGH);
53
}
54
if((millis()-lastMillis1)==1440){
55
digitalWrite(ledPin3,LOW);
56
}
57
if((millis()-lastMillis1)==1600){
58
digitalWrite(ledPin3,HIGH);
59
}
60
if((millis()-lastMillis1)==1600){
61
digitalWrite(ledPin3,LOW);
62
63
}
64
65
66
67
68
69
if((millis()-lastMillis1)==500){ //Blitzlichter oben rechts und unten links
70
digitalWrite(ledPin1,HIGH);
71
}
72
if ((millis()-lastMillis1)==600) {
73
digitalWrite(ledPin1,LOW);
74
}
75
if((millis()-lastMillis1)==700){
76
digitalWrite(ledPin1,HIGH);
77
}
78
if ((millis()-lastMillis1)==800){
79
digitalWrite(ledPin1,LOW);
80
}
81
82
83
84
85
if((millis()-lastMillis1)==1300){ //Blitzlichter oben links und unten rechts
Hallo,
Du verrätst nicht, wie Du den Taster angeschlossen hast...
Nach Deiner Abfrage if(buttonState==HIGH){
fragst Du auf HIGH ab, Taster also zwischen IO-Pin und 5V. Dann brauchst
Du aber einen PullDown-Widerstand, damit der IO-Pin bei losgalassenem
Taster auch LOW erkennt.
Hast Du das so und welchen Wert hat Dein Widerstand?
Warum schalstest Du den Taster nicht zwischen IO und GND, aktiverst mit
pinMode(buttonPin,INPUT_PULLUP); den internen PullUp-Widerstand und
fragst dann mit if(buttonState==LOW){
auf LOW-Pegel ab?
Erspart den zusätzlichen Widerstand.
Gruß aus Berlin
Michael
Ich habe 5V zum Taster gelegt, andere Seite vom Taster auf Pin2 und am
wiederstand (war im Starter set). Am anderen kontakt vom wiederstand bin
ich auf GND
Unabhängig davon: Dein Programm checkt im Moment ja, wenn Taster
gedrückt, schalte LEDs. Aber was wenn Taster nicht gedrückt ist? Dann
bleiben die LEDs ja so wie sie sind. Es fehlt also noch ein Else: alle
LEDs aus
ich habe die else jetzt nachgetragen. wenn ich den Sketch auf den
arduino lade und schnell den Taster drücke, geht es. wenn ich loslasse
hört es auch auf. wenn ich dann aber wieder drücke, passiert nichts
mehr.
1
unsigned long lastMillis1;
2
int ledPin1=7; // Blitzlichter oben links und unten rechts
3
int ledPin2=8; // Blitzlichter oben rechts und unten links
4
int ledPin3=4; //Blitzlichter mitte
5
6
int buttonPin=2;
7
int buttonState=0;
8
9
void setup() {
10
11
pinMode(ledPin1,OUTPUT);//setup daten Blitzlicht
12
pinMode(ledPin2,OUTPUT);
13
pinMode(ledPin3,OUTPUT);
14
15
pinMode(buttonPin,INPUT);
16
17
18
}
19
void loop() {
20
buttonState=digitalRead(buttonPin);
21
22
if(buttonState==HIGH){
23
24
25
26
27
if((millis()-lastMillis1)==0){ //Blitzlichter mitte
28
digitalWrite(ledPin3,HIGH);
29
}
30
if((millis()-lastMillis1)==160){
31
digitalWrite(ledPin3,LOW);
32
}
33
if((millis()-lastMillis1)==320){
34
digitalWrite(ledPin3,HIGH);
35
}
36
if((millis()-lastMillis1)==480){
37
digitalWrite(ledPin3,LOW);
38
}
39
if((millis()-lastMillis1)==640){
40
digitalWrite(ledPin3,HIGH);
41
}
42
if((millis()-lastMillis1)==800){
43
digitalWrite(ledPin3,LOW);
44
}
45
if((millis()-lastMillis1)==960){
46
digitalWrite(ledPin3,HIGH);
47
}
48
if((millis()-lastMillis1)==1120){
49
digitalWrite(ledPin3,LOW);
50
}
51
if((millis()-lastMillis1)==1280){
52
digitalWrite(ledPin3,HIGH);
53
}
54
if((millis()-lastMillis1)==1440){
55
digitalWrite(ledPin3,LOW);
56
}
57
if((millis()-lastMillis1)==1600){
58
digitalWrite(ledPin3,HIGH);
59
}
60
if((millis()-lastMillis1)==1600){
61
digitalWrite(ledPin3,LOW);
62
63
}
64
65
66
67
68
69
if((millis()-lastMillis1)==500){ //Blitzlichter oben rechts und unten links
70
digitalWrite(ledPin1,HIGH);
71
}
72
if ((millis()-lastMillis1)==600) {
73
digitalWrite(ledPin1,LOW);
74
}
75
if((millis()-lastMillis1)==700){
76
digitalWrite(ledPin1,HIGH);
77
}
78
if ((millis()-lastMillis1)==800){
79
digitalWrite(ledPin1,LOW);
80
}
81
82
83
84
85
if((millis()-lastMillis1)==1300){ //Blitzlichter oben links und unten rechts
Das liegt vermutlich daran dass du in deinen if Abfragen immer auf
Gleichheit prüfst. Was passiert wenn die Laufzeit länger war und deine
Zahl schon größer geworden ist? Richtig, nix mehr.
Darum möglichst auf größer oder kleiner prüfen. Und nicht 1000 einzelne
ifs. Nimm wenn möglich auch mal else if, damit er die unnötigen nicht
extra noch prüft.
lastMillis wird nur gesetzt wenn du lange genug deinen Taster drückst.
Wenn du den aber vorher loslässt, was passiert dann?
millis() muss man auch pro Schleifendurchlauf nur einmal aufrufen und
sollte den Wert schön zwischenspeichern.
Ja weil erst durch den Taster die Möglichkeit entsteht dass
millis()-millis1 zu groß wird. Deine Abfragen funktionieren nur solange
du 100%ig jede Millisekunde an den Abfragen vorbei kommst. Wenn du den
Taster jetzt 1 Sek drückst und im else Zweig landest, ist das nicht mehr
gegeben.
Deswegen so:
Schau dir mal an, wie ein Switch-Case aussieht, das könnte genau das
sein, was deinen Code etwas übersichtlicher aussehen lässt.
Und als kleiner Spoiler: Als Bedingung kann man auch Bereiche vorgegeben
(z.B. als 310...330, genau so geschrieben). Das ist bei dir auch nicht
unpraktisch, wenn du mit deinen Abfragen mal eine Millisekunde durch
Laufzeitverschiebung daneben liegst und eigentlich kein If-Zweig true
ergibt.
Olli schrieb:> ich habe die else jetzt nachgetragen. wenn ich den Sketch auf den> arduino lade und schnell den Taster drücke, geht es. wenn ich loslasse> hört es auch auf. wenn ich dann aber wieder drücke, passiert nichts> mehr.
Vielleicht hilft es Dir ja, wenn Du Dir mal auf einem grossen Stück
Papier eine Zeitlinie zeichnest und darauf Ereignisse markierst.
Das Problem dabei ist, dass man streng darauf achten muss, genau
nachzuvollziehen, was das Programm tatsächlich tut und nicht was man
denkt, was es tun soll. Programmfehler bestehen nämlich oft darin, dass
man sich nicht so ausgedrückt hat, wie man es gemeint hat.
Nimm einmal folgenden Punkt:
In der setup-Funktion merkst Du Dir mit
1
lastMillis1=millis();
einen Zeitpunkt.
In der loop-Funktion prüfst Du, falls der Taster gedrückt ist, ob die
Differenz der Zeit 0, oder 160, oder 320 usw. ist.
Was passiert nun, wenn Du den Taster erst 170ms nachdem Du Dir in der
setup-Funktion die Zeit gemerkt hast, drückst? Richtig, der Ablauf
beginnt nicht am Anfang, sondern mittendrin!
Das wirft die Frage auf, wann denn genau der Ablauf der Lichter beginnen
soll. Doch wohl genau dann, wenn die Taste gedrückt wird, oder?
Das hast Du aber nicht hingeschrieben. Du hast im Code geschrieben, dass
der Zeitablauf, unabhängig davon, ob der Taster gedrückt wurde, oder
nicht, in der setup-Funktion - also kurz, nachdem Du den Controller
eingeschaltet hast -, beginnen soll.
Dazu noch folgender Punkt:
Du merkst Dir die Zeit, sobald der letzte Schritt in der Lichterfolge
erledigt ist und der Taster noch gedrückt ist.
Das soll wohl bewirken, dass der Ablauf von neuem beginnt, wenn der
vorherige beendet ist und die Taste noch gedrückt.
Aber falls Du die Taste loslässt, bevor der Ablauf beendet wurde, dann
merkst Du Dir keine neue Zeit, sobald Du die Taste erneut drückst. In
der Variable lastMillis1 steht immer noch der Zeitpunkt, als die
setup-Funktion ausgeführt wurde - was ja auch sehr lange her sein kann.
Was hat das zur Folge?
Mit dem Vergleich "==" gibt es auch ein Problem, dass ja schon erwähnt
wurde. Das ist nur nicht gleich merklich, weil Du ausser dem Port setzen
nicht viel tust. Aber nimm einmal an, das würde etwas mehr als die Zeit
dauern, die von der nachfolgenden if-Bedingung geprüft wird. Was
passiert dann und wie kann man das verhindern?
Das sollen nur Beispiele sein. Du solltest Dir wiegesagt, ganz genau und
Schritt für Schritt überlegen, was, wann und warum geschieht, so wie es
dasteht.
Es ist ein allgemeines Problem, dass man gedanklich oft das, was sein
soll "liest" und nicht das was tatsächlich dasteht. Da muss man sehr
aufpassen, beim programmieren.
Im Leben geht einem das ja auch gerne mal so, dass man hört was man
hören will und nicht das was gesagt wurde. :-)
Viel Erfolg.
Theor schrieb:> Es ist ein allgemeines Problem, dass man gedanklich oft das, was sein> soll "liest" und nicht das was tatsächlich dasteht. Da muss man sehr> aufpassen, beim programmieren.
Ich sehe, dass das eine Ablaufsteuerung/Schrittkette werden soll.
Irgendeine Form eines endlichen Automaten. Eine recht einfache.
Aber den exakten Ablauf, das was gewünscht ist, kann ich leider nicht
aus dem Code ersehen. Da müsste ich zu viel rein interpretieren, damit
das für mich verständlich wird.
Ich würde mich über eine genauere Erklärung (Zeitdiagramm) freuen.
Im Moment sehe ich 3 Blinkautomaten, welche zu unterschiedlichen Zeiten
starten, und unterschiedliche Intervall Zeiten haben.
Z.B.:
Was soll passieren, wenn man den Knopf länger als 1600ms drückt?
Guten Morgen Olli,
ich habe mal dein Code zerlegt und um deine Blink-Sequenz zu verstehen,
die LEDs mit einem Logic-Analyser mitgeschnitten (siehe
led_sequence.PNG).
Das Problem mit deinem Button, hängt mit deiner Zuweisung der letzten ms
zusammen, diese ist vom Ort her, nicht ganz geschickt gewählt.
Aber habe mal deinen Code bissel aufgeräumt und dir deine if-Abfragen
hinein kopiert, inkl. Button-Funktion (siehe led_blink_olli.ino).
Da diese if-Abfragerei sehr unübersichtlich ist, habe ich dir mal eine
andere Möglichkeit programmiert, damit kannst du dir Blink-Sequenzen
ganz bequem über ein char-Array generieren (siehe led_blink.ino).
Es führen viele Wege zum Ziel, dies soll lediglich ein Anreiz sein, die
Problematik zu analysieren und einen allgemeingültigen Weg zu finden,
sowie die Lesbarkeit zu erhöhen.
P.S.: Die Debug-Ausgaben mittel Serial.print() etc. kannst du natürlich
wieder löschen, falls du sie nicht benötigst.
Gruß Adam
Adam P. schrieb:> P.S.: Die Debug-Ausgaben mittel Serial.print() etc. kannst du natürlich> wieder löschen, falls du sie nicht benötigst.
einfacher:
ersetze
Serial.print(
zu
1
#define DEBUG // oder ausklammern mit // #define DEBUG
Ja, dann erst mal Danke, für die Anerkennung!
Allerdings, andererseits weiß ich aber nicht was (und ob ich) "besser"
ist/(bin).
Denn ich kann ja noch nicht mal zuverlässig zwischen Gut und Böse
unterscheiden.
@Joachim B. (jar)
@Arduino Fanboy D. (ufuf)
Das bedingte Kompilieren im DEBUG Modus ist natürlich Sinnvoll,
aber was mir überhaupt nicht einleuchtet:
Warum besitzt die Serial-Klasse von Arduino keine printf() wie man sie
kennt?
Nun muss man entweder selbst nachbessern, einen formatierten Buffer
erstellen oder sich aus print(), println() und write() seine Ausgabe
selbst formatieren.
Ich programmiere eigentlich kein Arduino, deshalb kann es sein, dass ich
da was übersehe. (?)
Adam P. schrieb:> Warum besitzt die Serial-Klasse von Arduino keine printf() wie man sie> kennt?
Naja...
Zu der Motivation der Arduinoentwickler kann ich wenig sagen, nur, dass
sie ursprünglich versucht haben Processing auf AVR zu portieren.
Und da gibts kein printf() soweit mir bekannt.
Des weiteren ist printf() recht speicherintensiv.
Gerade auch mit float Unterstützung.
Somit ist der Verzicht darauf schon fast positiv zu bewerten.
Tipp A:
Es stehen sprintf() und seine Brüder für dich bereit.
Dessen Ergebnisse lassen sich durchaus mit Serial ausgeben.
Tipp B:
Es ist ein kleines, eine eigene Print Implementierung zu schaffen,
welche dann Print::printf() beherrscht.
Tipp C:
https://playground.arduino.cc/main/printf
Schlussendlich:
Der von dir bemängelte Punkt ist also gar nicht so dramatisch.
Arduino Fanboy D. schrieb:> Schlussendlich:> Der von dir bemängelte Punkt ist also gar nicht so dramatisch.
Ne ist er auch nicht, wollte es lediglich wissen.
Arduino Fanboy D. schrieb:> Es ist ein kleines, eine eigene Print Implementierung zu schaffen
Auf meinen ARM Atmel µC habe ich eigene printf() implementierung mit
DMA.
(Mögliche Ausgabearten, siehe Bild).
Somit alles OK - war nur neugierig :-)
Olli schrieb:> Mein Problem ist, dass dieser Ablauf erst starten soll, wenn ich meinen> Taster drücke und aufhören soll wenn ich ihn loslasse.> Was mach ich verkehrt??
Mach mal statt
1
if(buttonState==HIGH){
2
3
.
4
.
5
.
6
7
}
eine while Schleife.
1
buttonState=digitalRead(buttonPin);
2
while(buttonState==HIGH){
3
buttonState=digitalRead(buttonPin);
4
.
5
.
6
.
7
}
Das müsste funktioniren, wenn ich das Problem richtig verstanden habe.