Forum: Compiler & IDEs Tastenentpreller aus Tutorial - will nicht


von RoyalFlush (Gast)


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?

von RoyalFlush (Gast)


Lesenswert?

ok habe einen Fehler in meinem Code gefunden. nun leuchten die LEDs aber 
der Taster reagiert garnicht mehr!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Welchen Code? Ich sehe keinen Code.

von RoyalFlush (Gast)


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
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Teste mal
1
  // TCNT0 = (uint8_t)(uint16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
2
  i = (F_CPU / 1024.0) / 100.0 + 0.5;  // preload for 10ms
3
  TCNT0 = 256 - i;

Auf diese Art solltest du auch TCNT0 in main() initialisieren bevor du 
den imer0 mit sei() anschaltest.

von RoyalFlush (Gast)


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!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das Debounce-Makro im gleichen Artikel kann man relativ einfach so 
anpassen
Beitrag "Re: Entprellen für Anfänger"

von RoyalFlush (Gast)


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.

von RoyalFlush (Gast)


Lesenswert?

ok danke, hab deinen Code hinzugefügt und nun klappt es wie es sollte.

mit get_key_press( ... ) wird die LED direkt eingeschaltet.

von Stefan B. (stefan) Benutzerseite


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

von RoyalFlush (Gast)


Lesenswert?

ok bis auf get_key_long() funktioniert alles sehr gut. funktioniert 
get_key_long() vielleicht wegen der Änderung im Code mit TCNT0 ??? Oder 
woran könnte es liegen?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Mist, da hatten sich unsere Antworten überschnitten :-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Weiss ich nicht und ich habe auch im Moment nicht den Nerv da 
einzusteigen.

Die Änderung bei TCNT0 ist mir eingefallen, weil beim Originalcode im 
Simulator eben keine 10ms Timer0-Interrupts wie der Kommentar vorgibt 
aufgetreten sind. Daraufhin hatte ich mir die Formel "vorgeknöpft".

von Peter D. (peda)


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

von Peter D. (peda)


Lesenswert?

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.


Peter

von RoyalFlush (Gast)


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!

von RoyalFlush (Gast)


Angehängte Dateien:

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?

von Peter D. (peda)


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

von Stefan B. (stefan) Benutzerseite


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.

von Peter D. (peda)


Lesenswert?

RoyalFlush schrieb:
> Mein Taster ist auf low mit GND
> verbunden. Erst wenn ich den Stecker des Taster (GND) ziehe, kommt die
> Meldung (***** BOOM *****).

Taster kaputt.


Peter

von Stefan B. (stefan) Benutzerseite


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

von Peter D. (peda)


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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Zum Glück steht es im Wiki mit int16_t drin. Dort hatte ich nicht 
nachgesehen, sondern nur im Code von RoyalFlush oben.

von RoyalFlush (Gast)


Lesenswert?

ahh mein Fehler, da habe ich mich verschrieben.
Taster ist richtig eingebaut, ich hab also den Taster mit 4 Pins.

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.