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
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.
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
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
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
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
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.
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;
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.
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.