Forum: Mikrocontroller und Digitale Elektronik While Schleife wird erst beim zweiten Mal ausgeführt?


von Sandra D. (sandy_d)


Lesenswert?

Huhu, wieder mal eine Anfängerfrage aber das verwirrt mich leider 
komplett.

Ich frage in meinem Code per "IF" einen Knopf ab. Direkt als erstes in 
der "IF"-Abfrage kommt eine While-Schleife die etwas so lange ausführt 
wie der Knopf gehalten wird.

Da das in meiner "größeren" Schaltung irgendwie nicht klappt habe ich 
jetzt einen kleinen Beispielcode geschrieben der sich auf dieses Problem 
fokusiert. Ich habe auf Serial.println() Befehle eingebaut dass ich am 
Computer mit dem Serial Monitor das Problem nachvollziehen kann.

Und hier zeigt er eben auch an dass er erst in die "IF"-Abfrage springt 
wenn ich den Knopf drücke, die While-Schleife allerdings komplett 
überspringt und erst beim wohl nächsten Durchlauf der kompletten "loop" 
Funktion meine While Schleife ausführt.

Meine Frage an die Profis ist nun: Warum?

Das ist mein kleines Testprogramm:
1
const int Knopf = 12;
2
const int LED = 5;
3
4
void setup() {
5
  Serial.begin(9600);
6
7
  pinMode(Knopf, INPUT_PULLUP);
8
  pinMode(LED, OUTPUT);
9
10
  digitalWrite(LED, LOW);
11
}
12
13
void loop() {
14
  if (digitalRead(Knopf) == LOW)
15
  {
16
    Serial.println("Der Knopf wurde gedrückt");
17
    while (digitalRead(Knopf) == LOW)
18
    {
19
      Serial.println("Knopf wird gehalten");
20
      digitalWrite(LED, HIGH);
21
    }
22
    Serial.println("Aus der While Schleife drausen");
23
    digitalWrite(LED, LOW);
24
  }
25
26
}

Und das ist die Ausgabe des Serial Monitors:
1
Der Knopf wurde gedrückt
2
Aus der While Schleife drausen
3
Der Knopf wurde gedrückt
4
Knopf wird gehalten
5
Knopf wird gehalten
6
Knopf wird gehalten
7
Knopf wird gehalten
8
Knopf wird gehalten
9
Knopf wird gehalten
10
Knopf wird gehalten
11
Knopf wird gehalten
12
Knopf wird gehalten
13
Knopf wird gehalten
14
Aus der While Schleife drausen
15
Der Knopf wurde gedrückt <-- Hier habe ich ein zweites Mal den Knopf gedrückt
16
Aus der While Schleife drausen
17
Der Knopf wurde gedrückt
18
Knopf wird gehalten
19
Knopf wird gehalten
20
Knopf wird gehalten
21
Knopf wird gehalten
22
Knopf wird gehalten
23
Knopf wird gehalten
24
Knopf wird gehalten
25
Knopf wird gehalten
26
Knopf wird gehalten
27
Knopf wird gehalten
28
Knopf wird gehalten
29
Knopf wird gehalten
30
Knopf wird gehalten
31
Aus der While Schleife drausen

Ich hoffe dass es nicht wieder so eine Diskussion ausartet wie meine 
Frage gestern :-)

LG
Sandy

: Verschoben durch Moderator
von Sebastian R. (sebastian_r569)


Lesenswert?

Ist der Taster irgendwie entprellt?

von mitlesa (Gast)


Lesenswert?

Die Meldungen Zeile 1 und 2 stammen vermutlich noch aus
der Zeit der Initialisierung wo der Pullup noch nicht
ausreichend wirkt (da sehr schwach).

Mach mal versuchshalber ein delay(500) am Ende von <void setup()>

von Pinkshell (Gast)


Lesenswert?

Ich denke auch, dass es Tastenprellen sein könnte.
Die Ausgabe des ersten Serial.println() dauert so circa 20ms, manche 
Schalter prellen so lange.
Ein delay(100) vor dem while könnte das verbessern.
- Tom

von mitlesa (Gast)


Lesenswert?

Pinkshell schrieb:
> Ich denke auch, dass es Tastenprellen sein könnte.

Ein Prellen ist aber nicht reproduzierbar und würde jedes
Mal ein anderes Ergebnis bringen. Das wissen wir aber bisher
nicht.

von Oliver S. (oliverso)


Lesenswert?

mitlesa schrieb:
> Die Meldungen Zeile 1 und 2 stammen vermutlich noch aus
> der Zeit der Initialisierung wo der Pullup noch nicht
> ausreichend wirkt (da sehr schwach).

