www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik entprellen nach Dannegger


Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
die Entprellung mit
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
{
    if ( ! (*port & (1 << pin)) )
    {
        /* Pin wurde auf Masse gezogen, 100ms warten   */
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz
        _delay_ms(50); 
        if ( *port & (1 << pin) )
        {
            /* Anwender Zeit zum Loslassen des Tasters geben */
            _delay_ms(50);
            _delay_ms(50); 
            return 1;
        }
    }
    return 0;
}


Funktionierte auf Anhieb.

Nun wollte ich mich an die Entprellung nach Dannegger wagen bekomme sie 
aber nicht zum laufen. Umgebung ist ein STK 500 mit Atmega8, Taster sind 
auf PORTB, LEDs auf PORTC, µC auf 4Mhz.
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                      With Repeat Function                            */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                      danni@specs.de                                  */
/*                                                                      */
/************************************************************************/
 
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
#ifndef F_CPU
#define F_CPU           4000000                   // processor clock frequency
#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         DDRC
#define LED_PORT        PORTC
#define LED0            0
#define LED1            1
#define LED2            2
 
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
 
 
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;
  }
}
 
///////////////////////////////////////////////////////////////////
//
// 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;
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}
 

int main( void )
{
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 
  TCCR0 = (1<<CS02)|(1<<CS00);       // divide by 1024
  TIMSK = 1<<TOIE0;               // enable timer interrupt
 
  LED_PORT = 0xFF;
  LED_DDR =  0xFF;                     // long press: task 2
 

  sei();

  PORTC &= ~(1<<PC5);                  // LED5 zum Testen einschalten 

 while(1)
    {

     if( get_key_short( 1<<KEY1 )) PORTC &= ~(1<<PC1); //mit entprellen 

    

     if ( !(PINB & (1<<PINB4)) ) PORTC &= ~(1<<PC4); // Ohne entprellen LED4 ein 
    
    }
           
      
} 


Die Test LEDs 5 und 4 gehen jeweils an nur die LED 1 mit dem entprellen 
nicht, ich sehe das Problem irgend wie nicht :(.

Danke für die Tips

lg Malte

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hat sich erledigt, die hardware war es ;)

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eine Sache ist da noch, wie kann ich die routine auslagern so das ich 
sie in einem extra debounce.c File habe ?

wenn ich eine debounce.h erzeuge
#ifndef F_CPU
#define F_CPU           4000000                   // processor clock frequency
#warning kein F_CPU definiert
#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         DDRC
#define LED_PORT        PORTC
#define LED0            0
#define LED1            1
#define LED2            2


meine debounce.c
#include "debounce.h"
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 

 
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
 

 
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;
  }
}
 
///////////////////////////////////////////////////////////////////
//
// 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;
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}

und main.c
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#include "debounce.h"



int main( void )
{
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
  TIMSK = 1<<TOIE0;        // enable timer interrupt
 
  LED_PORT = 0xFF;
  LED_DDR = 0xFF;                     
 
  sei();
 
  while(1){
    if( get_key_short( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;
 
    if( get_key_long( 1<<KEY1 ))
      LED_PORT ^= 1<<LED2;
 
                                                  // single press and repeat
 
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      uint8_t i = LED_PORT;
 
      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      
    }
  }
}

Funktioniert es nicht mehr... vielleicht übersehe ich da auch wieder was 
:)

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!

Probier mal #include "debounce.c"

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

woher soll der Compiler, wenn er die main.c kompiliert, denn wissen, 
dass es eine Funktion get_key_short gibt?

Das kann man ihm auf zwei verschiedene Weisen bekannt machen:

1) Wie Alex vorschlägt, die .c includen. Das würde ich 
Holzhammer-Methode nennen :)
2) Wie allgemein üblich: Funktionsprototypen in die .h schreiben. Das 
sieht so aus:
uint8_t get_key_rpt( uint8_t key_mask );

Damit ist klar getrennt: In der .h steht alles, was man nach außen hin 
wissen muss (wie man eine Funktion aufruft, sínnvollerweise auch, was 
sie tut (Dokumentation) und ggf. einige defines zur Anpassung...) In der 
.c steht nur noch "interner" Code, den du auch beliebig ersetzen 
könntest, solange er noch das gleiche tut. Wie er genau aussieht, 
interessiert deine main ja nicht, sondern nur, was er tut.

Wichtig: Im zweiten Fall muss man noch irgendwie dafür sorgen, dass die 
.c trotzdem kompiliert und dazugelinkt wird. Zum Beispiel, indem man im 
Beispielmakefile zu SRC noch debounce.c hinzufügt.

MfG, Heiko

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned char get_key_press( unsigned char key_mask );
unsigned char get_key_rpt( unsigned char key_mask );
unsigned char get_key_short( unsigned char key_mask );
unsigned char get_key_long( unsigned char key_mask );

das habe ich noch in die header datei eingefügt und zack es ging, so 
langsam blicke ich es glaube ich...

Autor: Bernd O. (bitshifter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alex schrieb:
> Hi!
>
> Probier mal #include "debounce.c"
Das ist ganz sicher der falsche Weg.

Ziel der Trennung von Code-Teilen ist es, separate Objektfiles zu 
erzeugen, die der Linker dann verbindet.
Die Header-Datei soll das enthalten, was der Verwender des Objectfiles 
benötigt - aber eben nur das. Sämtliche Implementierungsdetails sollten 
ausschliesslich in der jeweiligen C-Datei oder einem separaten Header, 
der vom Verwender nicht eingebunden wird gekapselt sein.

So ist es möglich, Module unabhängig voneinander zu ändern und - viel 
wichtiger - man erhält ein sauber getrenntes System, bei dem nicht 
kreuz- und quer über viele Dateien hinweg Variablen geschrieben werden.

@Malte:
Die Initialisierung der Tasten solltest Du auch noch in eine Funktion 
kapseln. Es ist einfach besser gekapselt, wenn sich debounce.* komplett 
um die verwendeten Pins kümmert:

void debounce_init(void)
{
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
}


Gruß,
Bernd

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich bin gerade bei meinem ersten größeren Projekt und beschäftige mich 
eigentlich nur damit Struktur rein zu bekommen. Es geht um eine einfache 
Temperatur Steuerung mit Display, nichts wildes aber wenn man es sauber 
aufbauen will muss man sich ganz schön in die Grundlagen fuchsen.

Da kommt gerade einiges zusammen, mit entprellen, LCD Display, 
Festkommaarithmetik, ADC, PWM, aufs EEPROM schreiben... ich versuche das 
jetzt gut auf zu teilen das alles übersichtlich bleibt...

deinen tipp habe ich schon beherzigt ;), danke :D

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.