Guten Tag Zusammen, ich habe folgendes Problem und habe auch lange an einem ähnlichen Beispiel gesucht und leider nichts gefunden, vielt kann mir da jemand helfen! Ich benutze einen STM32F1 und am Ende des Projektes soll es eine Uhr werden. Ich habe 4 Taster angedacht: Taster + Taster - Taster Return Taster- Menu/Enter: durch diesen Taster soll man ins "Menu" kommen, sprich er fängt bei Stunden an es ändern zu können und mit den Tasten + und - kann man den Wert von Stunden erhöhen und verkleinern. Durch erneutes drücken der Menu/Enter-Taste soll es bestätigt werden und mit der Taste + oder - sollte man den nächsten Wert verändern können, sprich Minute. Mit der Return Taste soll das Menu sofort verlassen werden. Die Taster habe ich alle vor das Entprellen geschützt. Nun weis ich leider nicht wie man bei einer solchen Routine vorgehen soll. Da ich leider nicht so viel Erfahrung in Sachen Programmierung habe, würde ich mich sehr über Tipps und Tricks von euch freuen!! Ich bedanke mich jetzt schon ganz herzlich auf wertvolle Beiträge. Mit freundlichen Grüßen Fabian
Dazu nimmt man eine Statemaschine. Hier mal ein Beispiel mit 2 Tasten und kurz/lang Unterscheidung: Beitrag "Jumbo-LED Uhr"
mal dir erst mal ein Zustandsdiagramm auf. Knubbel für bestimmte Zustände, und Pfeile zwischen den Knubbeln, um von einem Zustand zum nächsten zu gelangen. Die Knubbel und die Pfeile beschriftest du mit "sinnigem" ich gebe mal vor: erster Knubbel = Startzustand, Uhr ist im Anzeigemodus (was auch immer sie dort macht) vom Startzustand führen 3 Kanten wieder direkt als "Schlaufe" in den Startzustand zurück: "Taste + gedrückt", "Taste - gedrückt", "Taste return gedrückt". Nur eine einzige Kante "Taste Menue gedrückt" führt zu einem weiteren Knubbel "Taste Menue WURDE gedrückt" und so weiter. Du wirst z.B. irgendwann z.B. einen Zustand "erhöhe den Minutenzähler - Modulo 60" haben, d.h. der Minutenzähler wird immer um 1 erhöht, bis er bei 60 wieder auf 0 "zurück" geht und wieder von vorne los zählt" Dahinter verbirgt sich natürlich einiger Programmieraufwand, z.B. eine Variable zu erhöhen [=Variable lesen, neu berechnen = +1 modulo 60, und Variable zurück speichern], Aber die konkrete "Programmierbefehl-Umsetzung" ist für die erste Gestaltung des Ablaufs erst mal unwichtig. Interessant ist halt auf jeden Fall, immer alle Dinge im Auge zu behalten, was irgendwo irgendwie passiert. z.B. hast du ja auch eine Anzeige, welche aktualisiert werden möchte. Durch was das "automatisch" erfolgt, mag jemand anderes verraten. Den Zustandsgraphen mußt du dann "nur noch" später in eine Programmiersprache deiner Wahl formulieren, und fertig ist das Programm ;-)
Fabian L. schrieb: > Nun weis ich leider nicht wie man bei einer solchen Routine vorgehen > soll. Du hast dir ja schon den prinzipiellen Ablauf klar gemacht. Von daher sollte das nicht mehr weiter schwer sein. Grundsätzlich gibt es 2 Möglichkeiten: Der eine ist er sequentielle Durchlauf, der andere der ereignis gesteuerte Ablauf. Nehmen wir mal den sequentiellen Durchlauf, da er meistens etwas einfacher zu verstehen ist. Du nimmst einfach nur deinen bereits bekannten Bedienablauf her und programmierst den im Grunde runter. Dazu brauchst du ein paar Hilfsfunktionen, wie zb Tastenerkennung und Auswertung. Die sollten im Vorfeld schon mal stehen und stabil sein. Aber dann geht das dahin. Im einfachsten Fall steckst du die ganze Einstellerei in eine Funktion, denn dann bedeutet "Abbrechen der Eingabe" einfach nur: vorzeitiger Aussteig aus der Funktion in etwa so
1 | void SetupClock() |
2 | {
|
3 | uint8_t gedrueckteTaste; |
4 | uint8_t StundeLokal; |
5 | uint8_t MinuteLokal; |
6 | |
7 | //
|
8 | // erst mal die "richtigen" Werte lokal in die Funktion übernehmen
|
9 | // dann kann man die Ändern ohne die "echte Uhr" durcheinander
|
10 | // zu bringen. Das ist insofern zb wichtig, weil der Benutzer
|
11 | // bei der Eingabe der Minuten immer noch aus der ganzen Einstellung
|
12 | // aussteigen kann und sich dann die Stunden auch nicht verändern
|
13 | // sollen.
|
14 | // Nur wenn der ganze Einstellvorgang als ganzes durchgelaufen ist,
|
15 | // dann gilt die neu eingestellte Zeit und dann wird die richtige
|
16 | // Uhr aus den eingestellten Werten neu gestellt.
|
17 | //
|
18 | StundeLokal = StundeGlobal; |
19 | MinuteLokal = MinuteGlobal; |
20 | |
21 | StundeLokal ausgeben |
22 | MinuteLokal ausgeben |
23 | |
24 | // Stunden einstellen
|
25 | // die Einstellung wird durch Drücken von Return oder Enter beendet
|
26 | |
27 | do
|
28 | {
|
29 | gedrueckteTaste = hole_nächsten_Tastendruck(); |
30 | |
31 | if( gedrueckteTaste == Taste_+ ) |
32 | {
|
33 | StundeLokal++; |
34 | if( StundeLokal == 24 ) |
35 | StundeLokal = 0; |
36 | |
37 | neue StundeLokal ausgeben |
38 | }
|
39 | |
40 | else if( gedrueckteTaste == Taste_- ) |
41 | {
|
42 | if( StundeLokal > 0 ) |
43 | StundeLokal-- |
44 | else
|
45 | StundeLokal = 23; |
46 | |
47 | neue StundeLokal ausgeben |
48 | }
|
49 | |
50 | else if( gedrueckteTaste == Taste_Return ) |
51 | return; |
52 | |
53 | } while( gedrueckteTaste != Taste_Enter ); |
54 | |
55 | // dasselbe nochmal für die Minuten
|
56 | do
|
57 | {
|
58 | gedrueckteTaste = hole_nächsten_Tastendruck(); |
59 | |
60 | ....
|
61 | |
62 | } while( gedrueckteTaste != Taste_Enter ); |
63 | |
64 | // Die Einstellung ist bis hier her durchgelaufen, d.h der Benutzer
|
65 | // will tatsächlich genau die eingestellte Zeit setzen und ist nicht
|
66 | // vorher mit Return ausgestiegen
|
67 | //
|
68 | // aktiviere jetzt die so eingestellte Zeit, indem die
|
69 | // 'richtigen' Stunden und Minuten Werte aus den eingestellten
|
70 | // WErten aktualisiert werden
|
71 | |
72 | StundeGlobal = StundeLokal; |
73 | MinuteGLobal = MinuteLokal; |
74 | }
|
das ist natürlich nur eine Skizze. Mangels Wissen über dein Komplettsystem hab ich ein paar Annahmen treffen müssen, um wenigstens die grundlegende Idee skizzieren zu können. Wie du konkret die Tastenabfrage machst, bzw. wie du konkret auf deiner Anzeige was ausgibst, das musst du selber wissen. Betrachte den Code also mehr als eine grundsätzliche Idee, denn als Code den du mit Copy&Paste übernehmen kannst.
:
Bearbeitet durch User
Vielen Dank für die vielen Beiträge! Ich schaue es mir an und versuche es alles umzusetzen!
Hallo zusammen, erst mal vielen dank an Karl Heinz, dein Beitrag war für mich sehr wertvoll!! Nun bin ich an dem Problem gestoßen, dass ich zwar die Stunden problemlos umstellen kann, jedoch weis ich dann nicht wie ich die Minuten umstellen kann. Also die do-while schleife hat bei mir nicht funktioniert, da die schleife immer einmal abgearbeitet wird und da ich die Funktion in main bei der while(1) reingepackt habe, kann ich die Uhrzeit bzw. die Stunden jederzeit ändern. Zugegeben ich habe es ohne: gedrueckteTaste = hole_nächsten_Tastendruck(); programmiert, da ich nicht wusste wie ich es umsetzen sollte. Mag sein das es daran liegt. Mein Problem: Ich würde gerne mit der Taste-Menu/Enter (ist nur eine Taste) mit einmaligem betätigen in die Funktion void SetupClock()gelangen und durch nochmaliges betätigen dieser Taste zwischen Stunde & Minuten wechseln. Ist mit Sicherheit was simples, doch leider versuche ich es schon seit Freitag ohne Erfolg :( Danke im Voraus und lieben Gruß Fabian
Fabian L. schrieb: > Zugegeben ich habe es ohne: > > gedrueckteTaste = hole_nächsten_Tastendruck(); > > programmiert, da ich nicht wusste wie ich es umsetzen sollte. Mag sein > das es daran liegt. Das dachte ich mir schon. Das ist allerdings einer der wensentlichen Punkte in der Menüprogrammierung: die UNterscheidung zwischen * mach etwas SOLANGE eine Taste gedrückt ist * mach etwas, beim NIEDERDRÜCKEN einer Taste. Das sind 2 paas Schuhe. Das eine ist recht trivial und bedeutet nichts anderes als: du drückst auf eine Taste und das Garagentor fährt zu. Lässt du die Taste los, bleibt das Tor stehen. SOLANGE die Taste gedrückt ist, bewegt sich das Tor. Das andere ist erstaunlicherweise gar nicht so einfach und es bedeutet schlicht und ergreifend: mit dem Antippen eines Tasters wird ein Vorgang ausgelöst. Der Vorgang des Tastendrückens ist es, welcher die Aktion anstösst. Du drückst eine Taste und eine LED schaltet sich ein. Du drückst nochmal auf dieselbe Taste und die LED schaltet sich wieder aus. Das sind 2 verschiedene Dinge und wenn du dich an Menüsteuerungen versuchst, dann brauchst du als aller erstes eine robuste und zuverlässige Erkennung eines Tastendrucks! (Also nicht eine Erkennung ob eine Taste gedrückt ist, sondern eine Erkennung, dass eine Taste gedrückt wurde). IM ersten Fall reicht es, das 'gedrückt sein' festzustellen. Im zweiten Fall durchläuft die Tastenerkennung aber den Zyklus vom nicht-gedrückten Taster - den Vorgang des Niederdrückens - den Status des gedrückt seins - den Vorgang des loslassens - den Status des losgelassenen Tasters, bis ein Tastendruck komplett abgehandelt ist. Hier Entprellung die Komfortroutinen vom PeDa machen das problemlos. Es gibt auch noch andere Routinen, aber die PeDa Routinen spielen alle Stücke die du jemals brauchen wirst.
:
Bearbeitet durch User
> Das sind 2 verschiedene Dinge und wenn du dich an Menüsteuerungen > versuchst, dann brauchst du als aller erstes eine robuste und > zuverlässige Erkennung eines Tastendrucks! (Also nicht eine Erkennung ob > eine Taste gedrückt ist, sondern eine Erkennung, dass eine Taste > gedrückt wurde). > IM ersten Fall reicht es, das 'gedrückt sein' festzustellen. Im zweiten > Fall durchläuft die Tastenerkennung aber den Zyklus vom nicht-gedrückten > Taster - den Vorgang des Niederdrückens - den Status des gedrückt seins > - den Vorgang des loslassens - den Status des losgelassenen Tasters, bis > ein Tastendruck komplett abgehandelt ist. > Genau das habe ich vergeblich versucht, doch leider bin ich folglich dran gescheitert. > Hier > Entprellung > die Komfortroutinen vom PeDa machen das problemlos. Es gibt auch noch > andere Routinen, aber die PeDa Routinen spielen alle Stücke die du > jemals brauchen wirst. Die Komfortroutine von PeDa habe ich mir schon oft angeschaut und versucht es zu verstehen, doch leider kann ich es nicht am STM32F1 umsetzen, wenn ich es zu 80% NICHT verstehe :(
Fabian L. schrieb: > Die Komfortroutine von PeDa habe ich mir schon oft angeschaut und > versucht es zu verstehen, doch leider kann ich es nicht am STM32F1 > umsetzen, wenn ich es zu 80% NICHT verstehe :( Entschuldige. Daran hab ich nicht mehr gedacht, dass du ja einen STM32F1 hast. Nun das Prinzip ist ja recht einfach. Erst mal brauchst du einen Timer, der dir eine ISR in regelmässigen Zeitabständen aufruft. Ohne diese Zutat geht recht wenig. D.h. wenn du das noch nie gemacht hast, dann ist jetzt der beste Zeitpunkt, den Umgang mit einem Timer zu lernen. IN der ISR wird ganz einfach der am Port festgestellte Zustand der Tasten mit dem zuletzt im Programm als gültig angesehenen Tastenzustand verglichen. Sind sie gleich, dann ist die Taste entweder gerade gedrückt oder gerade losgelassen. Welcher Fall vorliegt kann man ja recht einfach am Portpegel feststellen. Der interessante Fall liegt aber vor, wenn programmintern eine entsprechende Variable aussagt, dass die Taste momentan nicht gedrückt ist, tatsächlich ergibt aber die aktuelle Nachschau in der ISR, dass die Taste jetzt aber gedrückt ist. Dieser Zustand kann nur dann eintreten, wenn just in diesem Moment gerade jemand auf die Taste gedrückt hat. Denn davor waren ja die beiden Dinge gleich (programmintern besagte die VAriable, dass die Taste nicht gedrückt ist, und eine Nachschau um Port bestätigt dieses und auch umgekehrt). D.h. genau dieser Wechsel ist dein Tastendruck, den man in der ISR registrieren muss (zb in einer Variablen merken), so dass das restliche Programm dann auch auf die Abfrage: "Ist die Taste Enter gedrückt worden?" dann auch genau diese Auskunft nur ein einziges mal kriegt: Jawohl, ist sie. Die PeDa Routinen leisten dann noch mehr, in dem sie da eine Entprellung drüber legen und auch noch so Dinge wie Autorepeat einfügen können. Aber den Teil musst DU unter Kontrolle kriegen. Einen Tastendruck auszuwerten, egal wie, ist Grundtechnik. Das ist, technisch gesprochen, nichts anderes als eine Flankenerkennung.
1 | int main() |
2 | {
|
3 | bool EnterPressed = false; |
4 | |
5 | uint8_t TastenZustandEnterAlt; |
6 | |
7 | ....
|
8 | |
9 | while( 1 ) |
10 | {
|
11 | |
12 | // Feststellen und Erkennen eines Tastendrucks
|
13 | |
14 | TastenzustandEnter = Status vom Pin jetzt in diesem Moment |
15 | |
16 | if( TastenzustandEnter != TastenzustandEnterAlt ) |
17 | {
|
18 | // Ha. Da hat sich was verändert! Der Portpin ist in einem
|
19 | // anderen Zustand.
|
20 | // In welchem?
|
21 | //
|
22 | if( TstenzustandEnter == gedrückt ) |
23 | EnterPressed = true; |
24 | |
25 | TastenzustandEnterAlt = TastenzustandEnter; |
26 | }
|
27 | |
28 | // einen eventuell festgestellten Tastendruck dann auch auswerten
|
29 | if( EnterPressed == true ) |
30 | {
|
31 | EnterPressed = false; |
32 | |
33 | mache die Aktion, die bei einem Tastendruck gemacht werden soll |
34 | zb eine LED umschalten |
35 | }
|
36 | }
|
37 | }
|
Das ist so ungefähr das Grundgerüst für die ersten SChritte in die Tastendrück-Erkennung. Da ist noch keine Entprellung drinnen, aber zumindest die Flankenerkennung. Sieh zu, dass du dieses Verfahren verstehst (erst mal abseits deines eigentlichen Programms, mach dir ein Testprogramm dafür), bring ihn auf deinem µC zum laufen und verlagere dann den ganzen Teil der Tastenerkennung in eine Timer-ISR, so dass die Nachschau auf dem Portpin so ungefähr alle 15 bis 20 Millisekunden gemacht wird. Das ist zwar noch keine ganz saubere Entprellung, aber für nicht allzu schlechte Taster sollte es reichen. Das ist dein Teil-Ziel. Und das ist ein wichtiges Ziel um Tastenauswertung so zu machen, dass man dann als nächstes ein Menü darauf aufbauen kann. Ehe du diesen Teil nicht im Griff hast, hat es keinen bis kaum Sinn, am Menü weiter zu arbeiten.
:
Bearbeitet durch User
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.