Tastenentpreller aus Tutorial - will nicht

Gast #1890123
Lesenswert?

Hallo,

habe das folgende Tutorial versucht nachzubauen:
http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29
(Komfortroutine (C für AVR))

Für eine LED funktioniert es. Wenn ich es aber mit zwei machen will, 
leuchtet eine LED an PD0 und geht danach aus.

1
if( get_key_short( 1<<KEY0 ))
2
LED_PORT ^= 1<<LED0;
3
 
4
if( get_key_long( 1<<KEY0 ))
5
LED_PORT ^= 1<<LED1;


Auch habe ich oft das Problem, dass das Programm abstürzt und nicht mehr 
reagiert, wenn ich zu oft auf den Knopf drücke. Und die Tasten reagieren 
auch nicht schnell genug. get_key_short dauert auch schon eine Ewigkeit 
bis die LED angeht.

benutze den internen Quarz 1MHz.

Woran liegt mein Problem?
Gast #1890180
Lesenswert?

1
/********************************************************************/
2
/*                                                                  */
3
/* 1LED 1Taster - Entprellung (bessere Version                      */
4
/*                                                                  */
5
/* active-low: ein Anschluss an den Port-Pin, der anderer an GND    */
6
/* Pull-Up Widerstand (10k) zwischen Port-Pin und VCC.              */
7
/*                                                                  */
8
/* PB0: Taster                                                      */
9
/* PD0: LED                                                         */
10
/*                                                                  */
11
/* Datum: 10.10.2010                                                */
12
/*                                                                  */
13
/********************************************************************/
14

15
#include <stdint.h>
16
#include <avr/io.h>
17
#include <avr/interrupt.h>
18

19
#ifndef F_CPU
20
#define F_CPU       1000000
21
#endif
22

23
#define KEY_DDR      DDRB
24
#define KEY_PORT    PORTB
25
#define KEY_PIN      PINB
26
#define KEY0      0
27
#define KEY1      1
28
#define KEY2      2
29
#define ALL_KEYS    (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
30

31
#define REPEAT_MASK    (1<<KEY1 | 1<<KEY2)        // repeat: key1, key2
32
#define REPEAT_START  50                // after 500ms
33
#define REPEAT_NEXT    20                // every 200ms
34

35
#define LED_DDR      DDRD
36
#define LED_PORT    PORTD
37
#define LED0      0
38
#define LED1      1
39
#define LED2      2
40

41
volatile uint8_t key_state;
42
volatile uint8_t key_press;
43
volatile uint8_t key_rpt;
44

45

