Einen wunderschönen Guten,
nachdem ich gerne hier auf der Suche nach Hilfe in den bereits
geschriebenen Beiträgen fündig geworden bin, dachte ich, es wäre mal
Zeit, dass ich selber auch mal was schreibe. ;)
Ich bin noch ziemlich neu, was das Programmieren von uC angeht. Bisher
schlage ich mich meiner Meinung nach ganz gut, aber ich muss wohl noch
eine Menge Trickse und Kniffe lernen. Wie z.B. das Entprellen. Davon
gibt es ja reichlich Beiträge, aber so richtig verstehen konnte ich noch
keinen. Weswegen ich mir dann gesagt habe, dass ich dann keine
Codeschnipsel kopieren werde, sondern selber versuchen werde, was
Funktionierendes zu kreeiern.
Nun habe ich da was gebastelt, was funktioniert. Aber ich vermute dabei
auch ein Problem: Nämlich das, dass der uC sich deswegen nach einigen
Minuten (es sind so knapp 5 davon) aufhängt, und nicht mehr reagieren
möchte. Es muss meine Entprellroutine sein, weil sonst nichts Anderes im
Programm passiert.
Ich benutze einen PIC 16F876 mit nem 4MHz Quarz. Da Interrupts und Timer
besetzt sind, polle ich die Tastenabfrage, was ich folgendermaßen
realisiert habe: In einer kleinen Schleife wird nachgeschaut, ob eine
Taste gedrückt wurde. Die Schleife zählt rückwärts. Gegenläufig läuft
ein weiterer Zähler. Ist während der ganzen Schleifenabfrage eine Taste
dauerhaft gedrückt worden, so erreicht der zweite Zähler den Anfangswert
des Schleifenzählers. (Prellt die Taste, wird der zweite Zähler wieder
auf Null gesetzt.) Somit gilt die Taste als gedrückt, und es darf was
ausgeführt werden.
Das Ganze funktioniert prima, die Tasten werden damit prima entprellt,
Tastendruck und Loslassen der Taste werden erkannt, die Ausführungen
werden dann gemacht. Nur eben nach schätzungweise 5 Minuten (ich drücke
keine Taste und es trifft auch sonst kein Ereignis ein) bleibt alles
stehen. Hat jemand eine Idee?
Danke!
Wie stellst du fest, dass das Programm sich aufgehängt hat?
Was passiert denn, wenn du die Tasten nicht entprellst?
Abgesehen natürlich davon, dass dann die Tasten prellen ;-)
Aber du drückst dann ja auch keine Taste...
Du kommst übrigens in das zweite
> if(debounce_state == debounced)
auch rein, wenn nicht alle Tasten losgelassen sind. Denn debounce_state
wird vor der dem "Entprellen Loslassen" nicht mehr auf 0 gesetzt.
Aber insgesamt ist das schon recht kreativ programmiert: ein Zähler, der
runterzählt, damit ein anderer Zähler hochgezählt werden kann...
Hi Lothar. Vielen Dank für die Lobpreisung meiner Kreativität. Ich tue
mein momentan Bestes. :) Aber es funktioniert zufriedenstellend.
Nun, in der weiteren Ausführung zeige ich Ziffern in einer LCD an. Bei
Tastendruck ändert sich die (angezeigte) Zahl, und nach knapp 5 Minuten
halt nicht mehr. Auch eine LED, die den Tastendruck anzeigt leuchtet
nicht mehr auf.
Ja, dass das zweite
1
>if(debounce_state==debounced)
immer arbeitet, habe ich auch grad bemerkt... Ich habe mal das
Entprellen nach Loslassen komplett in den ersten Ausführungezweig
hineingepacktaber das klappt nicht. Ich füge noch eine Variable namens
keypressed hinzu, die beim ersten debounce auf 1 gesetzt wird. Das
zweite Entprellen wird dann nur ausgeführt wenn keypressed, und darin
wird keypresssed wieder auf Null gesetzt.
--- Nö, das half auch nicht. Im Gegenteil: Jetzt muss ich keine 5
Minuten warten... (!?)
Oh, es scheint doch daran gelegen zu haben. Wenn ich keine Taste drücke,
verschwindet debounce_state wohl irgendwann ins Nirwana, und keine
meiner Abfragen trifft dann für weitere Ausführungen zu. Oh je, das Auge
dafür muss ich noch entwickeln. Ich sitze schon seit einer Woche daran,
und erkenne das Problem erst jetzt, wo ich es poste. Sorry, das Board
mehr oder weniger zugemüllt zu haben. :)
Für die, die es interessiert mit Problembehebung:
Was halten denn Profis sonst noch von meiner Entprellroutine? Was ist
gut und was nicht so gut daran? Wo kann es bei meiner Lösung zu
Problemen kommen?
Grüße
Tihomir Tomsic wrote:
> Was halten denn Profis sonst noch von meiner Entprellroutine?
Garnichts, da ich nirgends eine Entprellroutine sehe.
Deine Schleifen dürften wenige µs dauern, ein Taster prellt aber im
ms-Bereich.
Warscheinlich erfolgt das Entprellen nur durch die Ausführungszeit der
nicht sichtbaren "//DANN WIRD HIER WAS AUSGEFÜHRT"-Teile.
> Ich benutze einen PIC 16F876 mit nem 4MHz Quarz. Da Interrupts und Timer> besetzt sind,...
Wenn man es nicht zu ungeschickt anstellt, kann ein Timerinterrupt viele
zeitgesteuerte Funktionen ausführen.
Peter
Ja ich seh das auch wie Peter.
Du solltest einen Timer aufsetzten. Z.B. für 10ms und dort die Taster
entprellen. Dann hast du eine definierte Entprellzeit.
Weißt du denn, wann deine While-Loop aufgerufen wird und wie lange die
dauert?
Hi Ihr zwei,
danke für Eure Beiträge. Das mit dem Timer führt zu den
Entprellroutinen, die ich bisher nicht ganz nachvollziehen konnte.
Meine Theorie basiert darauf:
Ich möchte erkennen, ob eine Taste gewollt gedrückt wurde. Ich frage in
der "while (debounce_loop--)" 150 Mal ab, ob eine der Tasten betätigt
wurde. Für jedes TRUE inkrementiere ich "debounce_state". Lag kein
Prellen vor, so werde ich 150 Mal ein TRUE erhalten haben, ich betrachte
die betätigte Taste als gedrückt, und gebe die dazugehörige Ausführung
frei.
Liegt ein Prellen vor, werde ich dabei sicherlich mindestens ein FALSE
erhalten, "debounce_state" kann folglich den Wert 150 nicht erreichen
("debounce_state" setze ich für den Fall zusätzlich zurück). Erst bei
(evtl. mehreren) erneuten Durchläufen des Hauptprogramms (und somit der
"while (debounce_loop--)"-Schleife) wird dann die Taste als gedrückt
erkannt, weil "debounce_state" irgendwann nur durch gewolltes Betätigen
den Wert 150 erreichen kann.
Das ist dann quasi meine Entprellung: Erst wenn die 150 komplett voll
gemacht wurden, gibt's grünes Licht, notfalls oder auch gezwungenermaßen
nach mehrmaligem Durchlaufen des Hauptprogramms. Mein Hauptprogramm ist
sozusagen ein virtueller Zähler, der sich selbstständig zurücksetzt. s
Zum Timing:
Meine "while (debounce_loop--)"-Schleife beobachtet min. 75 us lang
((150 + x) * 1/(2MHz)), ob ein gedrückter Zustand erkannt wird. Wobei x
noch die mir unbekannte Anzahl der Maschinenzyklen ist, die durch die
Tastenabfrage und das Inkrementieren von "dbounce_state" produziert
wird. Ich schätze mal, dass dadurch 600 us vorliegen, wenn ich je Taste
und für die Inkrementierung einen Maschinenzyklus berechne. In dieser
Zeit sollte jedes Entprellen vorüber sein (bei meinen Tastern sind es im
allerhöchsten Höchstfall 200 us, üblicherweise 30-40).
Mein Hauptprogramm ist recht klein, so dass ich keine Angst haben muss,
dass möglicherweise ein Tastendruck nicht erkannt wird, weil diese
außerhalb der "while (debounce_loop--)"-Schleife betätigt wurde. Im
Gegenteil, ich muss noch ein Ausgeführt-Flag setzen, damit beim erneuten
Durchlaufen des Hauptprogramms die Ausführung nicht wiederholt
aufgerufen wird.
Rein theoretisch gibt es da auch kein Problem: Mein Hauptprogramm mit
allen Unterprogrammausführungen müsste das einmalige Ausführen des
Hauptprogramms auf mindestens 20-50 ms ausdehnen, weil sogar der
schnellste Finger die Taste nicht kürzer drücken kann. Und das tut es
nicht. Lediglich hier muss der Anwender (ich in diesem Falle) dafür
Sorge tragen, dass er keine Warteschleifen von mehreren Millisekunden im
Programm hat.
Hmm, ein wenig umständlich, nech? ;) Ich werde mal bei Zeiten mir das
mitm Timer nochmal genauer angucken.
>Ich möchte erkennen, ob eine Taste gewollt gedrückt wurde. Ich frage in>der "while (debounce_loop--)" 150 Mal ab, ob eine der Tasten betätigt>...>gewolltes Betätigen>den Wert 150 erreichen kann. Das ist dann quasi meine
Genau so ist der Ablauf einer Entprellung. NUR dass das Timing der
Timer macht. zB alle 10ms wird jede Taste geprüft, dann wird entweder
der Tasten-spezifische Zähler auf Null oder eins hoch gesetzt.
Bei zb 15 (=150ms) wird das als "gedrückt" erkannt...
Naja, mein Programm stützt sich auf die Tastenabfrage. Es soll nur bei
Tastendruck etwas passieren. Somit polle ich sie bei jedem Durchlauf, da
das Programm im Falle des Nicht-Tastendrucks nichts anderes zu tun hat.
Da brauche ich dann nicht noch Timer abzufragen. Das Programm gibt mir
sozusagen das Timing vor: Unkritisch bei mir, da in meinem Falle im
Mikrosekundenbereich, im Höchstfall (bei Ausführungen nach
Tastendrucken) im sehr kleinen Millisekundenbereich ist.
Sicher könnte ich da trotzdem mit Timing arbeiten, um den uC auch
schlafen zu schicken, wg. Stromverbrauch. Aber das kommt später mal. :)
>Das Programm gibt mir sozusagen das Timing vor:
Und das ist Murks. Genau das gibt dir Probleme, wo du ewig suchst und
nie genacu nachvollziehen kannst, warum was mal sporadisch auftritt.
Machs einfach gleich richtig und lerne die Algorithmen (hier mit Timer)