Hallo Leute,
Ich weiß es gibt viele Tutorials zum Taster entprellen jedoch will ich
nicht blind was kopieren oder auswendig lernen sondern es selber
schreiben und wirklich durchdenken.
Meiner Meinung nach ist mein Programm genau das was es sein soll, jedoch
leuchtet die LED einfach nicht auf. Schon langsam gebe ich auf.
Könnt ihr mal drüberschauen und mir eventuelle einen Denkstoss
verpassen?
Schaltung ist nur eine LED mit Vorwiderstand auf Pin 7,mehr nicht. Bin
Anfänger und beginne eben nur mit ner LED jedoch schreibe ich immer
verschiedene Programme dafür (Ext.Interrupt, PWM,..)
Das hier wäre mein Code:
_____________________________________________
volatile int y=0,x=0,z=0;
boolean ledstatus=LOW;
void setup()
{
pinMode(2,INPUT);
pinMode(7,OUTPUT);
}
void loop()
{
y=digitalRead(2);
if(y>0)
{
x=millis();
if((millis()-x)>50)
{
if(y>0)
{
ledstatus=HIGH;
}
}
}
else if (y==0)
{
ledstatus=LOW;
}
digitalWrite(7,ledstatus);
}
____________________________________________________
Pin 2 hat einen Pull Down Widerstand.
Bin für jede Kritik dankbar.
Lg Stefan
Stefan Mayerhofer schrieb:> x=millis();> if((millis()-x)>50)> {> if(y>0)> {> ledstatus=HIGH;> }> }> }
Sieh Die mal die ersten beiden Zeilen an.
x wird der aktuelle Wert von "millis()" zugewiesen.
Unmittelbar danach wird geprüft, ob der Wert x um mehr als 50 vom
aktuellen Wert von "millis()" abweicht.
Wie soll das funktionieren? Dein µC ist nicht so langsam, daß er für
zwei unmittelbar aufeinanderfolgende Operationen mehr als 50
Millisekunden benötigt.
Komischer Weise wenn ich das Programm am Arduino so stehen lasse für
einige Zeit dann leuchte die LED iergendwann mal auf also kommt es doch
iergendwie in die if-Abfrage rein.
Ich überreisse es einfach nicht :/
> Ich überreisse es einfach nicht
Welches Arduino Modul verwendest du denn?
Wenn es eins mit im µC integriertem USB oder WLAN ist, kann das schon
sein, denn diese unterbrechen den normalen Programmablauf zyklisch um
die Schnittstellen zu bedienen.
Stefan Mayerhofer schrieb:> Komischer Weise wenn ich das Programm am Arduino so stehen lasse für> einige Zeit dann leuchte die LED iergendwann mal auf also kommt es doch> iergendwie in die if-Abfrage rein.
Vermutung: wenn millis() zwischen den 2 Abfragen überläuft.
> Vermutung: wenn millis() zwischen den 2 Abfragen überläuft.
Kann auch sein. Wenn die Variable x vom gleichen Typ wäre, wie das
Ergebnis von millis() würde der Überlauf allerdings keine Fehlfunktion
auslösen. Um das zu erklären, muss man sich ganz genau anschauen, was
die Subtraktion in diesem Fall mit den Bits anstellt.
Dietrich L. schrieb:> Vermutung: wenn millis() zwischen den 2 Abfragen überläuft.
Bzw. x. Denn es ist ja nur 16 Bit breit und vorzeichenbehaftet, also
wird es nach ca. 32 Sekunden negativ.
Dann lies den Thread, auf den ich verwiesen habe. Dort steht die Lösung.
Falls du den nicht verstehst, melde Doch hier nochmal. Dann müssen wir
nämlich ganz unten bei den allerersten Grundlagen anfangen. Die wären:
- wann und wie oft wird setup() ausgeführt?
- wann und wie oft wird loop() ausgeführt?
- was macht millis()?
- was ist der Unterschied zwischen einer Schleife und einer Bedingung?
- Welche Datentypen stehen zur Verfügung?
Das steht aber auch alles in den Arduino Tutorials, man muss sie nur
lesen. Die sind schon sehr kurz gehalten, extra für Leute, die nicht
gerne lesen.
Stefan Mayerhofer schrieb:> I know I know, für euch ist mein Problem lustig jedoch ist es für mich> zurzeit eine richtige Herausforderung :/
Du willst ja lernen, daher:
Ich empfehle, erst einmal ein Flußdiagramm zu zeichnen, wie du dir den
Ablauf denkst.
Als zweiter Schritt käme dann die Umsetzung in den Code.
Den Thread habe ich gelesen und den verstehe ich, dieser soll eine LED
zum BLinken bringen und da speichert man den millis Wert in eine
Variable und diese Variable fragt man danach ab und toogelt.
Hier kann ich ja den millis Wert nach der if-Abfrage nicht abspeichern
weil ja dieser danach viel kleiner ist als der jetzige wenn ich die
taste drücke, da komm ich ja immer wieder in die if Abfrage rein du das
Entprellen ist weg.
Genau, und deswegen kann millis() nicht kleiner werden (angesehen von
dem sehr seltenen Überlauf, der aber bei der Subtraktion zum Glück
keinen Fehler auslöst).
Du willst die LED einschalten, wenn der Taster mindestens 50ms lang
gedrückt wurde. Also:
Ich erwarte nicht, dass du ihn vollständig verstehst. Aber hoffe, dass
du etwas daraus mitnehmen kannst.
z.B: Das man sich mit komplizierten if, und ihren Bedingungen, selber
eine Frikadelle ans Knie nagelt.
> Das man sich mit komplizierten if, und ihren Bedingungen,> selber eine Frikadelle ans Knie nagelt.
Ah ja, und was finden wir in der Datei CombieTimer.h? Komplizierte if
Bedingungen! Und dann auch noch den kompletten Quelltext in der *.h, das
ist definitiv nichts, was man Anfängern empfehlen sollte.
Dann wird dort der () Operator überladen, da muss man erstmal drauf
kommen!
Der TO wollte keine fertige Klasse verwenden, sondern lernen, wie es
funktioniert.
Danke dir,
Kann ich meinen Code umschreiben, deinen verstehe ich nur teilweise.
Bei der else if Abfrage kommt ja kein (digitalRead(2)==HIGH)) , wie soll
der dann hier reinkommen.
Ich mein es funkt, habs auspobiert, jedoch hab ichs nicht zur Gänze
kapiert.
Stefan U. schrieb:> Ah ja, und was finden wir in der Datei CombieTimer.h? Komplizierte if> Bedingungen!
3 IF Bedingungen
> if(!abgelaufen)
und
> if(merker == trigger)> if(timer(entprellzeit))
Das sind drei einfache Bedingungen.
Und nicht verschachtelt.
Das ist dir also schon zu kompliziert....
Aha, ja...
Des weiteren, im Gegensatz zum Code des TE, deutlich benannte Variablen.
Stefan U. schrieb:> Und dann auch noch den kompletten Quelltext in der *.h,
Was gibts dagegen einzuwenden?
Als Arduino User hat man dauernd damit zu tun.
Viele Libs sind so aufgebaut.
Stefan U. schrieb:> Der TO wollte keine fertige Klasse verwenden, um zu lernen, wie es> funktioniert.
Sicher!
Darum sagt er ja auch:
Stefan Mayerhofer schrieb:> Hat wer eine Lösung ?
Das ist die Lösung welche ich bieten kann.
Entweder lernt er was draus, oder er verwirft sie.
Ist mir beides recht.
Übrigens, ich halte es für eine echt doofe Idee, Arduino Anfänger vor
der OOP beschützen zu wollen.
Denn:
Als Arduino User hat man dauernd damit zu tun.
Viele Libs sind so aufgebaut.
> Kann ich meinen Code umschreiben, deinen verstehe ich nur teilweise.
Offensichtlich kannst du deinen Code nicht umschreiben, weil du weder
deinen noch meinen verstanden hast. Wir helfen Sir gerne, aber dazu
musst du konkrete Fragen stellen und wenigstens die Grundlagen der
Programmiersprache gelernt haben.
> Bei der else if Abfrage kommt ja kein (digitalRead(2)==HIGH)),> wie soll der dann hier reinkommen.
Ich verstehe diesen Satz nicht. Wer soll wo rein kommen?
Was glaubst du denn, was digitalRead(2) liefert?
Und was erwartet if() zwischen den Klammern?
Welche Ausdrücke/Werte gelten als wahr?
Stefan Mayerhofer schrieb:> Bei der else if Abfrage kommt ja kein (digitalRead(2)==HIGH)) , wie soll> der dann hier reinkommen.
(digitalRead(2)==HIGH)
Ist das gleiche wie:
digitalRead(2)
Das ==HIGH ist an der Stelle flüssiger wie Wasser.
Überflüssig.
Ok also, DU fragst ab Wenn der Taster nicht gedrückt ist
(if(!digitalRead(2))
soll die Lampe aus sein. Millis wird hier dauernd in die Sperrzeit
geschrieben.
So, ich drücke nun den Taster und da häng ich wieder. Es steht niergends
eine Abfrage was ist wenn der Taster gedrückt wird. Was ich aber
verstehe ist das wenn der Taster prellt die if Abfragen nacheinander
aufgerufen werden.
Bitte erkläre mir deinen Code.
Ist doch recht einfach...
Wenn die Taste NICHT gedrückt ist, wird sich die Sperrzeit gemerkt und
die led aus gemacht.
Wenn die Taste gedrückt ist, wird geprüft, ob die 50ms abgelaufen sind,
und dann die LED angemacht.
Der Code wird auf einem UNO ca 100000 mal pro Sekunde durchlaufen.
> Es steht niergends eine Abfrage was ist wenn der Taster gedrückt wird.
Doch, das ist der "else" Teil. Und an den habe ich direkt die nächste
Bedingung angehängt.
1
unsignedlongsperrzeit=0;
2
3
voidloop()
4
{
5
if(!digitalRead(2))// Wenn die Taste nicht gedrückt ist ...
6
{
7
// Taste wurde losgelassen oder prellt
8
9
// Messung der Sperrzeit erneut beginnen
10
sperrzeit=millis();
11
12
// LED aus
13
digitalWrite(7,LOW);
14
}
15
else// ansonsten (also wenn die Taste gedrückt ist)...
16
if(millis()-sperrzeit>50)// Wenn die Sperrzeit überschritten wurde
17
{
18
// Taste wurde lange genug gedrückt
19
// LED an
20
digitalWrite(7,HIGH);
21
}
22
}
Mit if und else if kann man beliebig lange Ketten bauen.
1
if(geld<10)
2
puts("ich bin bettelarm, denn ich habe weniger als 10 Euro");
3
elseif(geld<100)
4
puts("ich kann was zum essen kaufen, denn ich habe 10 bis 99,99 Euro");
5
elseif(geld<500)
6
puts("ich kann ins Restaurant gehen, denn ich habe 100 bis 499,99 Euro");
7
else
8
puts("Es reicht sogar für ein neue Fahrrad, denn ich habe mindestens 500 Euro");
Stefan U. schrieb:> Hier müsste eigentlich if..else erkläert sein, aber irgendwie haben sie> bei if aufgehört zu schreiben.
Die C++ Grundlagen muss man aus anderen Quellen beziehen.
Würde auch keinen Sinn machen die C++ Bücher abzuschreiben und auf der
Arduino Seite zu publizieren. Denn das Netz und die Büchereien sind voll
mit C++ Tutorials.
Außerdem ist das ein Wiki System, kein Selbstbedienungsladen ohne Kasse,
da beschwert man sich nicht über Unvollständigkeit, sondern erweitert
die Doku.
Merksatz:
Kritik an anderen, schützt nicht davor, eigene Leistung bringen zu
müssen..
Stefan schrieb:
> Mit if und else if kann man beliebig lange Ketten bauen.
Gibt es denn in dieser Supersprache kein "Select-Case" Konstrukt?
Wenn hier mehr als 3 Sachen zu unterscheiden sind, beißt der
Programmierer doch zwischenzeitlich die Tastatur in Stücke.
> Gibt es denn in dieser Supersprache kein "Select-Case" Konstrukt?
Doch schon (switch-case) aber das kann nur auf Gleichheit mit Konstanten
vergleichen, nicht größer oder kleiner als.
> Wenn hier mehr als 3 Sachen zu unterscheiden sind
Nur eine Sprache, nämlich C++. Da C++ jedoch eine Erweiterung von C ist,
genügt es für den TO momentan, die Grundlagen also C zu lernen.
Nur eine Idee von mir, wie wäre dieser Code um das Prellen zu entgehen?
Tastergedrückt=DigitalRead(Pin1);
If(tastergedrückt)
{
DigitalWrite(Pin2,High);
Variable=1;
}
If (variable==1&&tastergedrückt==0)
//fals prellen auftritt und wieder auf Masse gezogen wird
{
DigitalWrite (pin2,High)
Variable=0;
}
Else
DigitalWrite(Pin2,Low);
Die variable wird ja immer wieder von 0 auf 1 und umgekehrt gesetzt
dadurch kommts mal in die eine if und mal in die andere if. Ich bin über
jede kritik dankbar, das es perfekt ist kann ich selber nicht sagen,
aber ein vorschlag wärs halt gewesen.
und ???
die while-schleife auch ... und zwar genau
solange wie du auf den knopf drückst ...
wenn dir das delay() da nicht gefällt lass es weg
und mach die zahlen in workOnKeyPress() größer
Stefan Mayerhofer schrieb:> Das hier wäre mein Code:
Da könntest du die c-Tags drumrum machen, so wie es ein paar Zeilen über
jeder Eingabebox beschrieben ist...
Stefan U. schrieb:>> Vermutung: wenn millis() zwischen den 2 Abfragen überläuft.> Wenn die Variable x vom gleichen Typ wäre, wie das Ergebnis von millis()> würde der Überlauf allerdings keine Fehlfunktion auslösen.
millis() selber hat einen unsigned long, der läuft erst nach 49 Tagen
über. Aber x ist leider nur ein 16 Bit int, da passiert der Überlauf
schon nach 65 Sekunden...
Ray M. schrieb:
1
voidtaster_isr(){
2
longintc=0;
3
noInterrupts();
4
while(digitalRead(DP_BUTTON)==LOW){
5
c++;
6
delay(30);
In einer ISR darf niemals (ich wiederhole in Worten: nie, auf keinen
Fall, garantiert nicht) ein delay() vorkommen. Nie!
Denn das sorgt dafür, dass andere Interrups nicht abgearbeitet werden
können und z.B. eine serielle Schnittstelle einfach überfahren wird.
Auch bei Timern kann es Probleme geben, wenn ihre Interrupts für solch
lange Zeit blockiert werden.
Und im speziellen Code hier wird sogar das komplette System während des
gesamten Tasterdrucks blockiert. Schlimmer gehts nimmer!
Stefan Mayerhofer schrieb:> jedoch will ich nicht blind was kopieren oder auswendig lernen sondern> es selber schreiben und wirklich durchdenken.
Eine brauchbare Entprellung ist in einem MAX6816 realisiert:
https://datasheets.maximintegrated.com/en/ds/1896.pdf
Und jetzt muss der Programmierer, der durch eigenes Nachdenken auf eine
gleich gute Lösung kommen will, einfach mal einen halben Tag über
"Figure 1. Block Diagram" grübeln und das in ein Programm umsetzen.
Wenn er es dann letztlich doch nicht hinbekommen hat und auch die vielen
andren Threads zum Thema nicht zur Erleuchtung beigetragen haben, dann
kann er ja immer noch einfach genau diesen MAX6816 kaufen und hat damit
eine zuverlässig funktionierende Entprellung in seinem System.
https://www.reichelt.de/ICs-MAX-1000-9201/MAX-6816-EUST/3/index.html?ACTION=3&GROUPID=5470&ARTICLE=148598> jedoch will ich nicht blind was kopieren oder auswendig lernen sondern> es selber schreiben und wirklich durchdenken.
Wie wäre es, wenn du die Reihenfolge von Schreiben und Durchdenken
umdrehst?
Du darfst auch gern anderen Code ansehen und analysieren. Du wirst
dann z.B. sehen, dass der geniale Code von Peter Dannegger prinzipiell
genauso funktioniert wie der obige MAX6816. Wenn du das erkannt hast,
dann bist du mit dem Denken fertig und kannst loslegen mit dem
Schreiben.
Als Denkhilfe ist recht brauchbar auch der Artikel Entprellung
> In einer ISR darf niemals (ich wiederhole in Worten: nie, auf keinen> Fall, garantiert nicht) ein delay() vorkommen. Nie!> Denn das sorgt dafür, dass andere Interrups nicht abgearbeitet werden> können und z.B. eine serielle Schnittstelle einfach überfahren wird.> Auch bei Timern kann es Probleme geben, wenn ihre Interrupts für solch> lange Zeit blockiert werden.> Und im speziellen Code hier wird sogar das komplette System während des> gesamten Tasterdrucks blockiert. Schlimmer gehts nimmer!
und ich hab gesagt dann lass den delay() einfach weg wenn er euch stört
für mich funktioniert das in 99% aller projekte, auch wenn die
isr natürlich alle anderen aktionen während das taster-drückens
blockiert, das delay() ist da gar kein problem weil eh noch
noInterrupts()
steht !!! damit passiert während des taster-drückens nix anderes mehr
und ja, die lösung mit dem max ist natürlich schöner ;)
Ray M. schrieb:> für mich funktioniert das in 99% aller projekte, auch wenn die> isr natürlich alle anderen aktionen während das taster-drückens blockiert
Alle Timer-Überläufe und sämtliche Schnittstellen und alle Interrupts.
Na toll, solche Geräte kenne ich. Für mich "funktionert" so ein
offensichtlich dahingehacktes Programm bestenfalls, wenn es für diesen
Controller nur einzig und allein um diese Taste geht und der sonst
nichts zu tun hat.
> und ja, die lösung mit dem max ist natürlich schöner
Und noch schöner ist Peter Danneggers Code, weil er zwar nicht bis 63
zählt, sondern nur bis 3, das aber parallel für 8 Tasten in 2 Bytes.
Stefan Mayerhofer schrieb:> Ich weiß es gibt viele Tutorials zum Taster entprellen jedoch will ich> nicht blind was kopieren oder auswendig lernen sondern es selber> schreiben und wirklich durchdenken.
Eine Entprellung besteht aus einem Integrator gefolgt von einem
Schmitt-Trigger.
In Software macht man dazu einen gleitenden Mittelwert über z.B. 4
Abtastungen. Das Abtastintervall wählt man größer als die Prellperiode,
aber nicht so groß, daß der Nutzer eine Verzögerung merkt (typisch
2..50ms). 4 aufeinanderfolgende Einsen werden dann als 1 interpretiert,
4 aufeinanderfolgenden Nullen als 0. Alle anderen Muster bewirken keine
Zustandsänderung. Fertig ist die Entprellung.
Ich habe es versucht Hardwaremäßig zu entprellen und es hat nicht
geklappt.
Hab auch einen Pull-Down Widerstand am Pin.
Hab parallel zum Pull Down einen 10uF Elko geschaltet und es hat sich
kaum was verändert. Hab nähmlich per Serial Print mir eine Variable
angeschaut die beim Tastendruck hinaufgezählt wird, bei einem
Tasterdruck war die Variable größer als 30 also null entprellung. Kann
ich da noch was machen, noch einen zusätzlichen Widerstand damit sich
der Elko langsamer entlädt bzw. aufladet ?
Mein Widerstand beträgt 10kOhm.
Mike1996 schrieb:> Ist mein Code also nicht vernünftig ?
Was heißt in Bezug auf Code "vernünftig"?
Er funktioniert halt einfach nicht, weil die Variable einfach um 1
Schleifenzyklus und der Ausgang asymmetrisch um 2 Schleifendurchläufe
versetzt dem Prellen folgt. Probiers aus...
Mike1996 schrieb:> Nur eine Idee von mir, wie wäre dieser Code um das Prellen zu entgehen?
Wie gesagt: am Besten vor dem Schreiben drüber nachdenken, ob das
überhaupt funktioniert?
Mike1996 schrieb:> Widerstnad 10kOhm, 10uF der Elko.
Warum ein Pulldown, wenn der uC schon einen Pullup hat?
Mit dieser Beschaltung funktionert Entprellen nur mäßig und nur, wenn
der µC Schmitttrigger-Eingänge hat.
Mike1996 schrieb:> Hab nähmlich per Serial Print mir eine Variable angeschaut die beim> Tastendruck hinaufgezählt wird
Lass mal das Programm sehen...
BTW: für (d)eine neue Frage solltst du (d)einen neuen Thread beginnen.
Und nicht den eines anderen kapern!
Mike1996 schrieb:> Widerstnad 10kOhm, 10uF der Elko.
Bei dem Konstrukt ist die Wahrscheinlichkeit sehr groß, das erstens der
Taster nicht lange hält, zweitens der Kontroller undefiniert reagiert.
Hubert G. schrieb:> Bei dem Konstrukt ist die Wahrscheinlichkeit sehr groß, das erstens der> Taster nicht lange hält, zweitens der Kontroller undefiniert reagiert.
Auch ein Brown Out Reset ist eine definierte Reaktion.
Und mit der Schaltung vermutlich sogar reproduzierbar.
Bis der Taster weg/fest brennt.
Wenn, dann:
Internen Pullup verwenden (spart einen Widerstand ein)
Kondensator kleiner, z.B. 100nF
Strombegrenzungswiderstand zwischen Taster und Kondensator.
Dann ist das eine recht stabile Hardwareentprellung.
Ok, probiere ich aus.
Lothar M. schrieb:> Warum ein Pulldown, wenn der uC schon einen Pullup hat?> Mit dieser Beschaltung funktionert Entprellen nur mäßig und nur, wenn> der µC Schmitttrigger-Eingänge hat.
Gilt das dann trotzdem ?
Peter D. schrieb:> In Software macht man dazu einen gleitenden Mittelwert über z.B. 4> Abtastungen. Das Abtastintervall wählt man größer als die Prellperiode,> aber nicht so groß, daß der Nutzer eine Verzögerung merkt (typisch> 2..50ms). 4 aufeinanderfolgende Einsen werden dann als 1 interpretiert,> 4 aufeinanderfolgenden Nullen als 0. Alle anderen Muster bewirken keine> Zustandsänderung. Fertig ist die Entprellung.
Das ist auch meine bevorzugte Variante wenn man
- keinen Timer/Interrupt verwenden will
- nur eine oder wenige Tasten hat
Ich hab es kürzlich mal so gelöst (mit den SBIT-Funktionen von PeDa) und
dem Vergleich von 8 gleichen Zuständen. Taste ist Low-Aktiv und die
Funktion liefert 1 bei gedrückter Taste. Es ist die Nachbildung eines
Schieberegisters mit der Ausgangsverknüpfung UND und NOR, die ein RS-FF
bedient.
1
uint8_tget_key()// Entprellung
2
{
3
staticuint8_tshift;// vorbesetzt vom letzten Tastendruck
4
while(1)
5
{
6
if(KEY_in==1)shift|=1;// Bit 0 setzen
7
elseshift&=~1;// Bit 0 löschen (&0xFE)
8
_delay_ms(3);
9
if((shift==0xFF)||(shift==0))return(!shift&0x01);// 8 mal hintereinander das selbe gelesen, Taste gedrückt bei LOW, get_key liefert dann '1'
Mike1996 schrieb:> So ?
Jawoll!
Genau so kann eine funktionierende Hardware Entprellung aussehen.
Aber eigentlich sind wir hier ja bei einer Software Entprellung.
Eine solche ist in den allermeisten Fällen vollkommen ausreichend, meist
erheblich billiger und flexibler was die Zeiten angeht..
Die Hardwareentprellung beginnt erst Sinn zu machen, wenn man den
Eingang per Interrupt auswerten muss. Und ohne das MUSS machen
Interrupts an der Stelle keinen Sinn.
Mike1996 schrieb:> Gilt das dann trotzdem ?
Ja, klar. Mit der ganzen RC-Bastelei wird es zwar ständig besser, aber
den eigentlichen Trick mit dem Schwellwert bringt erst ein
Schmitttrigger.
HildeK schrieb:
1
uint8_tget_key()// Entprellung
2
{
3
staticuint8_tshift;// vorbesetzt vom letzten Tastendruck
4
while(1)
5
{
Ich weiß nicht, mir gefällt dieses blockierende Programmierung nicht.
Ich mache selbst einfachste Sachen in der Hauptschleife mit z.B. einem
10ms-Flag in einem Zustandsautomaten und einem "Betätigungsdauerzähler":
- wenn die Taste nicht gedrückt ist, dann setze den Zähler zurück
- wenn die Taste gedrückt ist, dann zähle den Zähler hoch
- wenn der Zähler 5 (oder auch 10) erreicht, dann ist die Taste gedrückt
- nebenher Zähler sättigen (nicht dass ein Überlauf seltsame Dinge
bewirkt)
Das sind je nach Programmierstil 2..3 drei unabhängige Abfragen, die
sogar noch in beliebiger Reihenfolge kommen können:
1
uint8_tz=0;
2
3
for(;;){
4
:
5
if(flag_10ms){
6
:
7
if(taste_gedrueckt)z++;
8
elsez=0;
9
10
if(z>=5){
11
z=5;// Zähler begrenzen
12
// Taste entprellt und mindestens 50ms gedrückt
13
// machwas...
14
}
15
:
16
}
17
:
18
}
HildeK schrieb:> Ich hab es kürzlich mal so gelöst
Weil bei einem Linksshift eine 0 von rechts hereingeschoben wird, ließen
sich diese beiden Zeilen noch abkürzen:
1
// original
2
if(KEY_in==1)shift|=1;// Bit 0 setzen
3
elseshift&=~1;// Bit 0 löschen (&0xFE)
4
5
// kürzer
6
if(KEY_in==1)shift|=1;// Bit 0 setzen falls nötig. Default=0
Lothar M. schrieb:> Ich mache selbst einfachste Sachen in der Hauptschleife mit z.B. einem> 10ms-Flag in einem Zustandsautomaten und einem "Betätigungsdauerzähler":
In der Arduinowelt gibt es millis().
Einen weiteren Timer Interrupt für den Zweck etablieren ist nicht sehr
sinnvoll.
Also muss man mit millis() zurande kommen.
Und ja, das Entprellen erfordert einen Zustandsautomaten. Und sei er
noch so primitiv.
Lothar M. schrieb:> Ich weiß nicht, mir gefällt dieses blockierende Programmierung nicht.
Mir auch nicht.
"blockierende Programmierung" ist wie ein Stock in den Speichen.
Lothar M. schrieb:> Ja, klar. Mit der ganzen RC-Bastelei wird es zwar ständig besser, aber> den eigentlichen Trick mit dem Schwellwert bringt erst ein> Schmitttrigger.
Der hier behandelte AVR(hoffe ich doch mal) hat Schmitttriger Eingänge.
Lothar M. schrieb:> Ich weiß nicht, mir gefällt dieses blockierende Programmierung nicht.
Ich sagte ja auch: wenn ich keinen Timer verwenden will. In diesem Fall
habe ich aus Stromspargründen Timer, ADC usw. im PRR abgeschaltet. Ich
hatte keinen Arduino verwendet, wo der ggf. sowieso läuft.
In meiner Verwendung war ein 'Blockiern' überhaupt kein Thema, die
meiste Zeit ist der Prozessor eh im Tiefschlaf ...
Lothar M. schrieb:> Weil bei einem Linksshift eine 0 von rechts hereingeschoben wird> .> .> // noch kürzer> shift |= KEY_in;
Danke, du hast ja recht - schau ich mir noch an! Ich bin nicht der
Software-Profi, aber für solche Hinweise immer sehr dankbar ...
Lothar M. schrieb:> Weil bei einem Linksshift eine 0 von rechts hereingeschoben wird, ließen> sich diese beiden Zeilen noch abkürzen: // original> if(KEY_in == 1) shift |= 1; // Bit 0 setzen> else shift &= ~1; // Bit 0 löschen (&0xFE)>> // kürzer> if(KEY_in == 1) shift |= 1; // Bit 0 setzen falls nötig.Default=0>> // noch kürzer> shift |= KEY_in;
Habs mir angeschaut. Geht so nicht.
Sie entprellt zwar den Übergang von KEY_in=0 auf 1, nicht aber die
andere Richtung. Die geht nicht mal mehr, es kommt keine Null ...
Man könnte aber bei
1
staticuint8shift;
das 'static' weglassen und dafür shift mit z.B. 0xAA vorbesetzten.
HildeK schrieb:> Die geht nicht mal mehr, es kommt keine Null ...
Dann nimmt KEY_in völlig unerwarteterweise auch andere Werte als 0 und 1
an ;-)
HildeK schrieb:> das 'static' weglassen und dafür shift mit z.B. 0xAA vorbesetzten.
Das wäre sowieso sinnvoll, denn mit dem static wird evtl. gar nichts
entprellt, weil das static gespeicherte Abbild des Tasters mit der
Umwelt (und dem realen Tasterzustand) gar nichts zu tun hat.
Oder andersrum: wenn shift vom letzten Aufruf von keypress() noch 0xff
ist und wieder keypress aufgerufen wird, dann reicht theoretisch ein
einziger high Impuls (oder eine weiterhin gedrückte Taste) zum
Afragezeitpunkt um sofort wieder ein 0xff in shift zu erzeugen und die
Routine ohne jegliche Entprellzeit sofort zu terminieren.
Lothar M. schrieb:>> Die geht nicht mal mehr, es kommt keine Null ...> Dann nimmt KEY_in völlig unerwarteterweise auch andere Werte als 0 und 1> an ;-)
Nein, sicher nicht :-)
Das Problem war das links Schieben, das in meinem obigen Beispiel am
Ende gemacht wurde. Es müsste so aussehen, dann passt die gewünschte
Funktion und deine Vereinfachung:
1
uint8_tget_key()// Entprellung
2
{
3
staticuint8_tshift;// vorbesetzt vom letzten Tastendruck
4
while(1)
5
{
6
shift<<=1;
7
shift|=KEY_in;// Bit 0 setzen
8
_delay_ms(3);
9
if((shift==0xFF)||(shift==0))return(!shift&0x01);
10
}
11
}
Lothar M. schrieb:>> das 'static' weglassen und dafür shift mit z.B. 0xAA vorbesetzten.> Das wäre sowieso sinnvoll, denn mit dem static wird evtl. gar nichts> entprellt, weil das static gespeicherte Abbild des Tasters mit der> Umwelt (und dem realen Tasterzustand) gar nichts zu tun hat.> Oder andersrum: wenn shift vom letzten Aufruf von keypress() noch 0xff> ist und wieder keypress aufgerufen wird, dann reicht theoretisch ein> einziger high Impuls (oder eine weiterhin gedrückte Taste) zum> Afragezeitpunkt um sofort wieder ein 0xff in shift zu erzeugen und die> Routine ohne jegliche Entprellzeit sofort zu terminieren.
Doch, das 'static' passt schon. Es ist der Zustand, den die Taste beim
letzten Aufruf hatte. Einzig: man könnte 'shift' mit 0xFF vorbesetzen,
weil das der Zustand der ungedrückten Taste ist, was am
wahrscheinlichsten beim Start des Programms ist.
Ist der Taster losgelassen, dann ist der letzte Zustand (Taster Low
aktiv) von shift = 0xFF. Sollte die Routine wieder aufgerufen werden,
ohne gedrückten Taster, dann beendet sie sofort (nach einem Delay), weil
zu dem 0xFF - geschoben zu 0xFE - wieder eine 1 am LSB hinzugefügt
wurde. Kein Problem.
Wurde die Taste gedrückt, dann werden, wie du sagtest, automatisch auf
LSB-Seite Nullen eingeschoben, das müssen dann auch 8 Nullen
nacheinander sein. Die Routine läuft so lange, bis shift 0x00 ist und
gibt dann 'gedrückt' zurück - im besten Fall in 8 mal der Delayzeit.
Wird die Taste länger gedrückt oder länger losgelassen, dann kommt eben
bei weiteren Aufrufen der Funktion fast sofort, mit nur einer Delayzeit,
der aktuelle Zustand zurück.
Jede Störung oder Änderung, ob bei der losgelassenen oder gedrückten
Taste, müsste dann schon 8 Delayzeiten anstehen.
Ich finde, die Lösung durchaus brauchbar, wenn die 'Blockierung'
woanders keine Hemmnisse hervorruft.
Hallo Leute,
Stefan US hat mir diesen Code hier geschickt der softwaremäßig Taster
entprellt.
unsigned long sperrzeit=0;
void loop()
{
if (!digitalRead(2)) // Wenn die Taste nicht gedrückt ist ...
{
// Taste wurde losgelassen oder prellt
// Messung der Sperrzeit erneut beginnen
sperrzeit=millis();
// LED aus
digitalWrite(7,LOW);
}
else // ansonsten (also wenn die Taste gedrückt ist)...
if (millis()-sperrzeit > 50) // Wenn die Sperrzeit überschritten
wurde
{
// Taste wurde lange genug gedrückt
// LED an
digitalWrite(7,HIGH);
}
}
Nun meine Frage, wieso funkt mein Programm nicht ?
unsigned long Variable1;
boolean Variable2=0,tastergedrückt=0;
int AbfrageobPrellt=0,entprellzeit=50;
void loop()
{
tastergerückt=digitalRead(Pin2);
if(tastergedrückt)
{
Variable1=millis();
}
if ((millis()-Variable1)>entprellzeit) //entprellzeit=50ms
{
//Nach 50ms nochmal die Abfrage
if(tastergedrückt)
{
AnfrageobPrellt++;
digitalWrite(Pin1,HIGH);
}
}
if(!tasterdegrückt)
{
digitalWrite(Pin1,LOW);
}
Serial.println(AbfrageobPrellt);
Im Serial monitor wird per Tastendruck die Variable "AbfrageobPrellt"
immer um ~30mal erhöht also prellts immer noch, oder ist der uC so
schnell das er das loop 30mal durchläuft während ich kurz gedrückt habe
?
Wo könnt ich die Variable sonst hinsetzten um zu prüfen obs prellt oder
nicht ?
Der Timer soll zurückgesetzt werden, wenn der Taster NICHT gedrückt
wurde (beachte das "!").
Danach hast du das "else" ausgelassen.
Danach hast du einen weiteren unnötigen Check "if (tastergedrückt)"
eingebaut, das habe ich Dir nicht vorgeschlagen.
> AnfrageobPrellt++;
Was soll das werden?
Diese Variable soll mir im Serial monitor nur anzeigen ob der Taster
prellt, es zeigt mir beim tastendruck 30 stk davon an.
Meine Überlegung nun:
1)Ich Frage den Taster ab
2)Taster gedrückt ? Wenn Ja dann soll die Zeit mal abgefragt werden mit
millis().
3)Sind nun seit der Zeit wo das erste mal gedrückt wurde 50ms vergangen
frage ich zur Sicherheit nochmal ab ob der Taster nun wirklich NOCH
gedrückt ist.
Das habe ich als eigenes if gemacht damit es auch nach 50ms erfüllt
werden kann. Dh das Programm läuft weiter bis 50ms vergangen sind und
springt dann in die if rein.
4)Wenn ja dann leuchtet die LED und die Variable "abfrageobprellt" soll
hochgezählt werden um sie mir im Serial monitor anzuschauen.
5)Falls nicht gedrückt wird dann soll einfach die LED nicht leuchten.
Bitte erkläre mir wieso das so nicht passt und wieso die Zeit gemessen
werden soll wenn der Taster NICHT gedrückt ist, die Zeit wird abgefragt
wenn gedrückt wird danach läuft das Programm 50ms weiter und springt
erst dann in die zweite if Abfrage hineine und die LED leuchtet. Ich
raff nicht was daran falsch ist :(((
Ichn habe Dir schon erklärt, warum dein Code nicht funktioniert. Deine
if Abfragen folgen einer völlig anderen Logik, als mein Beispiel.
Wenn Du trotz Hinweis nicht verstehst, dass dein fehlendes
Ausrufezeichen und ein fehlendes "else" die ganze Logik kaputt machen,
dann kann ich Dir auch nicht weiter helfen.
Außer vielleicht mit dem Ratschlag, die Grundlagen der
Programmiersprache zuerst mit einem PC Programm (ganz ohne
Mikrocontroller) zu lernen. Und lerne auch, den Debugger zu benutzen,
denn damit kannst du Schritt für Schritt zugucken, wie das Programm
abläuft.
Lade Dir einfach mal Visual Studio runter, oder QT Creator und lerne
damit.
Ich schaff das nicht, hab vorhin sogar eine Schaltung wie im ANhang
nachgebaut mit 10k bzw.1k und 100nF (Vcc 5V). Auch dies genau 0
Besserung. Bin schon am Verzweifeln. Erfahrung habe ich im Dev-C++
gesammelt.
Habe einen Pull Up Widerstand.
Auch versucht mit Pull DOwn und auch mit Internen Pull Up und und und,
bin nur mehr am probieren aber es funktioniert einfach nicht den Taster
zu entprellen.
Habe ein ganz kleines Programm wo ich nur einen Taster abfrage, wenn der
Taster gedrückt ist gebe ich am Serial Monitor "GEDRÜCKT" aus.
So, ich drücke einmal die Taste und es steht "GEDRÜCKT" ca. 40-50mal am
Bildschirm. Keine Software und keine Hardware funktioniert bei mir.
Ich hätte schon so viele Ideen die ich weitermachen könnte, aber ich
will Ohne dieses Problem zu lösen einfach nicht weitermachen weil ich
dann ja nur herumpfusche.
Bitte gebt mir einen Lösungsvorschlag.
Stefan Mayerhofer schrieb:> Habe ein ganz kleines Programm wo ich nur einen Taster abfrage, wenn der> Taster gedrückt ist gebe ich am Serial Monitor "GEDRÜCKT" aus.> So, ich drücke einmal die Taste und es steht "GEDRÜCKT" ca. 40-50mal am> Bildschirm.
Entprellen hat mit Flankenerkennung erst mal nichts zu tun. Wenn du da
natürlich was ausgibst solange der Taster gedrückt ist, dann kommt da
natürlich solange du den Taster drückst auch was heraus.
Wenn bei 1 Tastendruck beliebiger Länge nur 1x etwas ausgegeben werden
soll, dann brauchst du zuerst eine Entprellung und danach eine
Flankenerkennung.
Stefan Mayerhofer schrieb:> oder ist der uC so schnell das er das loop 30mal durchläuft während ich> kurz gedrückt habe ?
Ja, denk mal einfach, dass er auch wenn er langsam ist, in 1 Sekunde
locker tausend Zeilen "schafft"...
Stefan Mayerhofer schrieb:> jedoch will ich nicht blind was kopieren oder auswendig lernen sondern> es selber schreiben und wirklich durchdenken.
Tu das. Es ist ein guter Ansatz.
Stefan Mayerhofer schrieb:> oder ist der uC so> schnell das er das loop 30mal durchläuft während ich kurz gedrückt habe> ?
Je nach dem, was zu tun ist, sind durchaus 100000 Loopdurchläufe/s, und
auch mehr, zu erwarten.
Um nur 30 zu erwischen, musst du schon SEHR schnell wieder loslassen.
Dir wurde die Hardware Entprellung erklärt.
Dir wurde der Umgang mit millis() gezeigt.
Dir wurde Code vorgekaut.
Und dennoch:
Stefan Mayerhofer schrieb:> Bitte gebt mir einen Lösungsvorschlag.
Eigentlich geht da nichts mehr.
Ich habe keine Antwort mehr für dich.
Außer vielleicht:
> Du musst dein Ändern leben!
Oder, wie kann ich dir helfen?
// ----
OK OK, eins fällt mir noch ein!
Die Nachtwächter Erklärung aus dem Arduino Forum.
Die beschreibt wie man zeitgesteuerte endliche Automaten baut.
Ein Entpreller ist genau ein solcher Automat.
https://forum.arduino.cc/index.php?topic=423688.0
--
Aber das schöne daran ist, wenn du diesen Bereich gefressen hast,
verstanden hast, dann hast du ein ganz wichtiges Kapitel gelernt.
Denn das Verfahren ist Grundlegend für nahezu alle deine weitere µC
Programmierung!
Immer!
Zeitsteuerung, und Automaten.