Probleme mit Tastenentprellung get_key_short/get_key_long

Gast #3319912
Lesenswert?

Hallo,

ich verwende folgenden Code auf einem Atmega8:
1
// ----------------------------------------------------------------------------
2
// INCLUDES
3
// ----------------------------------------------------------------------------
4

5
#include <stdint.h>      
6
#include <avr/io.h>        
7
#include <avr/interrupt.h>    
8
#include <inttypes.h>      
9
#include <avr/wdt.h>            
10
#include <util/delay.h>      
11

12

13
// ----------------------------------------------------------------------------
14
// DEFINES
15
// ----------------------------------------------------------------------------
16
#ifndef F_CPU
17
#define F_CPU           8000000UL                   // processor clock frequency 8Mhz
18
#endif
19

20
#define REPEAT_START    41                       
21
#define REPEAT_NEXT     83
22

23
#define LED      PD3    
24

25
// Port Defines
26
#define PORTLED    PORTD
27

28
// --------------------------------------------------------------------------------------------
29
// Funktionsdeklarationen
30
// --------------------------------------------------------------------------------------------
31
void init_ports(void);     // Initialisiert die Ports, Enable global Interrupt
32
void init_timer1(void);   // Initialisiert den Timer1 16-bit
33

34
uint8_t get_key_press_PIND_high( uint8_t key_mask );
35
uint8_t get_key_state_PIND_high( uint8_t key_mask );
36
uint8_t get_key_rpt_PIND_high( uint8_t key_mask );
37
uint8_t get_key_short_PIND_high( uint8_t key_mask );
38
uint8_t get_key_long_PIND_high( uint8_t key_mask );
39

40

41
volatile uint8_t key_state_PIND_high;        // debounced and non-inverted key state: bit = 1: key pressed, liest den Zustand eines Ports ein gemäß der Maske
42
volatile uint8_t key_press_PIND_high;        // key press detect active high
43
volatile uint8_t key_rpt_PIND_high;
44

45

46
//Timer1 16-bit Compare Match B Interrupt Service Routine
47
ISR (TIMER1_COMPB_vect){
48
  static uint8_t u8Entprellcounter;
49
  u8Entprellcounter++;              
50
  if (u8Entprellcounter >= 3){            // alle 12ms Entprellfunktionen aufrufen
51
    // Entprellen des PIND active high
52
    static uint8_t ct0_PIND_high, ct1_PIND_high, rpt_PIND_high;
53
      uint8_t i_PIND_high;
54
       
55
      i_PIND_high = key_state_PIND_high ^ PIND;               // key changed?, not inverted!
56
      ct0_PIND_high = ~( ct0_PIND_high & i_PIND_high );              // reset or count ct0
57
      ct1_PIND_high = ct0_PIND_high ^ (ct1_PIND_high & i_PIND_high); // reset or count ct1
58
      i_PIND_high &= ct0_PIND_high & ct1_PIND_high;                    // count until roll over ?
59
      key_state_PIND_high ^= i_PIND_high;                             // then toggle debounced state
60
      key_press_PIND_high |= key_state_PIND_high & i_PIND_high;        // 0->1: key press detect
61
    
62
      if( (key_state_PIND_high & (1<<PD0)) == 0 )            // check repeat function
63
        rpt_PIND_high = REPEAT_START;                          // start delay
64
      if( --rpt_PIND_high == 0 ){
65
        rpt_PIND_high = REPEAT_NEXT;                            // repeat delay
66
        key_rpt_PIND_high |= key_state_PIND_high & (1<<PD0);
67
      }
68
      
69
    u8Entprellcounter = 0;                // Entprellcounter nullen
70
  }
71
  
72
  
73
  OCR1B = OCR1B+((F_CPU/8000000UL)*31999);                // Compare Match Register wieder vorladen, erzeugt ein Compare Match jede 4ms
74
  
75
}
76

77

78
/*Hauptprogramm Aufgaben:
79

80
Das Hauptprogramm
81
*/
82
int main(void)
83
{
84
  init_ports();                                  
85
  init_timer1();  
86

87
  // LED einschalten, dass man sieht, dass Spannung anliegt und µC läuft
88
  PORTLED &= ~( 1<<LED );  
89
  _delay_ms(300);
90
  PORTLED |= ( 1<<LED );
91

92
  while (1){
93
  
94
    if( get_key_short_PIND_high( 1<<PD0 )){
95
        PORTLED &= ~( 1<<LED );  
96
        _delay_ms(300);
97
        PORTLED |= ( 1<<LED );
98
    }
99
    
100
    if( get_key_long_PIND_high( 1<<PD0 )){
101
        PORTLED &= ~( 1<<LED );  
102
        _delay_ms(1000);
103
        PORTLED |= ( 1<<LED );
104
    }
105
  
106
  
107
  } // Ende main loop
108
} // Ende Hauptprogramm
109