Nun ja, der hat ca. 50kOhm, und ist so schnell an, so schnell kannst du 
gar nicht gucken.

Wenn da natürlich ein paar Farad Kondensator am Knopf hängen, dann 
wird’s tatsächlich etwas dauern.

@TO: zeig mal die Schaltung dazu.

Oliver

von mitlesa (Gast)


Lesenswert?

Oliver S. schrieb:
> und ist so schnell an, so schnell kannst du gar nicht gucken.

Die Geschwindigkeit mit der ich schauen kann ist leider
nicht der Massstab für eine korrekte Funktion der Anordnung.

von Sandra D. (sandy_d)


Lesenswert?

Kondenstatoren oder so habe ich nicht.
Arduino D12 <-> Taster <-> Masse
Arduino D5 <-> Vorwiderstand <-> LED <-> Masse
Also ganz einfach. War ja nur zum Testen wegen der While-Schleife.

Und die Serial Ausgabe habe ich immer gelöscht bevor ich es getestet 
habe. Also da war auch nichts von der Initialisierung drin gehangen.

Aber vielen Dank an alle, das Problem ist gelöst.
Das Delay am Ende von der setup() Funktion hat irgendwie nichts 
gebracht.

Aber das Delay eine Zeile über der While-Schleife hat funktioniert.
Jetzt sieht die Serial Ausgabe so aus wie gehofft.

(Wieder so wie vorher. Gelöscht und dann neu getestet)
1
Der Knopf wurde gedrückt
2
Knopf wird gehalten
3
Knopf wird gehalten
4
Knopf wird gehalten
5
Knopf wird gehalten
6
Knopf wird gehalten
7
Aus der While Schleife drausen
8
Der Knopf wurde gedrückt <-- hier habe ich nochmal gedrückt.
9
Knopf wird gehalten
10
Knopf wird gehalten
11
Knopf wird gehalten
12
Knopf wird gehalten
13
Knopf wird gehalten
14
Knopf wird gehalten
15
Knopf wird gehalten
16
Knopf wird gehalten
17
Aus der While Schleife drausen

Dankeschön

LG
Sandy

von HildeK (Gast)


Lesenswert?

Sandra D. schrieb:
> Aber das Delay eine Zeile über der While-Schleife hat funktioniert.
> Jetzt sieht die Serial Ausgabe so aus wie gehofft.

Gratuliere, du hast gerade am lebenden Objekt das Tastenprellen 
nachgewiesen.

Mit dem Delay hast du das etwas entschärft, aber gut ist es deshalb noch 
nicht. Denn ein Taster prellt auch beim Loslassen und wenn du 
ausreichend viele Versuche machst, dann wirst du beobachten können, dass 
beim Loslassen auch mal "Der Knopf wurde gedrückt" kommen wird.
Du müsstest eine ordentliche Tastenentprellung in SW implementieren, 
z.B. derart, dass ein Tastenzustand z.B. viermal hintereinander im 
Abstand von z.B 5ms den selben Wert haben muss, damit er als gültig 
akzeptiert wird. Sowohl beim Drücken als auch beim Loslassen der Taste 
ist das notwendig.

Einfachst kannst du auch nochmals ein Delay nach Verlassen der 
while-Schleife einbringen.
Delays führen jedoch dazu, dass der Prozessor in der Zeit blockiert ist 
und nichts anderes machen kann.

von mitlesa (Gast)


Lesenswert?

HildeK schrieb:
> Denn ein Taster prellt auch beim Loslassen und wenn du
> ausreichend viele Versuche machst, dann wirst du beobachten können, dass
> beim Loslassen auch mal "Der Knopf wurde gedrückt" kommen wird.

mitlesa schrieb:
> Das wissen wir aber bisher nicht.

Will meinen der/die TO hätte dafür genauere Aussagen über den
Testvorgang abgeben müssen.

von hacker-tobi (Gast)


Lesenswert?

I am sorry aber das hier ist das falsche unter forum.
Projekte & code ist dafür da, fertige Projekte vorzustellen. Deine Frage 
gehört eher in Mikrocontroller & Elektronik. Vielleicht kanns ein admin 
ja verschieben.

von Yalu X. (yalu) (Moderator)


Lesenswert?

hacker-tobi schrieb:
> Vielleicht kanns ein admin ja verschieben.

Getan.

von Peter D. (peda)


Lesenswert?

Der ganze Ansatz wird Dir irgendwann auf die Füse fallen.

Wer es einfach und zuverlässig haben will, packt die Entprellung und 
Flankenerkennung in einen Timerinterrupt. Dann braucht die Mainloop 
nicht mehr CPU-Zeit mit Delays zu verplempern und die Tastenerkennung 
wird nicht durch die Main Laufzeiten gestört.
Auch sieht die Mainloop viel aufgeräumter aus, d.h. man macht weniger 
Fehler.

