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
Funktioniert :)
Gast
#1570895
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
Gast
#1634418
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
Gast
#1712860
Hallo, was ist eigentlich der Unterschied zwischen einer debouce() function und der _delay_ms() alleine
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
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
Jack schrieb: > was ist eigentlich der Unterschied zwischen einer debouce() function und > der _delay_ms() alleine >
1 | |
2 | |
> ... 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
eine Zeile kann lang sein...
Gast
#1713355
Peter schreibt: >Dann zeig dochmal diesen Einzeiler her, der auch sauber entprellt und >die Flanke auswertet der sauber entpreller kann einfach so
1 | |
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
1 | |
statt
1 | |
schreiben kann Danke nochmal im Voraus mfg Jack
Was machst du wenn deine Taste länger als 100ms prellt, oder wenn du ein Zeitkritisches Programm hast und nicht 100ms "übrig"? Gruß Fabian
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
Gast
#1808031
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 | |
2 | |
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
Gast
#1808040
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 :-)
Gast
#1808054
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
Carsten schrieb: > if(debounce(&PINB,PB1)) > ERR=1; Wenn Du Dich nicht auf den ursprünglichen Code beziehst, mach bitte nen eigenen Thread auf. 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.
Gast
#2665498
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
Hi! Du hast übersehen, dass die Variable flag als static deklariert wurde. Gruß Stefan
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
Gast
#3236321
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
Gast
#3803833
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 | |
2 | |
Gast
#3803839
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 | |
2 | |
3 | |
4 | |
5 | |
6 | |
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.
Gast
#3805555
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?
Gast
#3947979
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.
Beitrag #5244041 wurde von einem Moderator gelöscht.
Guten Abend, Wie lange dauert das Makro maximal? Lg
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
