Forum: Compiler & IDEs Entprellung Ansatz so OK?


von vollfreak (Gast)


Lesenswert?

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

von Bobetsch (Gast)


Lesenswert?

Das liest sih nicht freakig,
eher honkig !

von Moog (Gast)


Lesenswert?

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 :)

von Peter D. (peda)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

> 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.

von Erik L. (Firma: chip45) (uc-erik)


Lesenswert?

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

von P. M. (o-o)


Lesenswert?

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.

von vollfreak (Gast)


Lesenswert?

vielen Dank an Alle für die nützlichen Hinweise!

v

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.