Forum: Mikrocontroller und Digitale Elektronik Eingabetaster mit zwei unterschiedlichen Funktionen (PIC)


von Dieter L. (dlog43)


Lesenswert?

Hallo zusammen,
bei einer kleinen Bastelei möchte ich einem Eingabetaster an meinem PIC 
an verschiedenen Stellen im Programm je eine andere Funktion zuweisen. 
Sprich, wenn ich den Taster an Stelle X drücke soll A ausgeführt werden, 
wenn ich den Taster an Stelle Y drücke, soll B ausgeführt werden.

Wie löse ich das Problem am einfachsten (C/Assembler)?
Ich habe probiert, Variablen zu setzen bzw. zu löschen an den 
entsprechenden Stellen, aber dann werden bei Tastendruck immer A und B 
ausgeführt, egal ob ich bei X oder Y drücke (also genau, was ich nicht 
will). Die Taster werden jeweils im Programm per Polling abgefragt.

Ich hoffe ihr könnt mir helfen und kommt mit meiner groben Darstellung 
halbwegs zurecht, habe versucht das ganze recht einfach zu erklären :)

von Stefan (Gast)


Lesenswert?

Wie ist denn die Stelle definiert ?

von Simpel (Gast)


Lesenswert?

Das wird so nix, es sei denn du hast im Programm genug Zeit zu 
verplempern, um zu warten. Du müsstest an der jeweiligen Stelle des 
Programms die Debounce-Rotine starten und abwarten bis sie ein gültiges 
Ergebnis liefert.
Man macht das eher so: Für die beiden verschiedenen Funktionen einen 
kurzen und einen langen Tastendruck (oder einen normalen und einen 
Doppelclick) unterscheiden und das zur Separation der beiden Funktionen 
verwenden.

von WehOhWeh (Gast)


Angehängte Dateien:

Lesenswert?

Ich mach das so:
Für die Eingabegeräte gibts eine Type, z.B. sowas:
1
//Beschreibt einen Button
2
typedef struct{
3
    unsigned int pressed : 1;   //button has been pressed (may be reset externally)
4
    unsigned int released : 1;  //button has been released -""-
5
    unsigned int status : 1;    //actual status of button
6
}btn;
7
8
//Da sind die buttons alle aufgelistet
9
typedef struct{
10
    btn button1;
11
    btn button2;
12
}Buttons;

Die eigentliche Variable wird als "static" in main deklariert (oder in 
eine andere Struktur eingewurstelt), alle Funktionen die mit Tastern zu 
tun haben bekommen einen Pointer drauf, unter anderem jene, die die 
Buttons einliest.

Die Funktion, welche die Bits da einträgt, wird einmal alle 10ms oder so 
aufgerufen - die schaut nach, ob sich der Taster geänder hat und setzt 
fallweise das passende Bit. Entprellt ist das dann auch gleich, wenn der 
Taster nicht länger als 10ms prellt.

Funktionen, die Benutzereingaben verarbeiten, bekommen einen Pointer da 
drauf. Die verarbeiten dann das jeweilige Ereignis und setzen das dann 
zurück. z.B. so:
1
if(Input->button1.pressed){
2
     //mach was tolles
3
     Input->button1.pressed = 0;
4
}

Damit wird jedes Ereignis genau einmal verwurstet.
Den Pointer kann man soweit herumreichen, wie man lustig ist. Man kann 
solange mit der Reaktion auf den Button warten, bis der Controller alles 
andere wichtige abgewurstelt hat.

Damit kann man Button-gesteuerte Menüs beliebig verzweigen.

Im Anhang ist ein Beispiel.

von Teo D. (teoderix)


Lesenswert?

Du scheinst, eine noch etwas falsch Vorstellung von Programmabläufen, zu 
haben.
Zeig doch mal Deine Code.

Simpel schrieb:
> Das wird so nix, es sei denn du hast im Programm genug Zeit zu
> verplempern, um zu warten. Du müsstest an der jeweiligen Stelle des
> Programms die Debounce-Rotine starten und abwarten bis sie ein gültiges
> Ergebnis liefert.

Sorry, aber das ist Quatsch. Man muss nur, in der jeweiligen Situation, 
unterscheiden ob Aktion A o. B ausgeführt werden soll.

von X4U (Gast)


Lesenswert?

