Forum: Mikrocontroller und Digitale Elektronik Ungewollte Reaktion auf entprellte Tasten


von René (Gast)


Lesenswert?

Wenn ich die untere Taste drücke, leuchten bei mir je nach Laune drei 
unterschiedliche LEDs an, (PD1, PD2 und PD4) wobei ich dies so nicht 
bewusst programmiert habe. Bei den anderen Tasten passiert gar nichts, 
obwohl jede Taste zu einer LED programmiert wurde.
Habe mit einem Multimeter die Pegel an den Tastenpins gechekt. Es wird 
bei einem Tastendruck immer nur der Pegel vom zugewiesenen Pin auf low 
gesetzt. Somit keine Kurzschlüsse, also sollte es so stimmen.

Daher suche ich den Fehler im Programm und finde ihn leider nicht.
Ich benutze zum Entprellen der Tasten die Programmcodes von Peter.

Ich habe zum suchen dieses Fehlers mein Programm soweit reduziert, 
sodass nur noch die Eingabe der Tasten mit einer LED Ausgabe vorhanden 
ist.
Wie man aus Main entnehmen kann, möchte ich mit jeder Taste eine andere 
LED ansteuern können, wobei hier nur die untere Taste reagiert und dabei 
willkürlich drei unterschiedliche LEDs ansteuert.
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include "main.h"
6
#include "lcd.h"
7
#include <avr/wdt.h>
8
#include <avr/interrupt.h>
9
#include <util/delay.h>
10
#include <inttypes.h>
11
 
12
#ifndef F_CPU
13
#define F_CPU           7372800                   // processor clock frequency
14
#warning kein F_CPU definiert
15
#endif 
16
 
17
#define KEY_DDR         DDRC
18
#define KEY_PORT        PORTC
19
#define KEY_PIN         PINC
20
#define KEY_mitte       7
21
#define KEY_links       3
22
#define KEY_rechts      4
23
#define KEY_oben    6
24
#define KEY_unten    2
25
#define ALL_KEYS        (1<<KEY_mitte | 1<<KEY_links | 1<<KEY_rechts | 1<<KEY_oben /*| 1<<KEY_unten*/)
26
 
27
#define REPEAT_MASK     (1<<KEY_mitte | 1<<KEY_links | 1<<KEY_rechts | 1<<KEY_oben /*| 1<<KEY_unten*/)       
28
#define REPEAT_START    50                        // after 500ms
29
#define REPEAT_NEXT     20                        // every 200ms
30
 
31
#define LED_DDR         DDRD
32
#define LED_PORT        PORTD
33
#define LED0            0
34
#define LED1            1
35
#define LED2            2
36
#define LED3      3
37
#define LED4            4
38
#define LED5      5
39
 
40
#define ADCINPUTS 8    // Anzahl der ADC Eingänge
41
 
42
volatile uint8_t key_state;                                // debounced and inverted key state:
43
                                                  // bit = 1: key pressed
44
volatile uint8_t key_press;                                // key press detect
45
 
46
volatile uint8_t key_rpt;                                  // key long press and repeat
47
48
49
void timer0()
50
{
51
  TCCR0 = (1<<CS02)|(1<<CS00);         // divide by 1024
52
  TCNT0 = (-72);  // preload for 10ms
53
  TIMSK |= 1<<TOIE0;                   // enable timer interrupt
54
}
55
 
56
ISR( TIMER0_OVF_vect )                            // every 10ms
57
{
58
  static uint8_t ct0, ct1, rpt;
59
  uint8_t i;
60
 
61
  TCNT0 = (-72);  // preload for 10ms
62
  i = key_state ^ ~KEY_PIN;                       // key changed ?
63
  ct0 = ~( ct0 & i );                             // reset or count ct0
64
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
65
  i &= ct0 & ct1;                                 // count until roll over ?
66
  key_state ^= i;                                 // then toggle debounced state
67
  key_press |= key_state & i;                     // 0->1: key press detect
68
 
69
   if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
70
    rpt = REPEAT_START;                          // start delay
71
  if( --rpt == 0 )
72
  {
73
    rpt = REPEAT_NEXT;                            // repeat delay
74
    key_rpt |= key_state & REPEAT_MASK;
75
  }
76
}
77
78
///////////////////////////////////////////////////////////////////
79
//
80
// check if a key has been pressed. Each pressed key is reported
81
// only once
82
//
83
uint8_t get_key_press( uint8_t key_mask )
84
{
85
  cli();                                          // read and clear atomic !
86
  key_mask &= key_press;                          // read key(s)
87
  key_press ^= key_mask;                          // clear key(s)
88
  sei();
89
  return key_mask;
90
}
91
 
92
///////////////////////////////////////////////////////////////////
93
//
94
// check if a key has been pressed long enough such that the
95
// key repeat functionality kicks in. After a small setup delay
96
// the key is reported being pressed in subsequent calls
97
// to this function. This simulates the user repeatedly
98
// pressing and releasing the key.
99
//
100
uint8_t get_key_rpt( uint8_t key_mask )
101
{
102
  cli();                                          // read and clear atomic !
103
  key_mask &= key_rpt;                            // read key(s)
104
  key_rpt ^= key_mask;                            // clear key(s)
105
  sei();
106
  return key_mask;
107
}
108
 
