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
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
voidSetupClock()
2
{
3
uint8_tgedrueckteTaste;
4
uint8_tStundeLokal;
5
uint8_tMinuteLokal;
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
StundeLokalausgeben
22
MinuteLokalausgeben
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
neueStundeLokalausgeben
38
}
39
40
elseif(gedrueckteTaste==Taste_-)
41
{
42
if(StundeLokal>0)
43
StundeLokal--
44
else
45
StundeLokal=23;
46
47
neueStundeLokalausgeben
48
}
49
50
elseif(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.
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.
> 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.
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.