Forum: Mikrocontroller und Digitale Elektronik Buttons an ESP32 entstören


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Ernst P. (fredy15)


Angehängte Dateien:

Lesenswert?

Ich steuere mit einem ESP32 4 DC Motoren (12V). Jeder Motor wird mit 
einer BTS7960 43A H-bridge gesteuert, welche vom ESP32 via PWM 
kontrolliert wird. Die Zuleitungen von den H-Bridges zu den Motoren ist 
über 1mm2 Klingeldraht von 1-3m Länge realisiert. Die Motoren werden von 
einem 14.4V Akku angetrieben.

Das hat wunderbar funktioniert, so lange ich den ESP32 über einen 
kleinen Webserver am Handy bedient habe. Nun wollte ich die Schaltung 
mit 3 Buttons ergänzen, was auf dem Breadboard auch problemos 
funktioniert hat.

Der Code für die Buttons ist hier: 
https://github.com/pluess/workbench-lift/blob/master/src/button.cpp

Nachdem ich alles eingebaut hatte, gab es auf den GPIOs für die Buttons 
massenweise Geisterinputs. Die Buttons sind ca 1.5m vom ESP32 entfernt. 
Die Ursache war dann auch rasch gefunden: Die Zuleitungen für die DC 
Motoren und die Buttons liegen im gleichen Kabelkanal. Jedesmal wenn ein 
Motor ein-/auschaltet haben auch die GPIOs der Buttons reagiert.

Ich werde die Kabel für die Buttons getrennt verlegen, ev. genügt das ja 
schon.

Aber wenn ich schon mal dran bin: So viel ich ergoogelt habe wäre es 
sinnvoll vor den GPIOs einen physischen Pullupwiederstand und einen 
Kondensator einzubauen. Im Anhang seht ihr ein Foto der Schaltung und 
wie ich mir die Entstöhrung vorgestellt habe. Macht das so Sinn?

Ev. gibt es ja noch bessere Lösungen. Ich habe z.B. noch ein paar NE555 
rumliegen. Oder die Buttons mit einem ESP8266 auslesen und mit I2C 
Verbinden?

Viele Grüsse
Fredy

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ernst P. schrieb:
> Der Code für die Buttons ist hier:
> https://github.com/pluess/workbench-lift/blob/master/src/button.cpp

Nur weil man eine Funktion debounce nennt, entprellt sie noch lange 
nicht. Ich sehe darin nichts, was entprellen könnte.

Eine Entprellfunktion muß ja Tastenänderungen sicher erkennen, d.h. 
braucht für jede Taste eigene Variablen zur Filterung.
Bewährt hat sich eine Filterung über 4 oder mehr gleiche Zustände einer 
Taste je Zeitintervall (z.B. 10ms).
Zusätzliche Hardware ist dann unnötig und die CPU-Last ist auch 
lächerlich gering.

von Ernst P. (fredy15)


Lesenswert?

Gut möglich, das es hier noch Verbesserungspotential gibt. Aber 
Entprellung ist hier nicht das Problem.

von Peter D. (peda)


Lesenswert?

Ernst P. schrieb:
> Gut möglich, das es hier noch Verbesserungspotential gibt. Aber
> Entprellung ist hier nicht das Problem.

Natürlich ist die fehlende Entprellung Dein Hauptproblem. Es gibt leider 
auch viele gewerbliche Programmierer, die das nicht einsehen wollen und 
der Benutzer muß dann darunter leiden (Aufzüge, Kaffeemaschinen, 
Oszilloskope und und und).

von Rainer W. (rawi)


Lesenswert?

Ernst P. schrieb:
> Nun wollte ich die Schaltung mit 3 Buttons ergänzen

Du darfst die Dinger hier gerne "Taster"  nennen ;-)

> Nachdem ich alles eingebaut hatte, gab es auf den GPIOs für die Buttons
> massenweise Geisterinputs.

