www.mikrocontroller.net

Forum: Compiler & IDEs Entprellung Ansatz so OK?


Autor: vollfreak (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich habe mich mal an ner Software Entprellung versucht und dabei 
folgenden Code produziert.

Die Idee dahinter:
1. bei einem Keypress starte ich einen Timer t (der zählt im interrupt 
alle 8ms hoch)

2. nach 16ms also t==2 wird geprüft ob der Keypress noch immer besteht.

3. wenn dies zutrifft und die Taste anschließend wieder losgelassen ist, 
wird ein Zähler hochgezählt.


Hab dabei leider festgestellt das mein Programm dieses nur einmal macht. 
Irgendwo scheint er nach dem 1sten Hochzählen festzusitzen.

Wäre dankbar wenn mir einer sagen würde wo der Fehler ist. Compiler 
schluckt den Code so wie er unten steht.


#include <avr/io.h>
#include "lcd-routines.h"
#include <avr/interrupt.h>
#include <stdlib.h>
#include <math.h>


#ifndef F_CPU
#define F_CPU 8000000L
#endif

uint16_t keypress;
char Buffer[20],keystate;
volatile uint16_t t,t2;

void WriteToLCD(void)
{
  lcd_clear();

  set_cursor(0,1);
  lcd_string(itoa(keypress, Buffer, 10));

}

int main(void)
{
  DDRB |= (0 << PB1); // set PB1 as input
  PORTB |= (1 << PB1); // activate pullup for PB1
  lcd_init();

  TIMSK  |= (1 << TOIE0); // enable overflow interrupt

  sei(); //enable global interrupt

  TCCR0 |= (0 << CS00) | (0 << CS01) | (1 << CS02);
  //prescale of 256  overflow at 8,192ms


  for(;;)
  {
  if ((keystate == 0) && (!(PINB & (1 << 1)))) //keypress detected
  {
    keystate=1;
    t=0;
  }
         if ((t==2) && (keystate==1) && (!(PINB & (1 << 1)))) //keypress
         still active after 16ms
  {
    keystate=2;
  }
  if ((keystate==2) && (PINB & (1 << 1))) //keyrelease detected =
         valid keypress
  {
    keypress++;
    WriteToLCD();
    keystate=0;
  }
  }
}

ISR(TIMER0_OVF_vect)
{
  t++; //overflow at 8,192ms
}


Gruß vollfreak

Autor: Bobetsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das liest sih nicht freakig,
eher honkig !

Autor: Moog (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau doch mal was passiert wenn Keystate 1 und der Zähler T > 2 ist.
(unwahrscheinlich)

Soll das eine "Übung" für ne Statemachine werden ?

Baue dir Breakpoints ein die am Display ausgegeben werden !
So lernst Du auch ein wenig zum Thema Debuging :)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann das Fahrrad jedesmal neu erfinden.
Man muß dann aber auch Verständnis aufbringen, daß nur wenige Lust 
verspüren, sich die 1000000-ste Entprellung anzuschauen.

Oder man nimmt einfach bewährte Lösungen:
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                                                                      */
/************************************************************************/

//                      Target: ATmega48

#include <util/atomic.h>                // need "--std=c99"

#define F_CPU           8e6             // 8MHz

#define KEY_PIN         PINB
#define KEY_PORT        PORTB
#define KEY_DDR         DDRB
#define KEY0            0
#define KEY1            1
#define KEY2            2
#define KEY3            3
#define KEY4            4
#define KEY5            5
#define KEY6            6
#define KEY7            7

#define LED_DDR         DDRD
#define LED_PORT        PORTD
#define LED0            0
#define LED1            1
#define LED2            2
#define LED3            3
#define LED4            4
#define LED5            5
#define LED6            6
#define LED7            7


uint8_t key_state;                      // debounced and inverted keystate:
                                        // bit = 1: key pressed
uint8_t key_press;                      // keypress detect


ISR( TIMER0_COMPA_vect )                // every 10ms
{
  static uint8_t ct0, ct1;              // 8 * 2bit counters
  uint8_t i;

  i = ~KEY_PIN;                         // read keys (low active)
  i ^= key_state;                       // 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: keypress detect
}


uint8_t get_key_press( uint8_t key_mask )
{
  ATOMIC_BLOCK(ATOMIC_FORCEON){         // read and clear atomic !
    key_mask &= key_press;              // read key(s)
    key_press ^= key_mask;              // clear key(s)
  }
  return key_mask;
}


int main( void )
{
  TCCR0A = 1<<WGM01;                    // T0 Mode 2: CTC
  TCCR0B = 1<<CS02 | 1<<CS00;           // divide by 1024
  OCR0A = F_CPU / 1024 * 10e-3 - .5;    // 10ms
  TIMSK0 = 1<<OCIE0A;                   // enable T0 interrupt

  KEY_DDR = 0;                          // input
  KEY_PORT = 0xFF;                      // pullups on
  LED_PORT = 0xFF;                      // LEDs off (low active)
  LED_DDR = 0xFF;                       // LED output
  key_state = ~KEY_PIN;                 // no action on keypress during reset
  sei();

  for(;;){                        // main loop
    if( get_key_press( 1<<KEY0 ))
      LED_PORT ^= 1<<LED0;              // toggle LED0 on press KEY0

    if( get_key_press( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;

    if( get_key_press( 1<<KEY2 ))
      LED_PORT ^= 1<<LED2;

    if( get_key_press( 1<<KEY3 ))
      LED_PORT ^= 1<<LED3;

    if( get_key_press( 1<<KEY4 ))
      LED_PORT ^= 1<<LED4;

    if( get_key_press( 1<<KEY5 ))
      LED_PORT ^= 1<<LED5;

    if( get_key_press( 1<<KEY6 ))
      LED_PORT ^= 1<<LED6;

    if( get_key_press( 1<<KEY7 ))
      LED_PORT ^= 1<<LED7;
  }
}


Peter

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ansatz so OK?
> bei einem Keypress

Nein.

Das, was du Keypress nennst, ist eine Flanke, also ein sich änderndes 
Signal.
Davon macht ein Taster viele, nennt sich prellen, sogar so viele so 
schnell nacheinander, daß jede Interruptleitung damit überfahren wird.

Daher ist das bereits im Ansatz falsch.

Frage den aktiellen Tastenzustand in regelmässigen Zeitintervallen 
(länger als das Prellen der Taster, schnell genug um kurze Tastendrücke 
zu erfassen) ab. Das kann in der Programmhauptschleife oder in einer 
Interrupt-Routine erfolgen. Zeitintervalle kommen nicht zu schnell, 
sondern eben zeitlich (ausreichend) stabil, und es ist vollkommen 
wurscht, ob du bei so einem Zeitintervall eine offene, gedrückte, oder 
gerade an der Grenze befindliche Taste einliest, du liest auf jeden Fall 
einen Zustand ein.

Autor: Erik Lins (Firma: chip45) (uc-erik)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
es gibt von Jack Ganssle einen netten Artikel über Tastenprellen und 
-entprellen. Er hat einen Haufen gängiger Taster analysiert und zeigt 
das Prellverhalten - das einen manchmal sehr überrascht. Im folgenden 
gibt es einige Anregungen zum Entprellen in Software.

Hier der Link: http://www.ganssle.com/debouncing.htm

Ist auf englisch, aber vielleicht hilft es dem einen oder anderen.

Viele Grüße,
ER!K

http://www.chip45.com

Autor: P. M. (o-o)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einfacher ist es, wenn du nicht auf einen Tastendruck wartest und dann 
eine Aktion auslöst, sondern wenn du umgekehrt den Zustand der Tasten in 
regelmässigen Abständen (z.B. per Timer-Interrupt alle 50 Millisekunden 
oder in der Hauptschleife) einliest und je nach Zustand eine Aktion 
auslöst.

Vorteil:
1. Der Taster muss nicht entprellt werden.
2. Die Benutzerinteraktion passiert zu genau definierten Zeitpunkten, es 
pfuscht dir also nicht irgendwo ein Interrupt dazwischen.

Autor: vollfreak (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen Dank an Alle für die nützlichen Hinweise!

v

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.