von EAF (Gast)


Lesenswert?

Peter D. schrieb:
> Wer es einfach und zuverlässig haben will, packt die Entprellung und
> Flankenerkennung in einen Timerinterrupt.

Grundsätzlich hast du recht.

Allerdings wird in der Arduino Welt da eher millis() für sowas 
verwendet, denn der/ Timerinterrupt ist schon dafür belegt.

Bei mir sieht das dann so aus.
1
#include <CombiePin.h>
2
#include <CombieTimer.h>
3
#include <CombieTools.h>
4
5
using Taster = Combie::Pin::InvInputPin<2>; // Taster gegen GND geschaltet
6
using Led    = Combie::Pin::OutputPin<13>;
7
8
Combie::Timer::EntprellTimer   entprellen(20); // ms
9
Combie::Tools::ToggleSwitch    flippflop ; // 
10
11
void setup()
12
{
13
  Taster{}.initPullup();
14
  Led{}.init();
15
}
16
17
void loop()
18
{
19
  Led{} = flippflop = entprellen = Taster{};
20
}

Wenn bedarf an den Libs besteht, rücke ich sie auch wohl raus, sollten 
sich aber auch schon irgendwo hier im Forum finden lassen.

Für die Zeiten wird das im Arduino Beispiel "BlinkWithoutWelay" 
vorgestellte Prinzip verwendet.

von EAF (Gast)


Lesenswert?

EAF schrieb:
> "BlinkWithoutWelay"
Sorry:
"BlinkWithoutDelay"

von mitlesa (Gast)


Lesenswert?

EAF schrieb:
> Wenn bedarf an den Libs besteht

Ja, für jeden Mini-Scheiss sein eigenes System mit einer extra
Lib zukleistern statt sich selbst mal bemühen und eine kompakte
Lösung anpeilen.

von EAF (Gast)


Lesenswert?

mitlesa schrieb:
> statt sich selbst mal bemühen
Meinst du mich damit?
Dann muss ich dich enttäuschen!
Das ist mein Kram. Meine Mühe.

mitlesa schrieb:
> und eine kompakte Lösung anpeilen.
Ist sie.


Jeder Handwerker wird es kennen, den Gedanken:
> Wenn du irgendwas zum drittem mal tust, dann baue eine Schablone.
Und in der Arduino Welt sind das eben Libraries.
Es tut eben keine Not das Rad zum tausendsten mal neu zu erfinden. Erst 
recht nicht wenn es schon ein passendes rundes gibt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

mitlesa schrieb:
> Die Meldungen Zeile 1 und 2 stammen vermutlich noch aus
> der Zeit der Initialisierung wo der Pullup noch nicht
> ausreichend wirkt (da sehr schwach).
Das ist ein Ammenmärchen.
Wenn da keine meterlange Leitung am Pin hängt, dann "wirkt" der Pullup 
sofort.
Denn nehmen wir einfach mal an, auf der Platine wären insgesamt 100pF 
als parasitäre Leitungskapazität (ja, ich weiß, dass es viel weniger 
ist...).
Und dann gehen wir von 50k Ohm Pullup aus (ja, ich weiß, dass es weniger 
ist...), dann haben wir eine Zeitkonstante von t = 100E-12*50k = 5us. 
Nach dieser Zeit erkennt der Eingang bei nicht betätigtem Taster sicher 
"high".

Das, was zwischen pinMode(Knopf, INPUT_PULLUP); und der Tasterabfrage 
kommt, dauert garantiert diese 5us (die zudem den absoluten Worst-Case 
darstellen).

: Bearbeitet durch Moderator
von mitlesa (Gast)


Lesenswert?

EAF schrieb:
> Meinst du mich damit?

Nein, sondern den User der sich angesprochen fühlt.

EAF schrieb:
> Ist sie.

Kompakte Lösung ist es wenn ein paar wenige Zeilen im eigennen
Programm reichen.

Deine "kompakte Lösung" ist es eine Library zu verwenden die
(vermutlich) noch eine Menge anderes Zeugs anbietet und damit
das eigene System zukleistert. Ausserdem wird der/die Anfänger(in)
nicht sinnvoll (wissend was das macht) damit umgehen können.
Also reines C&P-verhalten ohne Denk-/Verständnismöglichkeit.

von EAF (Gast)


Lesenswert?

mitlesa schrieb:
> die
> (vermutlich) noch eine Menge anderes Zeugs anbietet und damit
> das eigene System zukleistert.

Es ist nur das interessant, was wirklich in den Code kompiliert wird.
Das "kleistern" existiert nur in deiner Fantasie

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.