Bei der bekannten Super-Duper-Lösung haben Anfänger oft das Problem, sie
zu verstehen, da das Vertikal-Counter Prinzip nicht so offensichtlich
ist. Außerdem haben Anfänger oftmals Angst vor Interrupts.
Man sieht ja oft die abenteuerlichsten Konstrukte, die mehr rein
zufällig funktionieren. D.h. wenn man sie in weiteren Projekten benutzen
will, gibt es plötzlich das große Staunen, weil eine vermeintlich
fertige Lösung nun rumzickt.
Manchmal wird auch nur das Loslassen gemeldet. Man stelle sich mal vor,
die S-Bahn Tür würde erst bei Loslassen der Öffnungstaste öffnen. Der
Griff zur Notbremse ist damit vorprogrammiert.
Hier nun eine Lösung, die deutlich einfacher gestrickt ist, d.h. gut zu
verstehen. Daher kann sie natürlich nicht so leistungsfähig sein. Aber
die meisten Frickellösungen wird sie trotzdem weit in den Schatten
stellen.
Da sie keinen Interrupt benutzt, gibt es eine Einschränkung dahingehend,
daß sie pro Drücken und Loslassen mindestens einmal aufgerufen werden
muß, sonst geht die Betätigung verloren.
Ansonsten ist die Wirkungsweise identisch:
Man hat ein Flag, wo gemerkt wurde, ob vorher Losgelassen oder Gedrückt
erkannt wurde. Und dieses Flag entscheidet nun, ob die entgegengsetzte
Betätigung entprellt werden muß. Damit vermeidet man unnötige
Wartezeiten, wenn die Taste länger gedrückt wird.
Auch wird während der Entprellzeit 256 mal auf Preller geprüft, d.h. bei
einem Preller wird nicht die komplette Wartezeit vergeudet.
Damit muß man auch nicht so lange warten, wie bei nur einem Test, da ja
die Prellperiode (Federkonstante der Kontaktfeder) kürzer ist, als die
gesammt Prellzeit. Daher sollten 25ms ausreichen.
Sie muß als Macro definiert sein, damit auch für jede Taste eine andere
Flagvariable angelegt wird. Daher können mehrere Tasten unabhängig
entprellt werden.
Peter
Peter Dannegger schrieb:
> Manchmal wird auch nur das Loslassen gemeldet. Man stelle sich mal vor,> die S-Bahn Tür würde erst bei Loslassen der Öffnungstaste öffnen. Der> Griff zur Notbremse ist damit vorprogrammiert.
Ich habe das Beispiel mal umgesetzt (#) und beobachte, dass die LED den
Zustand erst in dem Moment ändert, wenn der Taster losgelassen wird.
Meine grundsätzliche Änderung ist hardwareseitig: Der Taster auf dem
Pollinboard ist active-high vorgegeben, d.h. externer Pull-down im
Ruhezustand und Verbindung zu Vcc im gedrückten Zustand.
Edit: Wenn ich die Logik im Makro für active high anpasse, funktioniert
das Umschalten wie erwartet direkt beim Drücken der Taste. Prima! Die
Anpassung ist jetzt auch im Wikiartikel.
(#)
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Tasty_Reloaded
Stefan B. schrieb:
> Meine grundsätzliche Änderung ist hardwareseitig: Der Taster auf dem> Pollinboard ist active-high vorgegeben
Das ist die ungebräuchliche Beschaltung, da man dann nicht die internen
Pullups benutzen kann.
Aber ich denke, das schaffst Du selber.
Ist wie beim Fernsehquiz: "Legen sie ein ! um, damit die Funktion
stimmt."
Und die Zeilen zum Enablen des Pullups müssen natürlich auch raus.
Man kann sogar das Programm so ändern, daß beide Flanken zurückgegeben
werden (als 1 bzw. 2), dazu muß nur eine Zuweisung auf "i = 2;" geändert
werden.
Peter
Ich finde es zwar schön das hier ein Beispiel für Anfänger ist aber ich
komme mit dem Macro nicht zurecht... wie macht man daraus eine Funktion
?
Ich habe das jetzt in meine "main" eingefügt und es funktioniert, würde
das Ganze aber gerne in ein Modul auslagern (tast.c und tast.h).
Das Define gehört ja dann in das .h file und der Code ja in das
entsprechende c file.
Sorry das ich nachfrage aber ich verstehe Macros noch nicht.
Du kannst das Macro in ein *.h File schreiben und dann aufrufen.
Als Macro habe ich es schreiben müssen, damit auch mehrere Tasten
entprellt werden können. Dazu muß aber für jede Taste eine extra
Flagvariable angelegt werden.
Wäre es eine Funktion, würde die Variable für alle Tasten die gleiche
sein und damit das Programm nicht funktionieren.
Ein Macro ist nur eine Textersetzung, d.h. der Macroaufruf wird durch
den kompletten Text ersetzt und damit wird bei jeder Ersetzung auch eine
neue static Flagvariable angelegt.
Daher darf man das Macro pro Taste auch nur an einer Stelle aufrufen.
Ein Macro endet am Zeilenende und deshalb müssen die Zeilen der
Macrodefinition mit dem Zeilenverlängerungszeichen '\' abgeschlossen
werden. Für den Compiler ist das alles also nur eine einzige Zeile.
Ein "return" darf man im Macro nicht verwenden, es würde sich auf den
Aufrufer beziehen, d.h. das Main würde verlassen.
Ein Macro hat aber einen Wert, wie jeder C-Ausdruck und das ist der Wert
der letzen Anweisung. Deshalb das "i;" am Ende.
Ansonsten verhält sich ein Macro wie eine Inline-Funktion.
Peter
if( --i == 0 ){
flag = 1;
i = 1;
break;
Kann mir bitte jemand erklären, wann diese if-Bedingung wahr wird? i ist
doch vorher immer Null und die Bedingung wird doch erst wahr, wenn i=1
ist, oder hab ich da was falsch verstanden?
Danke
Eine 8Bit Variable erreicht nach 256 mal runterzählen wieder 0.
Man könnte auch zu Anfang "i = 255;" schreiben, der eine
Schleifendurchlauf weniger spielt hier keine Rolle.
Peter
/* Anwender Zeit zum Loslassen des Tasters geben */
11
_delay_ms(50);
12
_delay_ms(50);
13
return1;
14
}
15
}
16
return0;
17
}
Beispiel:
debounce(&PIND, PD2);
if(!(PIND & (1<<PIND2)))
{
test();
}
mann hätte ja auch sowas schreiben können
if(!(PIND & (1<<PIND2)))
{
test();
_delay_ms(1000);
}
denn braucht der Compiler in dem Fall nicht mehr die debounce Funktion,
um auf die delay header zugreifen.
anderes formuliert was ist der Nutz von so eine Funktion, wenn man das
gleiche mit einer Zeile erzielen kann
Danke im Voraus
Jack
> ...
Dieses debounce() hat nicht im entferntesten Ähnlichkeit mit meiner
Funktion.
Es verlangt, daß genau darin innerhalb 100ms losgelassen wird.
Sobald Deine Programme auch nur ein Quentchen größer werden und nicht
ständig im debounce() rumtrödeln können, werden Dir massiv Tastendrücke
verloren gehen.
Außerdem werden ständig dem Main 100ms CPU-Zeit geklaut, solange eine
Taste gedrückt ist.
> Beispiel:> debounce(&PIND, PD2);> if(!(PIND & (1<<PIND2)))> {> test();> }
Das ist völliger Quatsch, wo hast Du das her?
So darf mein Debounce nicht aufgerufen werden und es fehlt die
Auswertung des Returnwertes.
Und danach den Pin nochmal direkt einzulesen, macht das Entprellen ja
wieder zunichte.
Schau Dir doch bitte erstmal meinen Beispielcode an, da ist es richtig.
> anderes formuliert was ist der Nutz von so eine Funktion, wenn man das> gleiche mit einer Zeile erzielen kann
Dann zeig dochmal diesen Einzeiler her, der auch sauber entprellt und
die Flanke auswertet.
Peter
Peter schreibt:
>Dann zeig dochmal diesen Einzeiler her, der auch sauber entprellt und>die Flanke auswertet
der sauber entpreller kann einfach so
1
_delay_ms(100);
sein, so dass man nicht x-mals nach einem Zustand abfragen braucht
>Dieses debounce() hat nicht im entferntesten Ähnlichkeit mit meiner>Funktion
ja vielleicht habe ich meine Frage falsch formuliert, der Sourcecode,
und die Beschreibung stammen aus der
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Tasten_und_Schalter
und ich kann nicht verstehen warum man sich die mühe macht und die
Enprellfunktion schriebt, wenn man an jedem Gebrauch des Entprellens
einfach
Probier einfach mal das gleiche zu erreichen, wie mein Beispielcode:
Du hast 2 Tasten und 2 LEDs. Jede Taste muß ihre LED umschalten, egal
wie lange gedrückt wird und ob die andere Taste gedrückt ist.
Das wirst Du mit Deinem Delay nicht schaffen. Delay und Entprellen sind
2 völlig unterschiedliche Dinge.
Du wirst Dich bestimmt auch schon über Geräte mit schlechtem Entprellen
geärgert haben.
Nur weil andere schlecht programmieren, braucht man noch lange nicht
selber schlecht programmieren.
Peter
Moin Jungs. Ich habe eine einfache Frage. Ich möchte eine Überprüfung
machen, ob an einem Digitaleingang eine Spannung anliegt. Ich prüfe
allerdings nur, ob keine Spannung anliegt. Dann wird ein ErrorFlag
gesetzt. Jetzt muss ich beim Aufruf der Funktion nicht mehr
1
if(debounce(&PINB,PB1))
2
ERR=1;
aufrufen, sondern das invertierte von PB1,weil die Flag ja nur gesetzt
werden soll, wenn nichts anliegt. Wie kann ich PB1 invertieren, bzw was
muss ich übergeben beim Aufruf?
Grüße und Danke
Ich weis ja nicht warum immer no ein Umstand für getrieben wird einen
Taster zu entprellen... das geht mit nem Widerstand und einem
Kondesnator deutlich einfacher
:-)
ich schrieb:> Ich weis ja nicht warum immer no ein Umstand für getrieben wird einen> Taster zu entprellen... das geht mit nem Widerstand und einem> Kondesnator deutlich einfacher
Das ist richtig - vor allem für den Hobbybastler, bei dem Platinenfläche
und Kosten eine eher untergeordnete Rolle spielen. Wenn du allerdings an
ein kommerzielles Produkt denkst, das zig mal gebaut wird, summieren
sich die Mehrkosten für die größere Platine und die RC-Kombination und
irgendwann spielt das u.U. eine Rolle.
Außerdem ist die Software-Lösung flexibler: dort änderst du ein paar
Parameter und kannst so das zeitliche Verhalten beeinflussen - bei der
Hardwarelösung musst du dazu schon zum Lötkolben greifen.
Oder denk an ein Projekt mit vielen Tastern/Schaltern: willst du
wirklich alle Rs & Cs bestücken müssen? Bei einer Tastatur wären das
immerhin über 200 Bauteile.
ich schrieb:> Ich weis ja nicht warum immer no ein Umstand für getrieben wird einen> Taster zu entprellen...
Wo siehst Du da einen Umstand?
Einfach nur nen bewährten Code benutzen, sich freuen und gut is.
Umständlich ist immer nur, einem Anfänger zu erklären, das Entprellen
nötig ist und das ein stumpfes Delay kein Entprellen ist, sondern nur
die CPU stark belastet.
> das geht mit nem Widerstand und einem> Kondesnator deutlich einfacher> :-)
Stimmt, damit kackt dann die CPU deutlich einfacher ab, siehe
Pollin-Board:
Beitrag "Pollin AVR Board Fehler beim drücken der Taster / Qualität der Bauteile"
Funktionieren ist was anderes.
Peter
Ist das wirklich so ein Anfängerproblem?
Ich kann mich eigentlich auch als µC Anfänger bezeichnen. Gut, ich
konnte davor schon programmieren und ich kannte mich auch mit elektronik
und so aus.
Trotzdem habe ich für bei meiner Entprellmethode keine Probleme gehabt.
Also bei meiner wird nur x mal gezählt ob eine Taste auch die x Zyklen
gedrückt ist. Bei Prellungen wird von vorne angefangen. Braucht man
einen Zustand erst nach Loslassen wird das im entsprechenden Code dann
direkt geregelt.
Ich weiß nicht was daran schwer sein soll.
Hallo,
ich bin neu hier und ein echter Rookie, "muss" mich aber aufgrund einer
Studienarbeit mit der ganzen µC-Thematik befassen und ein bisschen
programmieren (es macht an sich Spaß, ist nur echtes Neuland), unter
anderem eben einen Taster inkl. Entprellung.
An dem debounce-Makro versteh ich größtenteils alles, bis auf die
if(flag)-Abfrage.
flag ist ja am Anfang 0, d.h. es wird direkt else abgearbeitet. Aber
selbst dann, wenn der Taster also die 25ms gedrückt bleibt und flag=1
gesetzt wird, so wird doch das Makro beendet und eine 1 zurückgegeben,
oder? Das wiederum heißt doch, dadurch dass bei erneutem Aufrufen des
Makros flag wieder 0 gesetzt wird, dass die if(flag)-Abfrage nie true
ist und nie abgearbeitet wird ... wozu ist diese dann da?
Oder hab ich da ordentlich was übersehen?
Sorry, ich weiß auch, dass der Thread schon alt ist, aber die Frage
kommt mir leider erst 2012;)
Dank euch!
Beste Grüße
heißt das, dieses macro erstellt mir für jeden Aufruf mit einem andere
Taster eine neue static flag oder wie ist das gemeint mit: ich muss für
jeden taster eine neue flag verwenden?
Grüße
Hallo,
Makros werden vor den Compilieren (durch den PreProcessor) ersetzt. Also
an der Stelle wo das Makro aufgerufen wurde, steht anschliessend das
Makro selber (der Code des Makros). Static vor einer Funktions-Varibale
bedeutet, dass die Lebensdauer global ist. Soll heissen, wird die
Funktion verlassen und in der Variable steht ein 123, dann steht dieser
Wert auch noch drinn, wenn die Funktion erneut aufgerufen wird. Die
Initialisierung der Variable findet nur bei der Deklaration statt.
Ich finde die Zählmethode auch nicht schlecht, habe aber zu wenig
Erfahrung zu diesem Thema.
Patrick
Hallo ich habe eine Frage zu dem Code.
ich denke ich habe den Code verstanden, aber eine Zeile kommt mir
komisch vor:
Das Flag ist zur internen Verarbeitung, ob die Taste vorher gedrückt
war, oder ob sie nicht gedrückt war. - das wird nicht nach "aussen"
gegeben.
In der main wird praktisch nur das "i" ausgewertet (0=key release
debounced und 1=key pressed debounced)
Für den Fall die Taste war nicht betätigt und ist nun betätigt und
entprellt gibt mir die funktion i=1 zurück und das flag ist 1 (wenn die
Taste prellt, ist i=0 und die schleife wird mit break unterbrochen)
Für den Fall die Taste war betätigt und ist nun nicht betätigt und
entprellt gibt mir die funktion i=0 zurück und das flag ist 0 (wenn die
Taste prellt, ist >>>i=0<<< und die schleife wird mit break
unterbrochen)
sollt beim prellen dann nicht das i=1 sein? oder habe ich nur einen
Denkfehler?
1
if((port&1<<pin)){/* ... until key pressed or ... */ \
Tobi schrieb:> if( (port & 1<<pin) ){ /* ... until key pressed or ... */ \> i = 0; <-- sollte hier nicht i=1 stehen? /* 0 = bounce */
Ups, hier ist ein ! verloren gegangen.
ich meine die Stelle bei if (flag):
1
if(flag){/* check for key release: */ \
2
for(;;){/* loop ... */ \
3
if(!(port&1<<pin)){/* ... until key pressed or ... */ \
Tobi schrieb:> sollt beim prellen dann nicht das i=1 sein?
Nein.
1 bedeutet Ereignis "Drücken" und das passiert nur an einer einzigen
Stelle.
Man kann auch das Ereignis "Loslassen" und die Zustände "Gedrückt" und
"Losgelassen" zurückgeben. Das müssen dann natürlich 4 verschiedene
Werte sein.
OK,
ich habe das so interpretiert:
für den Fall Flag = 1: (Taster ist gedrückt)
- Der Taster wird losgelassen und prellt: das Makro gibt eine 0 zurück
(bounced)
- Der Taster wurde losgelassen und ist mitllerweile entprellt: das Makro
gibt auch eine 0 zurück (key released debounced)
Wie kann ich nun den Zustand bounced und debounced unterscheiden?
Hallo,
ich beschäftige mich mal wieder nach ein paar Jehren Pause mit C und
AVR-Chips. Da ich eine Programm-Code für das Entprellen gesucht habe,
bin ich auf diesen Artikel gestossen. Ich weiss, das es normal ist. das
der Code mit englischen Kommentaren versehen ist. Ich hatte auch
Englisch in der Schule( zu DDR-Zeiten aber max 2h in der Woche), aber
das macht es als Neueinsteiger nicht einfacher. Damit ich den Code
besser verstehe, habe ich ihn mal in ein Flussdiagramm umgesetzt -> und
schon war mir das Prinzip klar. Als Hilfe für andere möchte ich das
Diagramm hier zur Verfügung stellen.