110

111

112
// ----------------------------------------------------------------------------
113
// Funktionen
114
// ----------------------------------------------------------------------------
115

116
/*Funktion zum Initialisierein des µC*/
117
void init_ports(void) {
118

119
  // ===========================================================================================
120
  
121
  DDRB = 0x00;  
122

123
  DDRC = 0x00;              // Datenrichtungsregister zunächst alle Eingang
124
  
125
  DDRD = 0x00;              // Datenrichtungsregister zunächst alle Eingang 
126
  DDRD |= (1 << DDD3);    // LED als Ausgang
127
  PORTD |= (1 << PD1) | (1 << PD2) | (1 << PD3) | (1 << PD4);  // Pullups einschalten, LED ausschalten
128
  
129

130
  sei();                  // setzt globales Interrupt enable
131
  
132
  return;
133
}   
134

135
void init_timer1(void) {
136
  
137
  OCR1B = ((F_CPU/8000000UL)*31999);            // Berechnet den Compare Wert für 4ms bei max. 16Mhz Frequenz
138
  TIMSK |= (1 << OCIE1B);  
139
  TCNT1 = 0;                        
140
  TCCR1B |= (1 << CS10);    // kein Prescaler, Timer1 läuft maximal durch
141
  
142
  return;
143
}
144

145

146
// Funktion für Tastendruck-Erkennung Tasten gegen VCC
147
uint8_t get_key_press_PIND_high( uint8_t key_mask ) {
148
  cli();                                          // read and clear atomic !
149
  key_mask &= key_press_PIND_high;                     // read key(s)
150
  key_press_PIND_high ^= key_mask;                     // clear key(s)
151
  sei();
152
  return key_mask;
153
}
154

155
uint8_t get_key_state_PIND_high( uint8_t key_mask ){
156

157
  key_mask &= key_state_PIND_high;
158
  return key_mask;
159
}
160

161
uint8_t get_key_rpt_PIND_high( uint8_t key_mask )
162
{
163
  cli();                                          // read and clear atomic !
164
  key_mask &= key_rpt_PIND_high;                            // read key(s)
165
  key_rpt_PIND_high ^= key_mask;                            // clear key(s)
166
  sei();
167
  return key_mask;
168
}
169

170
uint8_t get_key_short_PIND_high( uint8_t key_mask )
171
{
172
  cli();                                          // read key state and key press atomic !
173
  return get_key_press_PIND_high( ~key_state_PIND_high & key_mask );
174
}
175

176
uint8_t get_key_long_PIND_high( uint8_t key_mask )
177
{
178
  return get_key_press_PIND_high( get_key_rpt_PIND_high( key_mask ));
179
}

Taster hängt an PD0 mit 10k Pulldown gegen GND und 10k in Reihe zum 
Portpin, um den Strom zu begrenzen.
LED hängt an PD3

Der Taster ist also active high, weswegen ich auch diese Zeile die 
Negierung gelöscht habe:
1
i_PIND_high = key_state_PIND_high ^ PIND

Das Problem ist, dass ich den Taster betätige, gedrückt lasse und nach 
kurzer Zeit <1s die LED für 300ms leuchtet, ohne dass ich die Taste 
loslasse.
Die Funktionen sollen doch aber erst beim Loslassen entscheiden, ob eine 
Taste gedrückt ist oder nicht. So kann nämlich nicht zwischen lang und 
kurz unterschieden werden...

Kann jemand helfen?
#3319962
Lesenswert?

> Der Taster ist also active high
aus welchem Grund?

Wenn dein taster aktiv high ist, dann ist das Einschalten der Pullup 
Widerstände kontraproduktiv. Vor allen Dingen dann, wenn du selber dann 
auch noch externe Pulldown Widerstände angebracht hast. Auf die Art 
kriegst du niemals einen sauberen low Pegel.
Auf einem AVR schliesst man die Taster active low an. Das ist das 
einfachste und macht am wenigsten Probleme. Gewöhn dich daran - das ist 
softwaremässig überhaupt kein Problem, bei den Abfragen dieses active 
low zu berücksichtigen und die Abfrage umzudrehen.

Empfehlung: schmeiss die Pulldown raus und hänge die Taster genau so an, 
wie 50 Millionen andere Programmierer weltweit auch. Und dann nimm den 
PeDa Code so wie er ist.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren