Hallo, Ich habe mich mal an ner Software Entprellung versucht und dabei folgenden Code produziert. Die Idee dahinter: 1. bei einem Keypress starte ich einen Timer t (der zählt im interrupt alle 8ms hoch) 2. nach 16ms also t==2 wird geprüft ob der Keypress noch immer besteht. 3. wenn dies zutrifft und die Taste anschließend wieder losgelassen ist, wird ein Zähler hochgezählt. Hab dabei leider festgestellt das mein Programm dieses nur einmal macht. Irgendwo scheint er nach dem 1sten Hochzählen festzusitzen. Wäre dankbar wenn mir einer sagen würde wo der Fehler ist. Compiler schluckt den Code so wie er unten steht. #include <avr/io.h> #include "lcd-routines.h" #include <avr/interrupt.h> #include <stdlib.h> #include <math.h> #ifndef F_CPU #define F_CPU 8000000L #endif uint16_t keypress; char Buffer[20],keystate; volatile uint16_t t,t2; void WriteToLCD(void) { lcd_clear(); set_cursor(0,1); lcd_string(itoa(keypress, Buffer, 10)); } int main(void) { DDRB |= (0 << PB1); // set PB1 as input PORTB |= (1 << PB1); // activate pullup for PB1 lcd_init(); TIMSK |= (1 << TOIE0); // enable overflow interrupt sei(); //enable global interrupt TCCR0 |= (0 << CS00) | (0 << CS01) | (1 << CS02); //prescale of 256 overflow at 8,192ms for(;;) { if ((keystate == 0) && (!(PINB & (1 << 1)))) //keypress detected { keystate=1; t=0; } if ((t==2) && (keystate==1) && (!(PINB & (1 << 1)))) //keypress still active after 16ms { keystate=2; } if ((keystate==2) && (PINB & (1 << 1))) //keyrelease detected = valid keypress { keypress++; WriteToLCD(); keystate=0; } } } ISR(TIMER0_OVF_vect) { t++; //overflow at 8,192ms } Gruß vollfreak
Schau doch mal was passiert wenn Keystate 1 und der Zähler T > 2 ist. (unwahrscheinlich) Soll das eine "Übung" für ne Statemachine werden ? Baue dir Breakpoints ein die am Display ausgegeben werden ! So lernst Du auch ein wenig zum Thema Debuging :)
Man kann das Fahrrad jedesmal neu erfinden. Man muß dann aber auch Verständnis aufbringen, daß nur wenige Lust verspüren, sich die 1000000-ste Entprellung anzuschauen. Oder man nimmt einfach bewährte Lösungen:
1 | /************************************************************************/
|
2 | /* */
|
3 | /* Debouncing 8 Keys */
|
4 | /* Sampling 4 Times */
|
5 | /* */
|
6 | /* Author: Peter Dannegger */
|
7 | /* */
|
8 | /************************************************************************/
|
9 | |
10 | // Target: ATmega48
|
11 | |
12 | #include <util/atomic.h> // need "--std=c99" |
13 | |
14 | #define F_CPU 8e6 // 8MHz
|
15 | |
16 | #define KEY_PIN PINB
|
17 | #define KEY_PORT PORTB
|
18 | #define KEY_DDR DDRB
|
19 | #define KEY0 0
|
20 | #define KEY1 1
|
21 | #define KEY2 2
|
22 | #define KEY3 3
|
23 | #define KEY4 4
|
24 | #define KEY5 5
|
25 | #define KEY6 6
|
26 | #define KEY7 7
|
27 | |
28 | #define LED_DDR DDRD
|
29 | #define LED_PORT PORTD
|
30 | #define LED0 0
|
31 | #define LED1 1
|
32 | #define LED2 2
|
33 | #define LED3 3
|
34 | #define LED4 4
|
35 | #define LED5 5
|
36 | #define LED6 6
|
37 | #define LED7 7
|
38 | |
39 | |
40 | uint8_t key_state; // debounced and inverted keystate: |
41 | // bit = 1: key pressed
|
42 | uint8_t key_press; // keypress detect |
43 | |
44 | |
45 | ISR( TIMER0_COMPA_vect ) // every 10ms |
46 | {
|
47 | static uint8_t ct0, ct1; // 8 * 2bit counters |
48 | uint8_t i; |
49 | |
50 | i = ~KEY_PIN; // read keys (low active) |
51 | i ^= key_state; // key changed ? |
52 | ct0 = ~( ct0 & i ); // reset or count ct0 |
53 | ct1 = ct0 ^ (ct1 & i); // reset or count ct1 |
54 | i &= ct0 & ct1; // count until roll over ? |
55 | key_state ^= i; // then toggle debounced state |
56 | key_press |= key_state & i; // 0->1: keypress detect |
57 | }
|
58 | |
59 | |
60 | uint8_t get_key_press( uint8_t key_mask ) |
61 | {
|
62 | ATOMIC_BLOCK(ATOMIC_FORCEON){ // read and clear atomic ! |
63 | key_mask &= key_press; // read key(s) |
64 | key_press ^= key_mask; // clear key(s) |
65 | }
|
66 | return key_mask; |
67 | }
|
68 | |
69 | |
70 | int main( void ) |
71 | {
|
72 | TCCR0A = 1<<WGM01; // T0 Mode 2: CTC |
73 | TCCR0B = 1<<CS02 | 1<<CS00; // divide by 1024 |
74 | OCR0A = F_CPU / 1024 * 10e-3 - .5; // 10ms |
75 | TIMSK0 = 1<<OCIE0A; // enable T0 interrupt |
76 | |
77 | KEY_DDR = 0; // input |
78 | KEY_PORT = 0xFF; // pullups on |
79 | LED_PORT = 0xFF; // LEDs off (low active) |
80 | LED_DDR = 0xFF; // LED output |
81 | key_state = ~KEY_PIN; // no action on keypress during reset |
82 | sei(); |
83 | |
84 | for(;;){ // main loop |
85 | if( get_key_press( 1<<KEY0 )) |
86 | LED_PORT ^= 1<<LED0; // toggle LED0 on press KEY0 |
87 | |
88 | if( get_key_press( 1<<KEY1 )) |
89 | LED_PORT ^= 1<<LED1; |
90 | |
91 | if( get_key_press( 1<<KEY2 )) |
92 | LED_PORT ^= 1<<LED2; |
93 | |
94 | if( get_key_press( 1<<KEY3 )) |
95 | LED_PORT ^= 1<<LED3; |
96 | |
97 | if( get_key_press( 1<<KEY4 )) |
98 | LED_PORT ^= 1<<LED4; |
99 | |
100 | if( get_key_press( 1<<KEY5 )) |
101 | LED_PORT ^= 1<<LED5; |
102 | |
103 | if( get_key_press( 1<<KEY6 )) |
104 | LED_PORT ^= 1<<LED6; |
105 | |
106 | if( get_key_press( 1<<KEY7 )) |
107 | LED_PORT ^= 1<<LED7; |
108 | }
|
109 | }
|
Peter
> Ansatz so OK? > bei einem Keypress Nein. Das, was du Keypress nennst, ist eine Flanke, also ein sich änderndes Signal. Davon macht ein Taster viele, nennt sich prellen, sogar so viele so schnell nacheinander, daß jede Interruptleitung damit überfahren wird. Daher ist das bereits im Ansatz falsch. Frage den aktiellen Tastenzustand in regelmässigen Zeitintervallen (länger als das Prellen der Taster, schnell genug um kurze Tastendrücke zu erfassen) ab. Das kann in der Programmhauptschleife oder in einer Interrupt-Routine erfolgen. Zeitintervalle kommen nicht zu schnell, sondern eben zeitlich (ausreichend) stabil, und es ist vollkommen wurscht, ob du bei so einem Zeitintervall eine offene, gedrückte, oder gerade an der Grenze befindliche Taste einliest, du liest auf jeden Fall einen Zustand ein.
Hallo, es gibt von Jack Ganssle einen netten Artikel über Tastenprellen und -entprellen. Er hat einen Haufen gängiger Taster analysiert und zeigt das Prellverhalten - das einen manchmal sehr überrascht. Im folgenden gibt es einige Anregungen zum Entprellen in Software. Hier der Link: http://www.ganssle.com/debouncing.htm Ist auf englisch, aber vielleicht hilft es dem einen oder anderen. Viele Grüße, ER!K http://www.chip45.com
Einfacher ist es, wenn du nicht auf einen Tastendruck wartest und dann eine Aktion auslöst, sondern wenn du umgekehrt den Zustand der Tasten in regelmässigen Abständen (z.B. per Timer-Interrupt alle 50 Millisekunden oder in der Hauptschleife) einliest und je nach Zustand eine Aktion auslöst. Vorteil: 1. Der Taster muss nicht entprellt werden. 2. Die Benutzerinteraktion passiert zu genau definierten Zeitpunkten, es pfuscht dir also nicht irgendwo ein Interrupt dazwischen.
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.