mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik LCD Menü schreiben


Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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/Entprellun...

Die Funktionen sind perfekt geeignet um Eingaben
damit zu machen.

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: bla (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
  unsigned char MenuOnScreen;

  ....

  MenuOnScreen = 0;

  while( 1 ) {

    if( get_key_press( 1<<KEY0 )) {
      MenuOnScreen = 1 - MenuOnScreen;    // Menu anzeigen/verbergen

      if( MenuOnScreen ) {
        // das Menue anzeigen
      }
      else {
        // das LCD löschen
      }
    }

    if( MenuOnScreen ) {      // wenn das Menue aktiv ist, werden
                              // auch die anderen Tasten ausgewertet

      if( get_key_press( 1<<KEY1 )) {   // Cursor links
         // Cursor nach links
      }
 
      if( get_key_press( 1<<KEY2 )) {   // Cursor rechts
         // Cursor nach rechts
      }

      if( get_key_press( 1<<KEY3 )) {   // Cursor up
         // Cursor nach oben
      }

      if( get_key_press( 1<<KEY1 )) {   // Cursor down
         // Cursor nach unten
      }
    }
  }





Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!!

Autor: bla (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Ray (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zeig mal dein Programm.
An den Funktionen liegt es nicht, die hab ich selbst im
Einsatz und gehen tadellos.

Autor: Stefanie (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Zoch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das stimmt schon, die Taster muessen nach GND schalten.

Bin grade erst nach Hause gekommen.
Ich schau mal in dein Pgm.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bin erst jetzt zum Testen gekommen, aber es funktioniert super!!!!

Vielen, vielen Dank!!!!

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist deine Frage?

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dazu müssten wir schon den Source Code sehen.

Autor: Olli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
get_ket_press != get_key_press

Autor: Stefanie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, ichnehme alles zurück! Habe vergessen das neue File ins makefile 
mit einzutragen!
Tja, Anfängerin...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.