Forum: Mikrocontroller und Digitale Elektronik Reaktion auf Tasterereignis in zeitlich unkritischem Programm


von MC-Anfänger (Gast)


Angehängte Dateien:

Lesenswert?

Hi Community,

wie ich Tasten einlese weiß ich, mir geht es hier um die verschiedenen 
Möglichkeiten, welche Methoden sind für welche Anwendung geeignet.

Ich möchte ein Programm erstellen, dass nach einer Initialisierungs- und 
Einstellphase hauptsächlich nur noch auf Tastendrücke reagiert.

Ich habe mir bereits die verschiedenen Beispielcodes zum 
Tastenentprellen etc. durchgelesen und auch großteils verstanden.
An dieser Stelle schonmal ein Dankeschön :)

Nun zur eigentlichen Frage:

In meinem Projekt soll auf einen Tastendruck reagiert werden:
Eine Funktion F1 soll direkt nach der Betätigung von einem Taster T1, es 
soll auch schon ein Antippen ausreichen, ausgeführt werden.
Wann T1 losgelassen wird bzw. wie lang T1 gehalten ist mir egal.

Dauert jetzt F1 länger, wie T1 prellt, muuss ich ja theoretisch nicht 
entprellen oder?

Da ich jetzt nicht vorraussagen kann, wann T1 betätigt wird, habe ich 
überlegt das ganze über Interrupts zu steuern.
Sprich es soll auf eine steigende Flanke an T1 gewartet werden. Nun habe 
ich aber gelesen, dass ein Interrupt nicht über einen Taster ausgelöst 
werden soll, da durch das prellen der Interrupt ja öfter ausgeführt 
werden würde.

Gleiche Frage wie oben:
Wenn F1 länger dauert, wie T1 prellt und während F1 keine Interrupts 
zulässig sind, ist es doch unkritisch, den Interrupt auf T1 zu legen?

Sollte ich hier falsch liegen, wie sollte ich dann auf T1 prüfen, ob 
dieser betätigt wurde?

Im Anhang habe ich mal eine Zeichnung, welche die Zeitabhänigkeiten 
exemplarisch darstellen soll.

Ich hoffe ich konnte meine Frage deutlich darstellen und hoffe auf ein 
paar Tipps, wie ich die Sache am besten angehe.

Ich möchte keine Codes, nur eine Erklärung wie und warum ich auf ein 
solches Tasterereignis reagieren soll.

Danke schonmal für eure Hilfe
MC-Anfänger

von Karl H. (kbuchegg)


Lesenswert?

MC-Anfänger schrieb:

> wie ich Tasten einlese weiß ich, mir geht es hier um die verschiedenen
> Möglichkeiten, welche Methoden sind für welche Anwendung geeignet.
>

Ist ganz einfach.
Die brauchst eigentlich nur die Danegger Entprellung aus dem Wiki 
Artikel Entprellung.
Die kann alles was man in der Praxis braucht.


> Da ich jetzt nicht vorraussagen kann, wann T1 betätigt wird, habe ich
> überlegt das ganze über Interrupts zu steuern.

Timer Interrupt, wie in der Danegger Entprellung

> Sollte ich hier falsch liegen, wie sollte ich dann auf T1 prüfen, ob
> dieser betätigt wurde?

Du überlässt das der Danegger Entprellung.
Alles was du dazu brauchst, ist ein Timer, in dessen ISR alle paar 
Millisekunden nachgesehen wird, ob sich was an den Tastern getan hat.
In einem Wort: Danegger Entprellung

> Ich möchte keine Codes, nur eine Erklärung wie und warum ich auf ein
> solches Tasterereignis reagieren soll.

Auf jeden Fall nicht mit einem externen Interrupt

PS: auch in zeitlich kritischen Programmen benutzt man die Danegger 
Entprellung. Warum?
Weil sie fast keine Rechenzeit verbraucht und gut funktioniert. Und kein 
Mansch kann sagen, ob die Reaktion des Programms ~30 Millisekunden nach 
dem Tastendruck kommt oder schon früher. Bei Tastendrücken bewegen wir 
uns im Bereich von Zehntelsekunden, nicht Millisekunden. Schon 
Millisekunden sind für einen µC eine Zehntel Ewigkeit, Zehntelsekunden 
sind dagegen Zeitalter.

von Peter D. (peda)


Lesenswert?

MC-Anfänger schrieb:
> welche Methoden sind für welche Anwendung geeignet.

Ich nehme immer nur eine Methode und die war bisher für ausnahmslos jede 
Anwendung geeignet.
Daher sehe ich keinen Sinn darin, sich den Kopf zu zerbrechen, ob man 
für manche Anwendungen auch ne andere Methode nehmen könnte. Man sollte 
unnütze Arbeit ruhig vermeiden.

Ob Entprellen, Flanke erkennen, Lang-/Kurzdruck, Repeat, 2 Tasten 
gleichzeitig ..., ich will mir da keinen Kopp machen müssen, ich rufe 
einfach die entsprechenden Funktionen auf und gut is.


Peter

von Peter D. (peda)