109
///////////////////////////////////////////////////////////////////
110
//
111
// check if a key is pressed right now
112
//
113
uint8_t get_key_state( uint8_t key_mask ) 
114
{
115
  key_mask &= key_state;
116
  return key_mask;
117
}
118
 
119
///////////////////////////////////////////////////////////////////
120
//
121
uint8_t get_key_short( uint8_t key_mask )
122
{
123
  cli();                                          // read key state and key press atomic !
124
  return get_key_press( ~key_state & key_mask );
125
}
126
 
127
///////////////////////////////////////////////////////////////////
128
//
129
uint8_t get_key_long( uint8_t key_mask )
130
{
131
  return get_key_press( get_key_rpt( key_mask ));
132
}
133
134
135
void declaration()
136
{
137
/*  WDTCR = (1<<WDTOE);
138
  WDTCR &= ~(1<<WDE);  // Watchdog deaktivieren */
139
  DDRB = 0xFF; // Blaue LED: Ausgang
140
  PORTB &= ~(1<< PB0); 
141
  DDRC = 0x00; // Eingänge
142
  DDRC = ((1 << DDC0) | (1 << DDC1)) ; // PC0-1 Ausgang
143
  PORTC = 0xFF;
144
  PORTC &= ~((1<<PC0) | (1 <<PC1)); 
145
  
146
  DDRD = 0xFF;  // Alle Pins von Port D als Ausgang
147
  PORTD = (0<<PD0)| (0<<PD1)|(0<<PD2)|(0<<PD3)|(0<<PD4)|(0<<PD5)|(0<<PD6); 
148
  
149
  DDRA = 0xFF; // LCD Ausgänge
150
  DDRA &= ~((1<<PA6) | (1<<PA7));  // ADC Eingänge  
151
} 
152
 
153
int main( void )
154
{
155
156
157
    KEY_DDR &= ~ALL_KEYS;                // configure key port for input
158
    KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
159
    
160
  LED_PORT = 0xFF;
161
  LED_DDR = 0xFF;                     
162
 
163
  // Configure debouncing routines
164
165
166
  
167
  /*  IOs initialisieren */
168
169
  declaration();
170
  
171
172
    
173
  timer0();  // 10ms
174
  sei();
175
  
176
  while(1)
177
  {
178
    
179
  
180
  if(get_key_short(KEY_links)) PORTD ^= (1<<PD0);
181
  if(get_key_short(KEY_rechts)) PORTD ^= (1<<PD1);
182
  if(get_key_short(KEY_oben)) PORTD ^= (1<<PD2);
183
  if(get_key_short(KEY_unten)) PORTD ^= (1<<PD3);
184
  if(get_key_short(KEY_mitte)) PORTD ^= (1<<PD4);
185
  
186
  
187
    if(get_key_long(KEY_links)) PORTD ^= (1<<PD0);
188
    if(get_key_long(KEY_rechts)) PORTD ^= (1<<PD1);
189
    if(get_key_long(KEY_oben)) PORTD ^= (1<<PD2);
190
    if(get_key_short(KEY_unten)) PORTD ^= (1<<PD3);
191
    if(get_key_long(KEY_mitte)) PORTD ^= (1<<PD4);
192
  }
193
}

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

René schrieb:
> Daher suche ich den Fehler im Programm und finde ihn leider nicht.

Jaja.

Mit dem Kopf durch die Wand ohne Nachdenken.

Natürlich hast du einen dicken Fehler in deinem Programm. Der besteht 
aber nicht darin, daß du etwas falsch geschrieben hast, sondern darin, 
daß du dir überhaupt keinen Gedanken über irgend einen Algorithmus 
gemacht hast.

Also der Reihe nach:
1. Tasten kann man nicht einfach so, quasi ad hoc abrufen, sondern man 
muß eine Vorgeschichte beachten: war die Taste bereits gedrückt und wenn 
wie lange? Wenn ungedrückt, wie lange, länger als Entprellzeit? Sowas 
muß man am besten im internen Uhrprogramm erledigen.

2. Mache nicht alles in einem Klumpen, sondern teile die Aufgaben 
logisch auf. Also aus den Tastenabfragen Botschaften (neudeutsch: 
"events") generieren und diese in eine Warteschlange aka 
"Ereignispuffer" schreiben.

3. Im Grundprogramm die "events" der Reihe nach aus dem Ereignispuffer 
entnehmen und zweckdienlich verarbeiten. Quasi die generierten Ereinisse 
verbrauchen.

4. Dein Grundprogramm sollte so einen Murks:

  if(get_key_short(KEY_rechts)) PORTD ^= (1<<PD1);

weder tun, noch überhaupt sich mit irgendwelchen Ports und den Bits 
darin befassen. Das ist Sache des Tastaturtreibers (bei mir: 
Tasten-Bonze...).

Im Grundprogramm sollte es sinngemäß etwa so aussehen:

int event;