Wie sehen die "Geisterinputs" aus und wieviel Energie muss so eine 
Störung mitbringen, damit der ESP einen Puls erkennt. Vielleicht ist 
dein Eingang einfach zu hochohmig. Gegen kurze Störungen hilft ein 
Kondensator, aber bitte mit Serienwiderstand zur Strombegrenzung. Sonst 
gibt es jedes Mal beim Schließen des Kontaktes einen Funken, der 
langfristig deine Kontaktoberfläche verbrennt.

von Peter D. (peda)


Lesenswert?

Ich bevorzuge immer die Entprellung/Entstörung eines ganzen IO-Ports per 
vertical Counter. Dann muß man nicht umständlich für jede Taste den Code 
copy & pasten. Das Main wählt dann einfach per Bitmaske aus, welche 
Taste man an einer Stelle gerade auswerten will.
Ungenutze entprellte IO-Pins kosten weder Code noch RAM.
Daß alle Pins parallel entprellt werden, macht es auch leicht, 
Zusatzfunktionen (repeat, lang/kurz Erkennung) zu implementieren.

https://www.compuphase.com/electronics/debouncing.htm

: Bearbeitet durch User
von Monk (Gast)


Lesenswert?

Ernst P. schrieb:
> So viel ich ergoogelt habe wäre es sinnvoll vor den GPIOs einen
> physischen Pullupwiederstand und einen Kondensator einzubauen. Im Anhang
> seht ihr ein Foto der Schaltung und wie ich mir die Entstöhrung
> vorgestellt habe. Macht das so Sinn?

Ja. Die internen Pull-Up Widerstände im IC sind für die meisten 
Anwendungen zu hochohmig. Wegen Funkstörungen, aber auch weil die 
Kontakte der Taster ohne gemug Last nicht lange zuverlässig  arbeiten. 
Gehe da ruhig auf 1k oder 2,2k Ohm runter.

Ich würde noch 100 Ohm in Reihe zu den Tastern ergänzen, damit der 
Entladestrom (aus den Kondensatoren) nicht die Kontakte der Taster 
überfordert.

von Peter D. (peda)


Lesenswert?

Monk schrieb:
> aber auch weil die
> Kontakte der Taster ohne gemug Last nicht lange zuverlässig  arbeiten.

Das betrifft nur Taster (250VAC/10A) für Grobmotoriker.
Übliche Steuertaster (30V/100mA) brauchen keinen Frittstrom.
Aber wie gesagt, wozu noch externe Hardware dranpappen, wenn ordentliche 
Firmware völlig ausreichend ist.
Software schreibt man nur einmal, Hardware muß man jedesmal einlöten.
Und als Lib ist das besonders komfortabel, man kann sie einfach 
einbinden und muß nicht jedesmal erneut darüber nachdenken, wie man eine 
Flanke erkennt usw.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ernst P. schrieb:
> Der Code für die Buttons ist hier:
> https://github.com/pluess/workbench-lift/blob/master/src/button.cpp

Also mit C++ werde ich wohl nie warm werden. Man braucht Stunden, um 
sich durch die ganzen Abhängigkeiten der h- und cpp-Files 
durchzukämpfen, was wann passieren soll und wo.

Das debounce prüft nur, ob zwischen 2 Aufrufen eine genügend lange Zeit 
vergangen ist. Wobei das nichtmal überlauffest passiert. Erfolgt 
dazwischen ein Überlauf, wird die Summe lastReadTime_ + DEBOUNCE_MILIS 
ganz klein und die Bedingung (fast) nie mehr wahr.

Das check wiederum prüft nur, ob nach der Zeit eine Flanke erfolgt, mag 
sie auch noch so kurz sein. Da es in der Loop permanent aufgerufen wird, 
reagiert es sogar sehr wahrscheinlich auf jede Störung.
Wie schon gesagt, eine Filterung (Test auf Plausibilität) erfolgt 
nirgends.

Ich habe mir schon was dabei gedacht, daß bei mir die Filterung mit 
einem festen Zeitintervall im Timerinterrupt (Systick) erfolgt. Somit 
ist die Entprellung vollkommen unabhängig von jeglichen 
Programmlaufzeiten. Es werden sogar Tastendrücke gespeichert, wenn mal 
andere Tasks etwas länger beschäftigt sind und dadurch die Loop 
anhalten. Es gehen also keine Tastendrücke verloren, was auch ganz schön 
nervig für den Benutzer sein kann.

