mikrocontroller.net

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


Autor: René (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#ifndef F_CPU
#define F_CPU           8000000                  // processor clock frequency 8Mhz
#warning kein F_CPU definiert
#endif                 


/****************************************************************************/
/*                                      */
/*            Programm LED und Taster                */
/*                                      */
/****************************************************************************/

// ----------------------------------------------------------------------------
// INCLUDES
// ----------------------------------------------------------------------------

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>



// ----------------------------------------------------------------------------
// DEFINES
// ----------------------------------------------------------------------------
#define Taster  PB0    //Pin des Tasters
#define LED    PB1    //Pin der LED

//für die Entprellunsroutine
#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


// ----------------------------------------------------------------------------
// Funktionsdeklarationen
// ----------------------------------------------------------------------------
void init(void);
uint8_t get_key_press( uint8_t key_mask );


// ----------------------------------------------------------------------------
// globale Variablen die durch Interrupts verändert werden
// ----------------------------------------------------------------------------
volatile uint8_t key_state;                                // debounced and inverted key state:
                              // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect
 
volatile uint8_t key_rpt;                                  // key long press and repeat


// ----------------------------------------------------------------------------
// globale Variablen des Programms
// ----------------------------------------------------------------------------


//Timer0 Overflow Interrupt
ISR( TIMER0_OVF_vect )                            // every 10ms
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;
 
  TCNT0 = (uint8_t)(int16_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;                                 // count until roll over ?
  key_state ^= i;                                 // then toggle debounced state
  key_press |= key_state & i;                     // 0->1: key press detect
 
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}

//Das Hauptprogramm
int main()
{
//variablen für das Programm
char ledStatus=0;
  
  //Initialisieren der Ports über die Funktion init()
  init();
  
  while(1)
  
  
  //Zustand des Tasters abfragen mit Entprellfunktion
  if( (get_key_press( 1<<KEY0 )&&ledStatus==0)){
    PORTB &=~ (1 << LED);    //LED anschalten
    ledStatus=1;
  }
    
  else if ( get_key_press( 1<<KEY0 )){
    PORTB |= (1 << LED);    //LED ausschalten
    ledStatus=0;
  }

}



// ----------------------------------------------------------------------------
// Funktionen
// ----------------------------------------------------------------------------

/*Funktion zum Initialisierein des µC*/

void init(void) {
    // ------------------------------------------------------------------------
  // PORTB konfigurieren
  //
  //  B0 --> Eingang für Taster, active-low
  //  B1 --> Ausgang für LED, active-low
  // ------------------------------------------------------------------------
  
  DDRB = 0x00;      //Datenrichtungsregister zunächst alle Eingang 
  DDRB |= (1 << DDB1);   //PB1 als Ausgang schalten für LED
  PORTB = (1 << PB0) | (1 << PB1);      //an PB0 interne Pullup aktiviert (Eingang), LED anfangs ausschalten
  
  //-------------------------------------------------------------------------
  //Timer konfigurieren
  //-------------------------------------------------------------------------
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
  TIMSK = 1<<TOIE0;            // enable timer interrupt
  sei();                  //setzt globales Interrupt enable
}
  


/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                      With Repeat Function                            */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                      danni@specs.de                                  */
/*                                                                      */
/************************************************************************/
 
 

///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}


Autor: Peter Dannegger (peda)
Datum:

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

Autor: René (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?
if( (get_key_press( 1<<KEY0 ){   //Taste gedrückt?
// wenn die Taste gedrückt wird, prüfe, ob die LED vorher an oder aus war
if (ledStatus==1){     //LED war an--> ausschalten
PORTB |= (1 << LED); //LED ausschalten
}    
else{   //LED muss aus gewesen sein
PORTB &= ~(1 << LED);    //LED anschalten
}
}

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht 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:
if( (get_key_press( 1<<KEY0 ){
  PORTB = PORTB ^  (1<<LED);
}

Autor: René (Gast)
Datum:

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

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.