mikrocontroller.net

Forum: Compiler & IDEs Tastenentpreller aus Tutorial - will nicht


Autor: RoyalFlush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe das folgende Tutorial versucht nachzubauen:
http://www.mikrocontroller.net/articles/Entprellun...
(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.

if( get_key_short( 1<<KEY0 ))
LED_PORT ^= 1<<LED0;
 
if( get_key_long( 1<<KEY0 ))
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?

Autor: RoyalFlush (Gast)
Datum:

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welchen Code? Ich sehe keinen Code.

Autor: RoyalFlush (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
/********************************************************************/
/*                                                                  */
/* 1LED 1Taster - Entprellung (bessere Version                      */
/*                                                                  */
/* active-low: ein Anschluss an den Port-Pin, der anderer an GND    */
/* Pull-Up Widerstand (10k) zwischen Port-Pin und VCC.              */
/*                                                                  */
/* PB0: Taster                                                      */
/* PD0: LED                                                         */
/*                                                                  */
/* Datum: 10.10.2010                                                */
/*                                                                  */
/********************************************************************/

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU       1000000
#endif

#define KEY_DDR      DDRB
#define KEY_PORT    PORTB
#define KEY_PIN      PINB
#define KEY0      0
#define KEY1      1
#define KEY2      2
#define ALL_KEYS    (1<<KEY0 | 1<<KEY1 | 1<<KEY2)

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

#define LED_DDR      DDRD
#define LED_PORT    PORTD
#define LED0      0
#define LED1      1
#define LED2      2

volatile uint8_t key_state;
volatile uint8_t key_press;
volatile uint8_t key_rpt;


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

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

  i = key_state ^ ~KEY_PIN;      // Key changed?
  ct0 = ~( ct0 & i );          // reset or count ct0
  ct1 = ct0 ^ ( ct1 & i);        // reset or count ct1
  i &= ct0 & ct1;
  key_state ^= i;
  key_press |= key_state & i;

  if( (key_state & REPEAT_MASK) == 0 )
    rpt = REPEAT_START;
  if( --rpt == 0 ) {
    rpt = REPEAT_NEXT;        // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}


// Pr¸fe ob eine Taste gedruekt wurde. Jeder Druck wird als eins gewertet
uint8_t get_key_press( uint8_t key_mask ) {
  cli();
  key_mask &= key_press;
  key_press ^= key_mask;
  sei();
  return key_mask;
}

// Pr¸fe ob eine Taste lange genug gedr¸ckt wurde
uint8_t get_key_rpt( uint8_t key_mask ) {
  cli();
  key_mask &= key_rpt;
  key_rpt ^= key_mask;
  sei();
  return key_mask;  
}

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

// Pr¸fe ob eine Taste lang gedr¸ckt wurde
uint8_t get_key_long( uint8_t key_mask ) {
  cli();
  return get_key_press( get_key_rpt(key_mask) );
}



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


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


  LED_PORT = 0xFF;
  LED_DDR = 0xFF;

  sei();

  while(1) {
    if( get_key_short( 1<<KEY0 ) )  
      LED_PORT ^= 1<<LED0;

    if( get_key_long( 1<<KEY0 ) )  
      LED_PORT ^= 1<<LED1;
  }
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

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

Autor: RoyalFlush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Autor: RoyalFlush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: RoyalFlush (Gast)
Datum:

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

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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_Fun...

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

Autor: RoyalFlush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mist, da hatten sich unsere Antworten überschnitten :-)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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".

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:
i = key_state ^ ~KEY_PIN;      // low active Key changed?
und dreht deren Logik um:
i = key_state ^  KEY_PIN;      // high active Key changed?


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: RoyalFlush (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: RoyalFlush (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hey noch eine Frage

mit
while(1) {
    if( get_key_press( 1<<KEY0 ) )  
      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?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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....
Richtig:
---------o   o--------
         |   |
         o   o

Falsch:
---------o---o--------
              
         o---o

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan B. schrieb:
> Teste mal
>
>
>   // TCNT0 = (uint8_t)(uint16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  //
> preload for 10ms
>   i = (F_CPU / 1024.0) / 100.0 + 0.5;  // preload for 10ms
>   TCNT0 = 256 - i;
> 
>
> 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Autor: RoyalFlush (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.