Lesenswert?

Die Kunst beim Programmieren ist nicht, jedesmal neue auf die Anwendung 
zugeschnittene Speziallösungen zu schaffen, sondern zu abstrahieren.

Man versucht einen Aufgabe so universell wie möglich zu lösen, damit man 
dann die Lösung beim nächsten Projekt einfach übernehmen kann.

Beim Tastenabfragen ist z.B. Entprellen und Flanke erkennen immer nötig.
Zusätzlich sollten keine Wartezeiten das Programm blockieren. In vielen 
Fällen laufen ja noch andere Sachen neben der Tastenabfrage. Und wenn 
mal nicht, lohnt sich trotzdem keine Speziallösung.

Man muß auch daran denken, daß Programme eine sehr hohe Tendenz haben, 
später mal erweitert zu werden.


Peter

von MC-Anfänger (Gast)


Lesenswert?

Hi,
das ging ja schnell :)

Das Argument nach Möglichkeit universelle Lösungen zu erzeugen klingt 
sehr überzeugend.
Also werde ich mir mal Ihren Code zur Entprellung nochmal genauer 
ansehen.

Danke schonmal für die Antworten.

Gruß MC-Anfänger

von MC-Anfänger (Gast)


Lesenswert?

Hi,

ich hab jetzt mal eine Kleinigkeit programmiert, leider funktioniert das 
Ganze nicht so richtig :(

Ich habe das Evaulation-Board von Pollin und einen ATMega16.
Zum Test habe ich das Programm erstellt und auf den Device geschoben, 
jedoch reagiert dieser leider nicht ganz wie erwartet...

Hier mal der Code (Wie von euch empfohlen den von Peter Dannegger, aber 
etwas abgewandelt)
1
/************************************************************************/
2
/*                                                                      */
3
/*                      Debouncing 8 Keys                               */
4
/*                      Sampling 4 Times                                */
5
/*                      With Repeat Function                            */
6
/*                                                                      */
7
/*              Author: Peter Dannegger                                 */
8
/*                      danni@specs.de                                  */
9
/*                                                                      */
10
/************************************************************************/
11
12
#include <stdint.h>
13
#include <io.h>
14
#include <interrupt.h>
15
 
16
#ifndef F_CPU
17
#define F_CPU           1000000                  
18
#warning kein F_CPU definiert
19
#endif
20
 
21
#define KEY_DDR         DDRD
22
#define KEY_PORT        PORTD
23
#define KEY_PIN         PIND
24
#define KEY0            2
25
#define KEY1            3
26
#define KEY2            4
27
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
28
 
29
#define LED_DDR         DDRD
30
#define LED_PORT        PORTD
31
#define LED0            5
32
#define LED1            6
33
 
34
volatile uint8_t key_state;                                                                             
35
volatile uint8_t key_press;                               
36
 
37
 
38
ISR( TIMER0_OVF_vect )                            // every 10ms
39
{
40
  static uint8_t ct0, ct1;
41
  uint8_t i;
42
 
43
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
44
 
45
  i = key_state ^ ~KEY_PIN;                       // key changed ?
46
  ct0 = ~( ct0 & i );                             // reset or count ct0
47
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
48
  i &= ct0 & ct1;                                 // count until roll over ?
49
  key_state ^= i;                                 // then toggle debounced state
50
  key_press |= key_state & i;                     // 0->1: key press detect
51
}
52
 
53
///////////////////////////////////////////////////////////////////
54
//
55
// check if a key has been pressed. Each pressed key is reported
56
// only once
57
//
58
uint8_t get_key_press( uint8_t key_mask )
59
{
60
  cli();                                          // read and clear atomic 
61
  key_mask &= key_press;                          // read key(s)
62
  key_press ^= key_mask;                          // clear key(s)
63
  sei();
64
  return key_mask;
65
}
66
 
67
68
int main( void )
69
{
70
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
71
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
72
 
73
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
74
  TIMSK |= 1<<TOIE0;          // enable timer interrupt
75
 
76
  LED_PORT = 0x60;
77
  LED_DDR = 0x60;                     
78
 
79
  sei();
80
 
81
  while(1)
82
  {
83
  if( get_key_press (1<<KEY2) )
84
    LED_PORT ^= (1<<LED0);
85
  if ( get_key_press (1<<KEY1) )
86
    LED_PORT ^= (1<<LED1);
87
  if ( get_key_press (1<<KEY0) )
88
    LED_PORT ^= 0x60;
89
  }
90
}

Ich würde erwarten, dass wenn ich
 - KEY2 drücke, LED0 an/aus geschaltet wird
 - KEY1 drücke, LED1 an/aus geschaltet wird
 - KEY0 drücke, LED0/LED1 an/aus geschaltet wird

Jedoch tut sich irgendwie nichts...

Habe ich einen Fehler gemacht bzw. gibt es ein Problem, da LEDs und 
Taster auf einem Port liegen?

Danke schonmal für Eure Hilfe
MC-Anfänger

von Karl H. (kbuchegg)


Lesenswert?

MC-Anfänger schrieb:

> Ich habe das Evaulation-Board von Pollin und einen ATMega16.

Hast du das Board schon modifiziert?
Die Tasteranschaltung ist bei dem Board schlecht gemacht.

Ich such schon die ganze Zeit nach dem Artikel dazu, aber ich finde ihn 
nicht mehr.

In der Originalbeschaltung sind diese Taster, entgegen üblichen 
Gepflogenheiten 'high active' verschaltet.

Dreh dazu die Zeile

 i = key_state ^ ~KEY_PIN;                       // key changed ?

um auf

 i = key_state ^ KEY_PIN;                       // key changed ?


Damit sollte sich dann zumindest etwas tun.

von MC-Anfänger (Gast)


Lesenswert?

Danke für die schnelle Antwort, jetzt tut sich tatsächlich was, leider 
wird nicht jeder Tastendruck erkannt...
Das hängt mit dem Board zusammen? -> Ich habe daran nichts modifiziert, 
aber ich werde mich mal auf die Suche nach dem Beitrag begeben

Auf die Pullupwiderstände muss ich zugeben, habe ich nicht geachtet.
Aber da das Board Active-High ist, müsste ich die internen ja eigentlich 
abschalten oder?

In der main also anstatt:
 KEY_PORT |= ALL_KEYS;

Das hier einsetzen?
 KEY_PORT &= ~ALL_KEYS;

von Karl H. (kbuchegg)


Lesenswert?

MC-Anfänger schrieb:
> Danke für die schnelle Antwort, jetzt tut sich tatsächlich was, leider
> wird nicht jeder Tastendruck erkannt...
> Das hängt mit dem Board zusammen? -> Ich habe daran nichts modifiziert,
> aber ich werde mich mal auf die Suche nach dem Beitrag begeben

Im wesentlichen geht es darum, bei jedem Taster den C und den R 
auszubauen und eine kleine Modifikation zu machen, so dass die Taster 
gegen Masse schalten und nicht mehr gegen Vcc

> Auf die Pullupwiderstände muss ich zugeben, habe ich nicht geachtet.
> Aber da das Board Active-High ist, müsste ich die internen ja eigentlich
> abschalten oder?

Ja.

> In der main also anstatt:
>  KEY_PORT |= ALL_KEYS;
>
> Das hier einsetzen?
>  KEY_PORT &= ~ALL_KEYS;

Im Prinzip ja. Da aber die Pullups beim Einschalten sowieso aus sind, 
kannst du das auch komplett streichen, schadet aber auch nicht.

von Martin V. (oldmax)


Lesenswert?

Hi
Mein Tipp: Modifizier nicht am Board. Da du mit 3 Tastern auf Dauer 
sowieso nicht auskommst, kauf dir ein Steckbrett, such dir ein 40pol. 
altes Festplattenkabel und löte auf eine Seite eine 40 Pol. Fassung 
drauf. Diese steckst du aufs Steckbrett und machst ein paar Rangierungen 
auf zugängliche Kontakte. So brauchst du dir die Platine nicht versauen 
und kannst alles mögliche an den Controller ranbasteln......
Übrigends gibt es auch Quetschstecker, ähnlich einer 40 pol. Fassung. 
Ich hatte einen in meiner Kramkiste, weiß aber nicht mehr, wo ich den 
mal gekauft hab.
Gruß oldmax

von Karl H. (kbuchegg)


Lesenswert?

Martin Vogel schrieb:

> Mein Tipp: Modifizier nicht am Board. Da du mit 3 Tastern auf Dauer
> sowieso nicht auskommst, kauf dir ein Steckbrett, such dir ein 40pol.
> altes Festplattenkabel und löte auf eine Seite eine 40 Pol. Fassung
> drauf.

Das kann ich nur unterstreichen.
So ein Verbindungskabel zu einem Steckbrett ist Gold wert.

Ich habe das auch mit einem Flachbandkabel auf einer IC-Fassung gemacht. 
Allerdings brechen mit der Zeit gerne einzelne Adern direkt an der 
Lötung beim IC-Sockel ab. Meine Lösung: Das Kabelende, Lötung, IC-Sockel 
schön mit Heisskleber verpappen, so dass das Kabelende in Bezug zum 
Sockel mechanisch fixiert ist und die Lötung nicht mehr mechanisch 
beansprucht wird. Seitdem ich das gemacht habe, bricht da nix mehr.

von MC-Anfänger (Gast)


Lesenswert?

Hi,
danke für die Tipps, Kabel hab ich mir schon besorgt und vorbereitet :-)

Steckbrett wird dann demnächst folgen. Bis dahin baue ich mir mal eine 
'schwebende' Schaltung auf.
Ich hoffe das ganze klappt.
Sollte ja, da am Code ja anscheinend alles zu stimmen scheint.
Letzte Änderungen:
  -  Interne Pullups deaktiviert
  -  Abfrage für aktive high geändert

Wird für den 'Schwebeversuch' natürlch passend wieder geändert.

Danke nochmal für eure Tipps/Hilfe

Gruß
MC-Anfänger

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.