Dieter L. schrieb:
> Sprich, wenn ich den Taster an Stelle X drücke soll A ausgeführt werden,
> wenn ich den Taster an Stelle Y drücke, soll B ausgeführt werden.
>
> Wie löse ich das Problem am einfachsten (C/Assembler)?

Das fällt in die Kategorie state machine.

Status A = DiesUndDas

Status B = WennWasAnderes


Beim Ereignis Taste gedrückt fragst du den Status ab und machst dann 
entsprechend weiter.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Stefan schrieb:
> Wie ist denn die Stelle definiert ?

Ah, er meint 'im Zustand X' und 'im Zustand Y' usw., nicht 'Stelle'.

@X4U: Guut! :-)

Siehe Statemachine.

: Bearbeitet durch User
von Simpel (Gast)


Lesenswert?

Das Ganze macht eh nur bei einer (partiellen) State-Machine Sinn, bei 
der der Nutzer signalisiert bekommt, wie der aktuelle Stand ist, und 
auch Zeit hat zu reagieren, oder nicht... aber wenn die Eingabe eh von 
einem signalisierten Status (mit oder ohne Timeout) abhängt, ist es auch 
wurscht an welcher Stelle im Code die dazugehörige Tasteneingabe gemacht 
wird. Der Sinn des vom TO beschriebenen Vorgangs erschliesst sich mir 
irgendwie nicht...

von Simpel (Gast)


Lesenswert?

...oops... da hätt ich mir meinen letzten Text sparen können... schon 
erledigt :|

von Peter D. (peda)


Lesenswert?

Dieter L. schrieb:
> Wie löse ich das Problem am einfachsten (C/Assembler)?

Beim Programmieren gilt auch "Teile und (be)herrsche", d.h. man erstellt 
kleine übersichtliche Teilaufgaben.

Zuerst braucht man eine Entprell-Lib, die fertige Ereignisse liefert und 
vorzugsweise im Timerinterrupt läuft, damit keine Drücke verloren gehen.

Und die Ereignisse holt man sich dann in den verschiedenen Kontexten 
(State-Maschinen) ab und reagiert darauf in der eine Statemaschine so 
und in der anderen eben anders.

Um zu vermeiden, daß ein Druck aus einem vorherigen Kontext was falsches 
macht, wird bei Kontextwechsel das Ereignis gelöscht (Dummy-Abfrage).

Man kann auch in verschiedenen Kontexten verschiedene Tastenfunktionen 
benutzen (z.B. lang/kurz Druck, Repeatfunktion).

von Ulrich P. (uprinz)


Lesenswert?

Also der für mich einfachste Ablauf war damals...

Ich habe einen Timer oder eine Hauptschleife, in einem Intervall, dass 
größer als die Prellzeit meines Tasters ist, oder es gibt eine TMIN die 
mind. erreicht sein muss, damit der Tastendruck als gegeben hin genommen 
wird.

Tastenverlauf:
     TMIN TKURZ    TLANG
____|~~~~|+++++|###########|____|~~~~|+++++|###########|

Dann habe ich eine Funktion, die zählt einen Zähler hoch, so lange der 
Taster gedrückt ist. Wird der Taster los gelassen, wird geschaut, wie 
lang der Taster gedrückt war:
- Zähler < TKURZ ist, dann wird die Funktion kurzer_druck() aufgerufen
- Zähler > TKURZ ist, dann wird die Funktion langer_druck() aufgerufen

Man kann das auch noch erweitern, in dem man noch eine TLANG hinzufügt. 
Wird diese überschritten, wird die Funktion taster_halten() aufgerufen 
und der Zähler zurück gesetzt, so dass er gleich wieder los rennt. Auf 
die Art kann man seinen MP3 Player mit nur einer Taste steuern:

Kurzer Druck: PLAY/PAUSE
Mittellanger Druck: Nächster Titel
Halten: Springe im Titel

Damit die aufgerufenen Funktionen nicht den Ablauf durcheinander 
bringen, setzen diese einfach nur Flags, die dann irgendwo geordnet 
abgearbeitet werden.

Natürlich kann man das auch in Timer-Interrupts verankern und Callback 
Functions definieren, aber ich denke, das heben wir uns für den 2. Teil 
auf :)

Gruß
Ulrich

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
Noch kein Account? Hier anmelden.