Hallo, ich habe ein 2x16 LCD-Display und 5 Taster zum Steuern und möchte dafür ein Menü schreiben. Wenn ich den mittleren Taster drücke, so wird ein Interrupt ausgelöst und in der Interruptfkt wird die Funktion "show_menu" aufgerufen, die die ersten beiden Zeilen meines Menüs auf dem Display anzeigt. Nun habe ich den anderen Tastern auch noch Funktionen zugewiesen und zwar -Scroll UP -Scroll DOWN -Enter + Cursor RIGHT -Cursor LEFT Die Abfrage, was der Anwender tun möchte wollte ich so lösen (for-Schleife zum Entprellen): if(DOWN){ for(i=0;i<255;i++){} if(DOWN){ menue_scroll_down(); } } if(UP){ for(i=0;i<255;i++){} if(UP){ menue_scroll_up(); } } if(ENTER){ for(i=0;i<255;i++){} if(ENTER){ subMenue_Enter(); } } Mein Problem ist es nun, wie ich auf die Eingabe des Anwenders warte. Ich habe schon alles in eine for-Schleife gesteckt, die hochzählt, aber das geht viel zu schnell und funktioniert nicht. Wie löst man den soetwas professionell? Ich meine, der Mikrocontroller soll doch auch nicht die ganze Zeit warten, bis vielleicht irgendwann der Anwender eine Eingabe macht.
> Ich meine, der Mikrocontroller > soll doch auch nicht die ganze Zeit warten, bis vielleicht irgendwann > der Anwender eine Eingabe macht. Doch. Genau das soll er. Schau mal hier. http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29 Die Funktionen sind perfekt geeignet um Eingaben damit zu machen.
Danke für das Tasten entprellen, aber ich habe mich woll etwas ungünstig ausgedrückt. Wenn nun mein externer Interrupt kommt und das Display das Menü anzeigt, dann möchte ich ja wissen, ob der Anwender UP, DOWN oder ENTER drückt. Wie mache ich das? Wenn ich die if-Abfragen in die Interruptroutine schreibe, dann funktioniert es ja nicht, da ja kein Mensch mit dem nächsten Takt schon eine Taste gedrückt hat. Jetzt verständlich? Mir geht es nicht um das Warten bei der Tastenentprellung, sondern um das Warten auf die Eingabe des Anwenders. DANKE!
du brauchst irgendwo eine Endlosschleife in der du die Tasten abfragst(das ändert nichts an der Tatsache das die Entprellroutinen bei deiner Anwendung sinnvoll wären). In diesem Fall müsstest du dir in der Schleife in einem Flag merken,dass Menu gedrückt wurde und entsprechend bei weiteren Eingaben vorgehen. Gruß
Stefanie wrote: > Danke für das Tasten entprellen, aber ich habe mich woll etwas ungünstig > ausgedrückt. > > Wenn nun mein externer Interrupt kommt und das Display das Menü anzeigt, > dann möchte ich ja wissen, ob der Anwender UP, DOWN oder ENTER drückt. > > Wie mache ich das? Wenn ich die if-Abfragen in die Interruptroutine > schreibe, dann funktioniert es ja nicht, da ja kein Mensch mit dem > nächsten Takt schon eine Taste gedrückt hat. > > Jetzt verständlich? Mir geht es nicht um das Warten bei der > Tastenentprellung, sondern um das Warten auf die Eingabe des Anwenders. > Schau dir das Demo zu der Entprellroutine an! Da ist alles drinn was du für deine Anwendung brauchst. > dann funktioniert es ja nicht, da ja kein Mensch mit dem > nächsten Takt schon eine Taste gedrückt hat. Bruacht er auch nicht. Das zentrale Element ist die Endlosschleife. In der Endlos- schleife fragst du ständig eine Taste nach der anderen ab, ob sie gedrückt wurde. Wenn ja, machst du die Aktion Um das Erkennen des Drückens der Tasten kümmern sich die Entprellroutinenen von PeDa. Darum, dass jedes Tastendruck (selbst wenn sie eine halbe Stunde gedrückt wird) nur einmal erkannt wird, kümmern sich die Entprellroutinen von PeDa. Um den Autorepeat (wenn eine Taste länger gedrückt wird, melden die Funktionen regelmässig, dass die Taste schon wieder gedrückt wurde) kümmern sich die Routinen von PeDa. Die paar Funktionen können alles, was du brauchst um damit eine Tastenauswertung zu machen. Und im Demo wird auch gezeigt wie das geht. Also schaus dir an.
Und das ... > Wenn ich den mittleren Taster drücke, so wird ein Interrupt > ausgelöst und in der Interruptfkt wird die Funktion "show_menu" > aufgerufen .. solltest du gar nicht machen. Tasten legt man auf keinen Interrupt. Deine Haupschleife ist mit den Entprellroutinen so simpel wie:
1 | unsigned char MenuOnScreen; |
2 | |
3 | ....
|
4 | |
5 | MenuOnScreen = 0; |
6 | |
7 | while( 1 ) { |
8 | |
9 | if( get_key_press( 1<<KEY0 )) { |
10 | MenuOnScreen = 1 - MenuOnScreen; // Menu anzeigen/verbergen |
11 | |
12 | if( MenuOnScreen ) { |
13 | // das Menue anzeigen
|
14 | }
|
15 | else { |
16 | // das LCD löschen
|
17 | }
|
18 | }
|
19 | |
20 | if( MenuOnScreen ) { // wenn das Menue aktiv ist, werden |
21 | // auch die anderen Tasten ausgewertet
|
22 | |
23 | if( get_key_press( 1<<KEY1 )) { // Cursor links |
24 | // Cursor nach links
|
25 | }
|
26 | |
27 | if( get_key_press( 1<<KEY2 )) { // Cursor rechts |
28 | // Cursor nach rechts
|
29 | }
|
30 | |
31 | if( get_key_press( 1<<KEY3 )) { // Cursor up |
32 | // Cursor nach oben
|
33 | }
|
34 | |
35 | if( get_key_press( 1<<KEY1 )) { // Cursor down |
36 | // Cursor nach unten
|
37 | }
|
38 | }
|
39 | }
|
OK, danke nun verstehe es auch ich! Nur, warum legt man auf Tasten keinen Interrupt? Ich wollte es so machen, damit die ganze Zeit etwas anderes getan werden kann und wenn der Interrupt kommt, dann soll sich überhaupt erst mal ums Display gekümmert werden. Nun gut, wenn ich nun die obere Routine verwende, kann ich dann die if-Schleifen die z.B. Temperaturen überprüfen, mit da rein schreiben. NOCHMAL VIELEN DANK!!
die paar Abfragen in der Schleife kosten "keine" Zeit. Der Controller kann auch so noch jede menge andere Sachen machen, die du dann in die Endlosschleife integriegen musst.
Hallo, > Nur, warum legt man auf Tasten keinen Interrupt? Weil Du dann das ganze Prellen Deiner Tasten als Interruptaufrufe bekommst und das können je nach Kontaktart ziemlich viele sein. Besser ist es einen Timer-Interrupt wie im Beispiel von PeDa zu nehmen, da Du dann in festen Zeitabständen den Zustand der Tasten abfrägst und das ganze Prellen der Tasten ausgeblendet wird. > Nun gut, wenn ich nun die obere Routine verwende, kann ich dann die > if-Schleifen die z.B. Temperaturen überprüfen, mit da rein schreiben. Wenn Du obiges Beispiel übernimmst, musst Du alles was Du tun willst in die while Schleife reinpacken, da diese endlos läuft und nie mehr (regulär) verlassen wird. Evtl. kannst Du auch Sachen (z.B. Temperatur prüfen) in den Timerinterrupt verlagern. Dies ist für Routinen interesant, die nur selten, aber trotzdem regelmässig ausgeführt werden sollen. Aber beachten, dass diese Programmteile nicht zu aufwendig sind -> Also ein paar if-Abfragen und Zuweisungen ja, Ausgaben auf die RS232 nein. Gruß Ray
Sorry, wenn ich nochmal störe. Ich habe die Entprellfunktion des obigen Links auf meinen Controller gespielt, um die Funktion get_key_press() zu testen. Es funktioniert alles soweit ganz gut, nur nicht, wenn ich zweimal hintereinander die gleiche Taste drücken möchte. Auch wenn ich dazwischen lange warte. Warum funktioniert das nicht? Ich bräuchte das für meine Anwendung! DANKE
Zeig mal dein Programm. An den Funktionen liegt es nicht, die hab ich selbst im Einsatz und gehen tadellos.
Danke, das wäre super. Ich habe einen Atmega128 mit 14.7456MHz Quarz. Diese Definitionen stehen in dem Header-File #define UP (PINA & 1<<PINA0) #define DOWN (PINA & 1<<PINA3) #define LEFT (PINA & 1<<PINA2) #define SHOW (PIND & 1<<PIND2) #define ENTER (PINA & 1<<PINA1) /* RIGHT */ Wie gesagt, manchmal funktioniert der Tastendruck richtig, aber ich kann nie zweimal hintereinander eine Taste drücken.
Mein Ansatz : im Main eine Statusmaschine. Mit dem Timer werden die Tasten entprellt und des Status des Menues veraendert. Gewartet wird nirgends. Die Statusmaschine verarbeitet Events und produziert Actions. Z.
Deine Interrupt Overflow Zeiten sind etwa um einen Faktor 3.6 zu lang. Warum hast du denn die Berechnung TCNT0 = (u8)(s16)-(XTAL / 1024 * 10e-3 + 0.5); // preload for 10ms rausgeschmissen? Aber das kanns eigentlich nicht sein. Ich hab jetzt keinen AVR hier, auf der ich dein Pgm mal laufen lassen könnte. Ich werd am Abend mal dein Pgm auf meinen Mega16 (hab leider keinen 128er) spielen und schauen ob man da was sieht. So offensichtlich fällt mir nichts auf. Das ist das Pgm aus dem Artikel ergänzt um LCD Funktionen und angepassten Clock Settings für den Mega128. Tut mir leid, dass ich dir im Moment nicht weiter helfen kann.
> aber ich kann nie zweimal hintereinander eine Taste drücken.
Auch wenn du dir zwischen den Tastendrücken betont viel Zeit
lässt (sagen wir mal so 1 bis 2 Sekunden)?
Wie gesagt: Deine Overflow Zeiten stimmen nicht. Anstatt 10ms
liegt dein Overflow Intervall bei ca 35ms.
OK, ich glaube ich habe den Fehler. Meine Tasten ziehen den Pegel auf GND, sobald sie gedrückt sind. Ich glaube bei den oben beschriebenen Entprellroutinen ist der Pegel auf VCC bei Tastendruck. Ich hab versucht die Routinen umzuschreiben, aber irgendwie versteh ich es nicht ganz. Kann mir bitte wer helfen?
Das stimmt schon, die Taster muessen nach GND schalten. Bin grade erst nach Hause gekommen. Ich schau mal in dein Pgm.
Die Lösung ist ganz einfach. Ärgert mich jetzt ein bischen, eigentlich hätte ich das sehen müssen. Dein Port mit den Tastern ist zwar default mässig auf Input. Du hast aber vergessen die Pullup Widerstände einzuschalten: int main() { PORTA = 0xFF; Und der Spuk hat ein Ende. Ändere bitte die Berechnung des Reload Wertes in der Interrupt Routine wieder zurück.
Ich kann dir nicht mal einen Vorwurf machen. Die Pullups (bzw. ein Hinweis darauf) werden im Originalcode vom Artikel auch nicht eingeschaltet. PeDas Einverständnis mal vorausgesetzt, hab ich den dazu notwendigen Code hinzugefügt. Ich hab auch die SIGNAL gegen ISR ausgetauscht. PeDa hast du ein Problem damit, wenn ich die u8 gegen uint8_t austausche und so den Code noch etwas mehr modernisiere?
Bin erst jetzt zum Testen gekommen, aber es funktioniert super!!!! Vielen, vielen Dank!!!!
Hallo, es hat jetzt zwar nichts direkt mit dem Tastenentprellen zu tun, sondern ich glaube mehr mit dem Aufbau eines C-Projekts, aber ich hab halt eben Probleme damit: Ich verwende in der Main-Fkt die Fkt get_ket_press() und auch in der Datei menue.c Nun habe ich in der tasten.t die Funktion: extern uint8_t get_key_press( uint8_t key_mask ); deklariert und in tasten.c definiert (mit der zugehörigen Interruptfunktion). Komischerweise verwende ich in der main.c auch funktionen, die ich woanders definiert habe und die funktionieren bestens.
warum die Fehlermeldung in der main.c und in der menue.c lautet: undefined reference to 'get_ket_press' obwohl ich die tasten.h überall eingebunden habe
Sorry, ichnehme alles zurück! Habe vergessen das neue File ins makefile mit einzutragen! Tja, Anfängerin...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.