46
ISR( TIMER0_OVF_vect ) {      // every 10ms
47
  static uint8_t ct0, ct1, rpt;
48
  uint8_t i;
49

50
  TCNT0 = (uint8_t)(uint16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
51

52
  i = key_state ^ ~KEY_PIN;      // Key changed?
53
  ct0 = ~( ct0 & i );          // reset or count ct0
54
  ct1 = ct0 ^ ( ct1 & i);        // reset or count ct1
55
  i &= ct0 & ct1;
56
  key_state ^= i;
57
  key_press |= key_state & i;
58

59
  if( (key_state & REPEAT_MASK) == 0 )
60
    rpt = REPEAT_START;
61
  if( --rpt == 0 ) {
62
    rpt = REPEAT_NEXT;        // repeat delay
63
    key_rpt |= key_state & REPEAT_MASK;
64
  }
65
}
66

67

68
// Pr¸fe ob eine Taste gedruekt wurde. Jeder Druck wird als eins gewertet
69
uint8_t get_key_press( uint8_t key_mask ) {
70
  cli();
71
  key_mask &= key_press;
72
  key_press ^= key_mask;
73
  sei();
74
  return key_mask;
75
}
76

77
// Pr¸fe ob eine Taste lange genug gedr¸ckt wurde
78
uint8_t get_key_rpt( uint8_t key_mask ) {
79
  cli();
80
  key_mask &= key_rpt;
81
  key_rpt ^= key_mask;
82
  sei();
83
  return key_mask;  
84
}
85

86
// Pr¸fe ob eine Taste kurz gedr¸ckt wurde
87
uint8_t get_key_short( uint8_t key_mask ) {
88
  cli();
89
  return get_key_press( ~key_state & key_mask );
90
}
91

92
// Pr¸fe ob eine Taste lang gedr¸ckt wurde
93
uint8_t get_key_long( uint8_t key_mask ) {
94
  cli();
95
  return get_key_press( get_key_rpt(key_mask) );
96
}
97

98

99

100
int main(void) {
101
  KEY_DDR &= ~ALL_KEYS;      // Taste fuer Eingabe
102
  KEY_PORT |= ALL_KEYS;        // PULL-UP Widerstand An
103

104

105
  TCCR0 = (1<<CS02)|(1<<CS00);  // durch 1024 dividieren
106
  TIMSK |= 1<<TOIE0;        // Timer-Interrupt aktivieren
107

108

109
  LED_PORT = 0xFF;
110
  LED_DDR = 0xFF;
111

112
  sei();
113

114
  while(1) {
115
    if( get_key_short( 1<<KEY0 ) )  
116
      LED_PORT ^= 1<<LED0;
117

118
    if( get_key_long( 1<<KEY0 ) )  
119
      LED_PORT ^= 1<<LED1;
120
  }
121
}
Gast #1890247
Lesenswert?

Gibt es ein Entpreller, der die LED sofort einschaltet wenn ich den 
Taster drücke?

als der code von oben funktioniert hat, hat er nur dann eingeschaltet, 
als ich den Taster losgelassen habe und dass nach nur bestimmten ms. 
Also so ist der Code garnicht zu gebrauchen. Oder ich hab irgendwo ein 
Fehler drin!
Gast #1890257
Lesenswert?

Den habe ich schon ausprobiert. Das Problem ist dann, dass wenn ich die 
Taste etwas länger gedrückt halte, er mir die LED blinken lässt. Beim 
loslassen der Taster wird die LED eingeschaltet oder ausgeschaltet. Dies 
kann ich nicht kontrollieren.
Persönliche Seite #1890271
Lesenswert?

Kann ich nicht nachvollziehen.

Ich hatte das Debounce Makro selbst auf dem Pollin Board getestet und es 
funktionierte wie vorgesehen
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Tasty_Reloaded

Den Quellcode kann man 1:1 für den Atmega8 übernehmen, es sind keine 
Anpassungen außer neu übersetzen nötig. Achtung: Auf dem Pollin-Board 
sind die Taster und LEDs active high
#1890440
Lesenswert?

Der Fehler ist meistens, daß Anfänger denken, wenn man die Taste 
losläßt, kommt durch Magie der entgegengesetzte Pegel aus der Luft 
geflogen und setzt sich auf den Pin.
Dem ist nicht so!

Bei Taste gegen GND braucht man einen Pullup bzw. bei Taste gegen VCC 
einen Pulldown.
Praktischer Weise kann man im AVR nen internen Pullup einschalten, man 
braucht also keine zusätzliche externe Komponente.

Wählt man nun doch Taste + zusätzlichen Pulldown, muß man die Bitlogik 
umkehren und das macht bekannter Weise unter C das "~" Zeichen.

Also sucht man sich die Zeile, wo der Pin eingelesen wird:
1
i = key_state ^ ~KEY_PIN;      // low active Key changed?
und dreht deren Logik um:
1
i = key_state ^  KEY_PIN;      // high active Key changed?


Peter
Gast #1890508
Lesenswert?

Peter Dannegger schrieb:
> Also sucht man sich die Zeile, wo der Pin eingelesen wird:i = key_state ^ 
~KEY_PIN;      // low active Key changed?
> und dreht deren Logik um:i = key_state ^  KEY_PIN;      // high active Key 
changed?

besser wird es dadurch auch nicht. get_key_long() funktioniert immer 
noch nicht und get_key_press() läuft erst, wenn die Taste losgelassen 
wird also besser wird es dadurch auch nicht!
Gast #1890585
Lesenswert?

Hey noch eine Frage

mit
1
while(1) {
2
    if( get_key_press( 1<<KEY0 ) )  
3
      LED_PORT ^= 1<<LED0;

konnte ich eine LED an und ausschalten.

Nun wollte ich dies in LCD ausprobieren. Dabei soll ein Text ausgegeben 
werden. Doch dies will er nicht machen. Mein Taster ist auf low mit GND 
verbunden. Erst wenn ich den Stecker des Taster (GND) ziehe, kommt die 
Meldung (***** BOOM *****).

Wo ist mein Problem?
Angehängte Dateien:
#1890596
Lesenswert?

RoyalFlush schrieb:
> besser wird es dadurch auch nicht. get_key_long() funktioniert immer
> noch nicht

get_key_long(), get_key_short() funktionieren nur, wenn beide benutzt 
werden für diese Taste.
Wie leicht zu sehen ist, rufen sie get_key_rpt() auf, d.h. die Taste muß 
in der REPEAT_MASK mit eingetragen sein!


> und get_key_press() läuft erst, wenn die Taste losgelassen
> wird also besser wird es dadurch auch nicht!

Also ist Deine Taste wohl doch gegen GND.


Peter
Persönliche Seite #1890597
Lesenswert?

Peter Dannegger schrieb:

> Stefan B. schrieb:
>> Achtung: Auf dem Pollin-Board
>> sind die Taster und LEDs active high
>
> Und die Kondis an den Tasten müssen raus !!!!!
> Die bewirken sonst, daß der CPU bei jedem Drücken kurz der Saft
> abgedreht wird.

Weiss ich und das Thema ist in der Artikelsammlung dokumentiert ;-)

Die Hardware von RoyalFlushs Aufbau kenne ich nicht. Es war nur ein 
Hinweis dann aufzupassen, wenn mein Quellcode vom Pollin Board 
betrachtet oder auf RoyalFlushs unbekannten Aufbau übertragen wird.

Autor:  RoyalFlush (Gast)
Datum: 10.10.2010 18:31
> Mein Taster ist auf low mit GND
> verbunden. Erst wenn ich den Stecker des Taster (GND) ziehe, kommt die
> Meldung (***** BOOM *****).

Taster könnte um 90° verdreht eingebaut sein und bereits im Ruhezustand 
eine elektrische Verbindung zu GND haben.
Persönliche Seite #1890605
Lesenswert?

Stefan B. schrieb:

> Taster könnte um 90° verdreht eingebaut sein und bereits im Ruhezustand
> eine elektrische Verbindung zu GND haben.

Es gibt Taster, die 4 Pins haben. je zwei auf einer Seite sind 
miteinander verbunden. Baut man einen solchen Taster 90° verdreht 
ein....
1
Richtig:
2
---------o   o--------
3
         |   |
4
         o   o
5

6
Falsch:
7
---------o---o--------
8
              
9
         o---o
#1890609
Lesenswert?

Stefan B. schrieb:
> Teste mal
>
>
1
>   // TCNT0 = (uint8_t)(uint16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  //
2
> preload for 10ms
3
>   i = (F_CPU / 1024.0) / 100.0 + 0.5;  // preload for 10ms
4
>   TCNT0 = 256 - i;
5
>
>
> Auf diese Art solltest du auch TCNT0 in main() initialisieren bevor du
> den imer0 mit sei() anschaltest.

Du hast recht, diese Zeile funktioniert nicht.
Aber sie ist nicht von mir.
Mein Code:
http://www.mikrocontroller.net/attachment/highlight/16197

Da hat also jemand s16 durch uint16_t ersetzt.
Richtig muß es aber int16_t sein, dann funktioniert es auch.


Peter

P.S.:
Der GCC hätte da ruhig ne Warnung aussprechen können.
Der ist ja sonst so geschwätzig und warnt gerne mal unnötiger Weise.

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