...
immerzu:
  event = GetEvent();
  if (event==evTasteLinks) ReagiereAufTasteLinks();
  if (event==evTasteRechts) ReagiereAufTasteRechts();
goto immerzu;

ich häng dir mal zum verstehenden Lesen ne Tastenabfrage für eine ganze 
Breitseite von Tasten dran. Das ist zwar dramatisch mehr, als du jemals 
brauchen wirst, aber du kannst dabei sehen, wie sowas gemacht wird. 
Diese Tastenabfrage kennt 2 unterschiedlich lange Repetierzeiten, eine 
erste längere und für alle weiteren Repetierungen eine zweite kürzere. 
sowas wird im Allgemeinen als angenehmer empfunden als nur eine 
Repetierzeit.

W.S.

von René (Gast)


Lesenswert?

Fehler gefunden:

  if(get_key_short(1<<KEY_links)) LED_PORT ^= (1<<LED0);
  if(get_key_short(1<<KEY_rechts)) LED_PORT ^= (1<<LED1);
  if(get_key_short(1<<KEY_oben)) LED_PORT ^= (1<<LED2);
  if(get_key_short(1<<KEY_unten)) LED_PORT ^= (1<<LED3);
  if(get_key_short(1<<KEY_mitte)) LED_PORT ^= (1<<LED4);

1<<KEY_links statt KEY_links


Kein konstruktiver Beitrag W.S!!!!!

von Yoschka (Gast)


Lesenswert?

René schrieb:
> Kein konstruktiver Beitrag W.S!!!!!

Was bist Du denn für ein A...l Rene?
Da will Dir jemand zu besserem Code verhelfen und dann das.
Geh weg!

von René (Gast)


Lesenswert?

Ich finde es eher A***** wenn man ein 1500 Zeilen Programm so 
komprimiert, dass ich hier was posten kann um dann zu hören, dass das 
scheiße gegliedert ist^^.

von S. Landolt (Gast)


Lesenswert?

Also ich bin auch der Meinung, dass statt der fünf "!" ein "m.E." 
angebrachter gewesen wäre.
Und "1500 Zeilen Programm" ohne die Grundmodule einzeln getestet zu 
haben? - keine gute Vorgehensweise.

von Peter (Gast)


Lesenswert?

René schrieb:
> Kein konstruktiver Beitrag W.S!!!!!

Dein Programm ist trotzdem schlecht. Klar funktioniert es aber da dreht 
es einem echt den Magen um. 100% Zustimmung zu W.S. Beitrag.

von René (Gast)


Lesenswert?

S. Landolt schrieb:
> Und "1500 Zeilen Programm" ohne die Grundmodule einzeln getestet zu
> haben? - keine gute Vorgehensweise.

Habe ich getestet und daher mich auch gewundert, dass es nicht mehr 
ging. Habe bei der Hälfte des Codes Key_mitte statt 1<<Key_mitte stehen.

Peter schrieb:
> Dein Programm ist trotzdem schlecht. Klar funktioniert es aber da dreht
> es einem echt den Magen um. 100% Zustimmung zu W.S. Beitrag.

Stimme ich nicht zu, dies ist ein Projekt welches sich immer weiter 
entwickelt und aufbaut. Jedes mal alles neu aufzusetzen würde viel zu 
viel Zeit in Anspruch nehmen.
Für ein fertiges Produkt würde ich zu stimmen.
Im Grunde teste ich mehrere Funktionen nach und nach, die ich dazu baue.

von Vlad T. (vlad_tepesch)


Lesenswert?

René schrieb:
> Stimme ich nicht zu, dies ist ein Projekt welches sich immer weiter
> entwickelt und aufbaut. Jedes mal alles neu aufzusetzen würde viel zu
> viel Zeit in Anspruch nehmen.

deswegen modularisiert man das von Anfang an. Das ist genau das, was WS 
dir versucht hat zu erklären.
Macht man es so wie du, entwickelt sich das Programm mit jeder 
Erweiterung zu einem immer größerem Misthaufen, den keiner durchschaut. 
Irgendwann ist es dann so groß, dass man es doch komplett wegschmeißt 
und zu großen Teilen redesignt und neuschreibt.

Das hat auch den angehmen Nebeneffekt, dass man Code viel einfacher 
wiederverwenden kann.

Hin und wieder könnte man als Anfänger auch mal Fachleuten was glauben, 
vor allem, wenn man sie gerade gefragt hat, um Hilfe zu bekommen.

von Peter D. (peda)


Lesenswert?

Vlad Tepesch schrieb:
> deswegen modularisiert man das von Anfang an. Das ist genau das, was WS
> dir versucht hat zu erklären.

Wenn man sich den Code einfach nur mal anschauen würde, statt sofort 
drüber zu lästern, dann sieht man leicht, daß er modular ist und daß er 
Events liefert.
Nur kann man schon beim Aufruf auswählen, welches Event einen 
interessiert. Man muß sie also hinterher nicht extra 
auseinanderklamüsern.

Letztendlich war der Fehler ja auch nicht riesig.
Die Entprellfunktionen erwarten ein Bitmaske und keine Bitnummer.
Kann jedem mal passieren.

: Bearbeitet durch User
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.