www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Tasten entprellen ohne _delay_ms()


Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, nachdem ja delay funktionen in ISR verpönt sind und cih im Moment
nciht weiter weiß, folgede Frage:

Wie (außer mit 2 delays wie im AVR GCC Tutorial beschrieben), kann ich
einen Pin entprellen?

In meinem jetzigen Programmcode frage ich pins(aktiv low am STK)
einfach so ab:

if (!(PIND & (1<<PIN0)))
{


}

Wie "entprelle" ich eine solche Abfrage?
Habe mir ebreits das beispiel angesehen, wo 8 PINS gleichzeitig
entprellt werden, allerdings war mir das etwas zu hoch...
Vielleciht kann mir jemand ein einfaches Beispiel zeigen?!
Danke!

Autor: müllo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
da gibt es mehrere Möglichkeiten...

(1) Wenn du mit externer Beschaltung arbeiten willst, baust du ein
R-C-Glied als Tiefpass oder mittels Flip-Flop an den Pin.

(2) Softwaremäßig gibt es auch unterschiedliche Lösungen. Bei den
meisten meiner "kleinen Projekte" nutze ich eh einen Timer, meist mit
einem Timertick von 0,1 ... 1 ms. In den entsprechenden ISR lasse ich
dann je nach Anzahl verschiedene Variablen (=> Zeitbasis) zählen. Im
Hauptprogramm frage ich dann meist ganzzahlig Vielfache
(modulo-Division) der Zählvariablen ab. Bei normalen Schaltern hast du
meist eine Prellzeit im Bereich zwischen 5...10 ms. Also könntest Du 10
Timerticks vergehen lassen und schaust dann, ob der Signalpegel noch
anliegt. Wenn nicht, ist der jeweiligen Schalter "nicht sicher"
geschaltet worden.

Viele Grüße
müllo

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt, das Beispiel von Peter Fleury ist mir zu hoch:

Allein verstehe ich diese Aussage nicht:

/*
   * read current state of keys (active-low),
   * clear corresponding bit in i when key has changed
   */

  i = key_state ^ ~PIND;   // key changed ?

1.)Warum  macht man ein XOR zwishcen keystate und dem INVERTIRTEN Pin?
2.)keystate enthält zu der Zeit des codes noch gar kein Pin Abfrage
3.)warum "clear bit, when key has changed"?
   Soweit ich weiß ist das Ergebnis eine XOR verknüpfung "1", wenn
die zwei verglichenen Bits unterschiedlich waren..?!

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@müllo:

Danke erstnal für die Antwort, hast du zu deiner Erklärung
möglicherweise irgendein Code Schnipsel?
Ich würde die Entprellung schon gerne softwaremäßig(und
ressourcenschonend) machen, wenn irgendwie möglich..

Autor: müllo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde die Sache auf die Schnelle so machen:

if (!(PIND & (1<<PIN0))) key = 1;
  else key = 0;
if ((timerticks % 10 == 1) & (!(PIND & (1<<PIN0))) & (key ==1))
  {
    //mach etwas...
  }
  else
  {
   //mach etwas nicht...
  }

Ohne Gewähr - habe ich gerade zwischen Aufräumen und Heimgehen
gemacht...

mfg
müllo

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Max,

mach mal nen Link auf den ganzen Code, damit man mitreden kann.

So mit 3 Zeilen ausm Zusammenhang raus geht das nicht.


Peter

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter: Hier ist de komplette Code(zum entprellen von 8 PINS)


/*********************************************************************** 
*****
 Title:    Debouncing 8 Keys
 Author:   Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury,
           based on algorithm of Peter Dannegger <danni@specs.de>
 Date:     December 2003
 Software: AVR-GCC 3.3
 Hardware: AT90S8515 at 4 Mhz, STK200 compatible starter kit

 Description:
 Demonstrates debouncing 8 keys. The state of the eight keys is
sampled
 four times using a timer interrupt. If a key is pressed longer than
 four seconds, the corresponding bit in the key_press global variable
is set.
 The main loop checks if a bit is set in this global variable and
resets
 the bit.

 Pressing the key connected to PIND2 increments a counter, while
pressing
 the key connected to PIND3 decrements the counter.
 The value of this counter is displayed using LEDs on PORTB.

************************************************************************ 
*****/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


#ifndef CTC1
#define CTC1 WGM12              // for compatibility with ATmega
#endif


#define XTAL    4000000L    // Crystal frequency in Hz
#define DEBOUNCE  200L    // debounce clock 200Hz = 5msec


/*
 * Module global variable, informs the main programm when a key is
pressed.
 * This variable must be declared 'volatile, since it is accessed
from
 * both interrupt und main loop.
 */
static volatile uint8_t key_press;


SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  static uint8_t key_state;  // debounced and inverted key state:
  static uint8_t ct0, ct1;      // holds two bit counter for each key
  uint8_t i;


  /*
   * read current state of keys (active-low),
   * clear corresponding bit in i when key has changed
   */
  i = key_state ^ ~PIND;   // key changed ?

  /*
   * ct0 and ct1 form a two bit counter for each key,
   * where ct0 holds LSB and ct1 holds MSB
   * After a key is pressed longer than four times the
   * sampling period, the corresponding bit in key_state is set
   */
  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

  /*
   * To notify main program of pressed key, the correspondig bit
   * in global variable key_press is set.
   * The main loop needs to clear this bit
   */
  key_press |= key_state & i;  // 0->1: key press detect

}


int debounce( void)
{
  uint8_t count = 0;


  TCCR1B = _BV(CTC1) + _BV(CS10);  // clear timer on compare match, no
prescaler
  OCR1A  =  XTAL/DEBOUNCE;         // timer = 5 msec
  TIMSK  = _BV(OCIE1A);            // enable Output Compare 1 overflow
interrupt

  DDRB  = 0x00;                    // use all pins on PortD for input
  PORTD = 0xff;                    // with pull-up enabled

  DDRB  = 0xff;                    // use all pins on PortB for output

  PORTB = 0xff;                    // turn all LED off

  sei();                           // enable interrupt

  for(;;)
  {
    if (key_press & _BV(2) )
    {
        // key 2 pressed, increment counter
        count++;
        PORTB = ~count;

        key_press = 0;
    }
    else if ( key_press & _BV(3) )
    {
        // key 3 pressed, decrement counter
        count--;
        PORTB = ~count;

        key_press = 0;
    }
  }

}

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@müllo:


if (!(PIND & (1<<PIN0))) key = 1;
  else key = 0;

Ist mir klar; einfache (invertierte) Abfrage, ob Switch gedrückt

if ((timerticks % 10 == 1) & (!(PIND & (1<<PIN0))) & (key ==1))

Diese Ziele kapier ich net ganz:
-->if ((timerticks % 10 == 1)

Du meinst, wenn der zustand nach 10 timertikt nach wie vor der selbe
geblieben ist?

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, irgendwie schnall cih das ganze net so ganz....
Das kann doch nicht so kompliziert sein?!
Im Prinzip suche ich en verenifachte Version von dem oben geposteten
Code von Peter Fleury...

Statt 8 Pins reicht mir einer

Autor: sni (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
3-4 mal mit etwas abstand in einer timer isr einlsen und nach einem
wechesl bzw. einer flanke 001 oder so ausschauen

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: müllo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
- Ich lassen einen Timer mit T=1ms laufen
- in der Interrupt-Service-Routine (ISR) für den Timerüberlauf lasse
ich die Variable timertick hochzählen (evtl. bei bestimmten Zählerstand
rücksetzen)
=> timerticks wird alle 1ms um 1 erhöht und meinetwegen beim Typ char
bei einem Zählerstand von 219 auf 0 zurückgesetzt

if (!(PIND & (1<<PIN0))) key = 1;
  else key = 0;
//key ist eine Hilfsvariable, mit der ich sehe, ob die Taste am PortD
gedrückt wurde

if ((timerticks % 10 == 1) & (!(PIND & (1<<PIN0))) & (key ==1))
//Wenn der Rest der Division durch 10 = 1 ist (Zählerstand
1,11,21,31...) und die Taste an PortD dauerhaft gedrückt ist, ist die
Tasteneingabe gültig (ansonsten wäre key auf 0 zurückgegangen)

  {
    //mach etwas bei gültiger Tastenabfrage
  }
  else
  {
   //mach etwas bei ungültiger Tastenabfrage
  }

Mfg
müllo

Autor: Baku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moinsen!
Manche machen sich das Leben echt schwer...
Wenn ich den Tastenzustand ohnehin in einem Timerinterrupt abfrage,
dann muss ich einfach nur das Abfrageintervall länger als die maximale
Prelldauer machen und fertig ist die Laube.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Max

"* clear corresponding bit in i when key has changed"

Ich würd mal sagen, da hat sich Peter Fleury verschrieben.
Wie Du ja richtig erkannt hast, wird das Bit gesetzt.


Ansonsten hat Dir ja ...HanneS... Lux den original Link gegeben und da
sind auch ne Menge Erklärungen dabei.
Es dauert nur etwas, diesen langen Thread zu lesen (aber es lohnt
sich).

Diese 8-Tasten-Routine hat nämlich den Vorteil, daß sie kürzer und
schneller als die meisten 1-Tasten Routinen ist.
Sie lohnt sich also schon bei nur einer Taste.

Und oftmals bleibt es ja nicht bei einer Taste. Man hat also das schöne
Gefühl, für die Zukunft vorgesorgt zu haben.


Peter

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
P.S.:

Sourcen bitte das nächste mal als Dateianhang.


Peter

Autor: müllo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Baku:

Klar kannst du es so einfach machen. Wenn man aber mehrere
unterschiedlichen Zeitbasen benötigt und keine freien Timer hat, hilft
die Sache mit den timerticks...ansonsten hast du natürlich Recht.

mfg
müllo

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.