Forum: Mikrocontroller und Digitale Elektronik Peter Daneggers Entprellung mag bei mir nicht :-(


von René (Gast)


Lesenswert?

Hallo,

ich bin gerade dabei, Peter Daneggers Entprellung aus dem Tutorial 
auszuprobieren mittels einer LED und einem Taster.
Die LED soll mittels des Tasters an- und ausgeschaltet werden. Leider 
reagiert diese nicht auf jeden Tastendruck, sodass die Entprellung wohl 
nicht richtig funktioniert.
Versucht habe ich das mit einem Atmega8 und internem Takt von 8Mhz.
LED an PB1, Taster an PB0 aktiv low.

Wäre nett, wenn jemand mal über den Code schauen könnte und mir ggf. den 
Fehler aufzeigt:
1
#ifndef F_CPU
2
#define F_CPU           8000000                  // processor clock frequency 8Mhz
3
#warning kein F_CPU definiert
4
#endif                 
5
6
7
/****************************************************************************/
8
/*                                      */
9
/*            Programm LED und Taster                */
10
/*                                      */
11
/****************************************************************************/
12
13
// ----------------------------------------------------------------------------
14
// INCLUDES
15
// ----------------------------------------------------------------------------
16
17
#include <stdint.h>
18
#include <avr/io.h>
19
#include <avr/interrupt.h>
20
#include <util/delay.h>
21
#include <inttypes.h>
22
23
24
25
// ----------------------------------------------------------------------------
26
// DEFINES
27
// ----------------------------------------------------------------------------
28
#define Taster  PB0    //Pin des Tasters
29
#define LED    PB1    //Pin der LED
30
31
//für die Entprellunsroutine
32
#define KEY_DDR         DDRB
33
#define KEY_PORT        PORTB
34
#define KEY_PIN         PINB
35
#define KEY0            0
36
#define KEY1            1
37
#define KEY2            2
38
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
39
 
40
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
41
#define REPEAT_START    50                        // after 500ms
42
#define REPEAT_NEXT     20                        // every 200ms
43
44
45
// ----------------------------------------------------------------------------
46
// Funktionsdeklarationen
47
// ----------------------------------------------------------------------------
48
void init(void);
49
uint8_t get_key_press( uint8_t key_mask );
50
51
52
// ----------------------------------------------------------------------------
53
// globale Variablen die durch Interrupts verändert werden
54
// ----------------------------------------------------------------------------
55
volatile uint8_t key_state;                                // debounced and inverted key state:
56
                              // bit = 1: key pressed
57
volatile uint8_t key_press;                                // key press detect
58
 
59
volatile uint8_t key_rpt;                                  // key long press and repeat
60
61
62
// ----------------------------------------------------------------------------
63
// globale Variablen des Programms
64
// ----------------------------------------------------------------------------
65
66
67
//Timer0 Overflow Interrupt
68
ISR( TIMER0_OVF_vect )                            // every 10ms
69
{
70
  static uint8_t ct0, ct1, rpt;
71
  uint8_t i;
72
 
73
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
74
 
75
  i = key_state ^ ~KEY_PIN;                       // key changed ?
76
  ct0 = ~( ct0 & i );                             // reset or count ct0
77
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
78
  i &= ct0 & ct1;                                 // count until roll over ?
79
  key_state ^= i;                                 // then toggle debounced state
80
  key_press |= key_state & i;                     // 0->1: key press detect
81
 
82
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
83
     rpt = REPEAT_START;                          // start delay
84
  if( --rpt == 0 ){
85
    rpt = REPEAT_NEXT;                            // repeat delay
86
    key_rpt |= key_state & REPEAT_MASK;
87
  }
88
}
89
90
//Das Hauptprogramm
91
int main()
92
{
93
//variablen für das Programm
94
char ledStatus=0;
95
  
96
  //Initialisieren der Ports über die Funktion init()
97
  init();
98
  
99
  while(1)
100
  
101
  
102
  //Zustand des Tasters abfragen mit Entprellfunktion
103
  if( (get_key_press( 1<<KEY0 )&&ledStatus==0)){
104
    PORTB &=~ (1 << LED);    //LED anschalten
105
    ledStatus=1;
106
  }
107
    
108
  else if ( get_key_press( 1<<KEY0 )){
109
    PORTB |= (1 << LED);    //LED ausschalten
110
    ledStatus=0;
111
  }
112
113
}
114
115
116
117
// ----------------------------------------------------------------------------
118
// Funktionen
119
// ----------------------------------------------------------------------------
120
121
/*Funktion zum Initialisierein des µC*/
122
123
void init(void) {
124
    // ------------------------------------------------------------------------
125
  // PORTB konfigurieren
126
  //
127
  //  B0 --> Eingang für Taster, active-low
128
  //  B1 --> Ausgang für LED, active-low
129
  // ------------------------------------------------------------------------
130
  
131
  DDRB = 0x00;      //Datenrichtungsregister zunächst alle Eingang 
132
  DDRB |= (1 << DDB1);   //PB1 als Ausgang schalten für LED
133
  PORTB = (1 << PB0) | (1 << PB1);      //an PB0 interne Pullup aktiviert (Eingang), LED anfangs ausschalten
134
  
135
  //-------------------------------------------------------------------------
136
  //Timer konfigurieren
137
  //-------------------------------------------------------------------------
138
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
139
  TIMSK = 1<<TOIE0;            // enable timer interrupt
140
  sei();                  //setzt globales Interrupt enable
141
}
142
  
143
144
145
/************************************************************************/
146
/*                                                                      */
147
/*                      Debouncing 8 Keys                               */
148
/*                      Sampling 4 Times                                */
149
/*                      With Repeat Function                            */
150
/*                                                                      */
151
/*              Author: Peter Dannegger                                 */
152
/*                      danni@specs.de                                  */
153
/*                                                                      */
154
/************************************************************************/
155
 
156
 
157
158
///////////////////////////////////////////////////////////////////
159
//
160
// check if a key has been pressed. Each pressed key is reported
161
// only once
162
//
163
uint8_t get_key_press( uint8_t key_mask )
164
{
165
  cli();                                          // read and clear atomic !
166
  key_mask &= key_press;                          // read key(s)
167
  key_press ^= key_mask;                          // clear key(s)
168
  sei();
169
  return key_mask;
170
}

von Peter D. (peda)


Lesenswert?

Du hast das Prinzip nicht verstanden.
Die Routine get_key_press() liefert immer nur das Ereignis des Drückens, 
nicht den Zustand des Gedrückt seins.
D.h. pro Drücken liefert immer nur ein Aufruf den Zustand "wahr".

Schmeißt Du nun durch logisches AND mit einer anderen Bedingung dieses 
Ereignis weg, ist es eben weg.


Peter

von René (Gast)


Lesenswert?

Hallo Peter,

vielen Dank für die Antwort.
In der Tat habe ich die Routine nicht verstanden, dafür bin ich noch zu 
frisch in dem Thema. Ich habe versucht, diese Routine als eine Art 
Blackbox zu verwenden, das ging wohl in die Hose.

Demnach müsste ich das so umstricken, oder?
1
if( (get_key_press( 1<<KEY0 ){   //Taste gedrückt?
2
// wenn die Taste gedrückt wird, prüfe, ob die LED vorher an oder aus war
3
if (ledStatus==1){     //LED war an--> ausschalten
4
PORTB |= (1 << LED); //LED ausschalten
5
}    
6
else{   //LED muss aus gewesen sein
7
PORTB &= ~(1 << LED);    //LED anschalten
8
}
}

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Ja, allerdings musst du ledStatus auch aktualisieren, sonst schaltet 
sich die LED nur aus. Einfacher ist es wenn du statt ledStatus direkt 
PORTB einliest und schaust ob das Bit für die LED gesetzt ist. Oder noch 
einfacher, mit XOR:
1
if( (get_key_press( 1<<KEY0 ){
2
  PORTB = PORTB ^  (1<<LED);
3
}

von René (Gast)


Lesenswert?

Hallo,

ja, den Status habe ich in der Eile vergessen, aber trotzdem danke für 
den Hinweis.
Habe das "Einstiegsprogramm" gerade getestet und es läuft nun, wie es 
soll und reagiert auf jeden Tastendruck.
Vielen, vielen Dank euch beiden.

Grüße
René

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.