Ich hatte auch erst mit nur 2 Samples gefiltert und dabei gemerkt, daß 
das noch nicht zuverlässig entprellt bzw. entstört. Daher habe ich den 
Code auf 4 gleiche Samples erweitert.

Die Idee, zu den Tasten Callbacks zu hinterlegen, ist an sich nicht 
schlecht. Nur hat man oft Mehrfachbelegungen auf den Tasten und dann 
wird der ständige Wechsel der Callbacks schnell unübersichtlich und 
fehleranfällig. Ich bevorzuge daher, daß die gerade auszuführende Aktion 
direkt im jeweiligen Kontext steht und nicht irgendwo völlig anders.

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


Lesenswert?

Ernst P. schrieb:
> Im Anhang seht ihr ein Foto der Schaltung und wie ich mir die
> Entstöhrung vorgestellt habe. Macht das so Sinn?
Nein, auch damit bekommst du irgendwelche Störungen (ohne 'h') nicht 
weg. Zumindest nicht zuverlässig. Und zeichen das nächste Mal besser 
einen Schaltplan deiner Schaltung. Du brauchst ihn sowieso, dass du in 
einem halebn Jahr noch verstehst, was du da gebastelt hast.

> Ich habe z.B. noch ein paar NE555 rumliegen.
Entprellung/Entstörung so eines Signals macht man in Software. Nicht in 
Hardware.

> Oder die Buttons mit einem ESP8266 auslesen und mit I2C Verbinden?
Abgesehen vom technischen Overkill ist das dann das Prinzip Hoffnung. 
Meinst du, die Störungen, die sich derzeit auf deinen Tasterleitungen 
finden, verschwinden dann auf dem I²C auf magische Weise?

> Ich werde die Kabel für die Buttons getrennt verlegen, ev. genügt das ja
> schon.
Bis irgendwer in der Nähe eine Lampe oder gar den Mixer einschaltet...

> So viel ich ergoogelt habe wäre es sinnvoll vor den GPIOs einen
> physischen Pullupwiederstand
Vorneweg: es ist ein Widerstand mit nur 1 'e' hinter dem 'd'.
Wenn du bisher tatsächlich nur den eingebauten sehr hochohmigen 30..50k 
Pullup verwendest, dann wäre es zumindest nötig und sicher hilfreich, 
extern einen niederohmigen im Bereich 470R..1k an den Portpin zu 
schalten.

Insofern würde dein Workaorund mit dem I²C sogar "besser" funktionieren 
als die Schaltung bisher, denn der I²C hat Pukkups zwischen 2k2 und 4k7.

Peter D. schrieb:
> Das debounce prüft nur, ob zwischen 2 Aufrufen eine genügend lange Zeit
> vergangen ist.
Richtig, der Name debounce() für diese Funktion ist absolut irreführend, 
das ist ein simples (nichtsperrendes) Delay aufwändig formuliert.

> Somit ist die Entprellung vollkommen unabhängig von jeglichen
> Programmlaufzeiten.
Wenn man mit millis() arbeitet, dann bekommt man das genausogut (wenn 
auch nicht so kompakt) hin. Nur muss man eben den Taster auch 
tatsächlich mehrfach auf den selben Wert abfragen. Und nur, wenn der 
eingelesene Wert mehrmals (3..5x) innerhalb von z.B. 40ms immer gleich 
ist, dann liegt auch wirklich ein stabiler Wert am µC-Eingang an.

von Monk (Gast)


Lesenswert?

Peter D. schrieb:
> Übliche Steuertaster (30V/100mA) brauchen keinen Frittstrom.

Habe ich bei einigten Tastern anders erlebt. Aber ich verlange nicht, 
dass jeder die gleiche Erfahrung macht.

von Rainer W. (rawi)


Lesenswert?

Peter D. schrieb:
> Erfolgt dazwischen ein Überlauf, wird die Summe lastReadTime_ +
> DEBOUNCE_MILIS ganz klein und die Bedingung (fast) nie mehr wahr.

So passiert's, wenn jemand mit Integerrechnung nicht umgehen kann und 
schnell etwas hinpfuscht.

Eigentlich ist das Problem gelöst:

Beitrag "Re: Bug durch millis() Überlauf beim Vergleichen vermeiden"

von Peter D. (peda)


Lesenswert?

Ernst P. schrieb:
> Der Code für die Buttons ist hier:
> https://github.com/pluess/workbench-lift/blob/master/src/button.cpp

Ich hab ja doch riesen Probleme, mich durch C++ durchzufitzen.
Und es wird auch nirgends kommentiert, wie der eigentliche Ablauf ist.
Ich sehe nur, daß durch die Tasten irgendwelche Callbacks aufgerufen 
werden sollen, aber dann komme ich nicht mehr weiter.

Versteht irgend jemand, wie sich die 4 Motoren mit den 3 Tasten steuern 
lassen und wo in dem ganzen Wust dieser Ablauf codiert ist?

von Dennis S. (sixeck)


Lesenswert?

Die .h Dateien kannst du für den Ablauf erstmal ignorieren.

Den Ablauf sieht man in der main.cpp ganz unten. Das Programm läuft in 
einem “loop” und prüft dauernd ob einer der Buttons gedrückt oder 
losgelassen wurde(was keine Auswirkung hat).

Wenn ein Button gedrückt wurde, wird die Funktion in Zeile 197 
ausgeführt, welche den jeweiligen Motor in eine der 3 “Richtungen” 
(vorwärts, rückwärts und aus) drehen lässt.

von Joachim B. (jar)


Lesenswert?

Peter D. schrieb:
> Also mit C++ werde ich wohl nie warm werden.
me too,
deine 10ms Timerentprellung bullet proof funktioniert auch prima am ESP!

von Peter D. (peda)


Lesenswert?

Dennis S. schrieb:
> Wenn ein Button gedrückt wurde, wird die Funktion in Zeile 197
> ausgeführt, welche den jeweiligen Motor in eine der 3 “Richtungen”
> (vorwärts, rückwärts und aus) drehen lässt.
1
void pushed(int pinNr)
2
{
3
    // LOG_INFO("touched pin:  ", pinNr);
4
    for (int i = 0; i < motorArray.size(); i++)
5
    {
6
        motorArray[i].setDirection(getDirectionFromPin(pinNr));
7
    }
8
}

Das bringt mich leider auch nicht weiter. Welche der 3 Tasten bewirkt 
was?

Wenn ich 4 Motoren mit 3 Tasten steuern sollte, würde ich das so 
implementieren:
Taste 1: toggle Motor 1, Motor 2, Motor 3, Motor 4
Taste 2: toggle PWM 25%, 50%, 75%, 100%
Taste 3: toggle Vorwärts, Stop, Rückwärts, Stop

Kann es sein, daß mit den 3 Tasten nur die Richtung und Stop für alle 4 
Motoren gleichzeitig gesetzt werden kann?

: Bearbeitet durch User
von Dennis S. (sixeck)


Lesenswert?

> Kann es sein, daß mit den 3 Tasten nur die Richtung und Stop für alle 4
> Motoren gleichzeitig gesetzt werden kann?

Ich seh in dem Code keine 3 Buttons, nur 2. Und einer davon steuert alle 
4 Motoren in die eine, der andere Button alle 4 in die andere Richtung… 
wenn kein Button gedrückt ist bleiben die Motoren stehen.

von Peter D. (peda)


Lesenswert?

Dennis S. schrieb:
> Und einer davon steuert alle
> 4 Motoren in die eine, der andere Button alle 4 in die andere Richtung…

Das hatte ich befürchtet, die Tasten erlauben keine unabhängige 
Bedienung.

Dennis S. schrieb:
> wenn kein Button gedrückt ist bleiben die Motoren stehen.

Da würde mich mal interessieren, wie das gehen soll. Beim Loslassen wird 
doch nur ein "tue nichts" Callback eingestellt:
1
void released(int pinNr)
2
{
3
    // LOG_INFO("untouched pin:  ", pinNr);
4
}

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.