Forum: Compiler & IDEs Tasterentprellung


von Michael (Gast)


Lesenswert?

Hi,

habe mir gerade mal Gedanken über eine Entprellroutine gemacht...
Würde das nicht ausreichen? Geht auch nur um das drücken des Tasters...

void debounce_switch()
{
  uint8_t debounce_count = 0;

  for(int i=0; i<8;++i)
    _delay_us(50);
    if(!(PINB & (1<<PINB0)))
      ++debounce_count;
    else
      debounce_count = 0;
}

Beste Grüße,
Michael

von Michael (Gast)


Lesenswert?

void debounce_switch()
{
  uint8_t debounce_count = 0;

  for(int i=0; i<8; ++i)
  {
    _delay_us(50);
    if(!(PINB & (1<<PINB0)))
      ++debounce_count;
    else
      debounce_count = 0;
  }
}

von Michael (Gast)


Lesenswert?

Will meinen Taster bzw. mehrere Taster im Main Loop dauernd abfragen...

von Michael (Gast)


Lesenswert?

void debounce_switch()
{
  for(uint8_t debounce_count=0; debounce_count<8; ++debounce_count)
  {
    _delay_us(50);
    if(!(PINB & (1<<PINB0)))
      ++debounce_count;
    else
    {
      debounce_count = 0;
      break;
    }
  }
}

Sorry... Aber das wäre der Code

von Karl H. (kbuchegg)


Lesenswert?

Du erhöhst deinen debounce_count 2 mal innerhalb der Schleife.
Ist an und für sich kein Beinbruch, dann werden halt einfach nur 4 
hintereinanderliegende 0-Bits schon akzeptiert.

Wie willst du die Funktion verwenden?


Entprellung

von Michael (Gast)


Lesenswert?

uint8_t debounce_switch(volatile uint8_t *port, uint8_t pin)
{
  for(uint8_t debounce_count=0; debounce_count<8; ++debounce_count)
  {
    _delay_us(500);
    if(*port & (1<<pin))
    {
      debounce_count = 0;
      return 0;
    }
  }

  return 1;
}

Habe es jetzt so abgeändert... Brauch es nur um einen Tastendruck zu 
entprellen, das loslassen ist uninteressant. Wenn der Schalter gedrückt 
wird, geht der Pin auf Massepegel.

Danke

von Michael (Gast)


Lesenswert?

uint8_t debounce_switch(volatile uint8_t *port, uint8_t pin)
{
  for(uint8_t debounce_count=0; debounce_count<8; ++debounce_count)
  {
    _delay_us(500);
    if(*port & (1<<pin))
    {
      return 0;
    }
  }

  return 1;
}

von Karl H. (kbuchegg)


Lesenswert?

Ja.
Nur: Das erkennt keinen Tastendruck. Tastendruck musst du ausserhalb 
machen. Daher die Frage nach der Verwendung.

von Ralph Fischer (Gast)


Lesenswert?

Moin,

mal eine Frage aus Interesse:

was ist eigentlich so furchtbar an einer Hardware-Entprellung?

Es gibt hier eine Vielzahl von Beiträgen zur Software-Enprellung.

Ein schnödes RC-Glied pro Taster (so viele von den Dingern verbaut man 
ja auch nicht), und das Problem ist an der Wurzel gelöst.

Software-Entprellung ist doch nur das Doktern an Symptomen, ohne die 
Ursache zu beseitigen.

Oder übersehe ich irgendwas wichtiges?

Liebe Grüße aus der Wesermarsch

Ralph

von Carsten W. (eagle38106)


Lesenswert?

Die Ursache, der prellende Kontakt, der läßt sich nicht beseitigen!
Ein Taster prellt immer beim Schließen. Ist ein mechanisches Problem. 
Der einer Kontakt wird mit Kraft gegen den anderen bewegt, schlägt auf 
und federt zurück. Alternativ müsstest Du einen Taster bauen, dessen 
Kontakt exakt zum richtigen Zeitpunkt abgebremst wird. Nur wie soll das 
gehen? :-)

Ein Entprellen per Software ist ein sehr eleganter Weg, weil er Bauteile 
spart. Und weil man mit Software auch eine Repeat-Funktion realisieren 
kann. Mit Hardware wäre das recht aufwendig.

Carsten

von Karl H. (kbuchegg)


Lesenswert?

Ralph Fischer schrieb:

> Ein schnödes RC-Glied pro Taster (so viele von den Dingern verbaut man
> ja auch nicht), und das Problem ist an der Wurzel gelöst.

wenn mans richtig macht.
Pollin zb hat Hardware Entprellung, machts aber falsch. Folge: Der µC 
stürzt regelmässig ab.

Mit der PeDa Entprellung bin ich persönlich hoch zufrieden. Neben dem 
Entprellen kriege ich quasi zum Drüberstreuen noch einige Vorteile: Das 
Ding übersieht garantiert keinen Tastendruck (solange Interrupts 
aktiviert sind), kann zwischen langen und kurzen Tastendrücken 
unterscheiden und auf Wunsch krieg ich auch noch einen Autorepeat auf 
der Taste (eine von mir besonders bei Inkrement/Dekrement Funktionen 
gerne genutzte Funktionalität). Und das alles für noch nicht einmal 1% 
der Rechenzeit. Da kann man doch nicht meckern :-)
Die Frage lautet für mich also nicht
"Warum Software, wenn es auch in Hardware geht"
sondern
"Warum Hardware, wenn es auch in Software problemlos geht"

Die Entprellungen auf Basis Warteschleife: Von denen halte ich 
persönlich nichts, weil dann die Durchlaufzeiten unnötigerweise 
verlängert werden, ohne dass ich ausser der Entprellung noch etwas dafür 
kriegen würde.

von Michael (Gast)


Lesenswert?

if(!(PINB & (1<<PINB3)))
  {
    if(debounce_switch(&PINB, PINB3))
                {
                    ....
                }
                else
                {
                    ....
                }

         }

@Karl heinz Buchegger: So nutze ich meine Funktion... Habe ich vergessen 
zu erwähnen...

Danke!

von U.R. Schmitt (Gast)


Lesenswert?

Ralph Fischer schrieb:
> was ist eigentlich so furchtbar an einer Hardware-Entprellung?
>
> Es gibt hier eine Vielzahl von Beiträgen zur Software-Enprellung.
>
> Ein schnödes RC-Glied pro Taster (so viele von den Dingern verbaut man
> ja auch nicht), und das Problem ist an der Wurzel gelöst.
>
> Software-Entprellung ist doch nur das Doktern an Symptomen, ohne die
> Ursache zu beseitigen.

Wenn schon Hardware-Entprellung, dann aber richtig und kein 
"funktioniert solange Taster neu ist" RC Glied.
Nämlich ein Umschalttaster und ein RS Flipflop.

Ansonsten haben Karl Heinz und Carsten schon alles gesagt.

von Ralph Fischer (Gast)


Lesenswert?

Moin Jungs,

nur damit keine Mißverständnisse aufkommen: ich habe nicht behauptet, 
daß HW-Entprellung das einzig Senkrechte wäre. Das war wirklich eine 
neugierige Frage.

Bisher habe ich RC-Glieder mit ca. 15 Hz Grenzfrequenz genommen (weil 
menschliche Muskeln nicht schneller als 7 Hz können). Funktioniert auch 
in einer 30 Jahre alten Z80-Mimik noch tadellos.

Das war wohl mit

> "funktioniert solange Taster neu ist"

gemeint.

> Nämlich ein Umschalttaster und ein RS Flipflop.

Tja, und ab hier gefällt mir Software dann auch besser ;-)

Zusatzfrage: gibts von der Dannegger-Entprellung irgendwo eine 
Darstellung als Flußdiagramm?
Ich beherrsche nur Bascom und Z80-Assembler (letzteres schon einige 
Monde eingerostet). Dann könnte ich mir das mal nachhäkeln...

Herzlichen Dank und Ende der Fred-Kaperung :-)

Liebe Grüße aus der Wesermarsch

Ralph

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> if(!(PINB & (1<<PINB3)))
>   {
>     if(debounce_switch(&PINB, PINB3))
>                 {
>                     ....
>                 }
>                 else
>                 {
>                     ....
>                 }
>
>          }
>
> @Karl heinz Buchegger: So nutze ich meine Funktion... Habe ich vergessen
> zu erwähnen...

Damit detektierst du keinen Tastendruck, also das wechseln einer Taste 
vom Zustand 'nicht gedrückt' in den Zustand 'gedrückt'.

Du stellst nur fest, ob die Taste gedrückt ist. Und wenn du 2000 mal in 
der Sekunde nachsiehst ob die Taste gedrückt ist, dann führst du auch 
deinen Ausführungsteil 2000 mal aus.

von Michael (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du stellst nur fest, ob die Taste gedrückt ist. Und wenn du 2000 mal in
> der Sekunde nachsiehst ob die Taste gedrückt ist, dann führst du auch
> deinen Ausführungsteil 2000 mal aus.

Nope...
Die if(!(PINB & (1<<PINB3))) ist nur wahr wenn der Taster gedrückt 
wird... Ansonsten liegt an meinem Eingang ein High-Pegel an... Mich 
interessiert auch nur der Tastendruck also der Pegelwechsel von High auf 
Low an meinem Eingang.

von Peter D. (peda)


Lesenswert?

Michael schrieb:
> Die if(!(PINB & (1<<PINB3))) ist nur wahr wenn der Taster gedrückt
> wird...

Genau.
Und dann gibt debounce() jedesmal 1 zurück.
Eine Flankenerkennung erfolgt nicht.

Du kriegst alle 500µs * 8 = 4ms ne 1 solange Du drückst und nicht nur 
beim Wechsel der Taste zu gedrückt.


Peter

von Michael (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Genau.
> Und dann gibt debounce() jedesmal 1 zurück.
> Eine Flankenerkennung erfolgt nicht.
>
> Du kriegst alle 500µs * 8 = 4ms ne 1 solange Du drückst und nicht nur
> beim Wechsel der Taste zu gedrückt.
>
>
> Peter

Genau, aber wenn ich die Taste drücke, tue ich dies bewusst... Die 
Funktion ist quasi ein EMV Schutz...Meiner Meinung nach erkenne ich den 
Flankenwechsel mit einer kontinuierlichen Abfrage ala: if(!(PINB & 
(1<<PINB3)))...
Wenn ein Puls in meinen Eingang haut, wird diese Bedingung auch wahr, 
aber die debounce_switch liefert dann hoffentlich eine 0.

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Peter Dannegger schrieb:
>> Genau.
>> Und dann gibt debounce() jedesmal 1 zurück.
>> Eine Flankenerkennung erfolgt nicht.
>>
>> Du kriegst alle 500µs * 8 = 4ms ne 1 solange Du drückst und nicht nur
>> beim Wechsel der Taste zu gedrückt.
>>
>>
>> Peter
>
> Genau, aber wenn ich die Taste drücke, tue ich dies bewusst... Die
> Funktion ist quasi ein EMV Schutz...

Junger Mann.
Ja nachdem was dein Programm dann sonst noch so tut, kannst du die Taste 
gar nicht so schnell loslassen, dass sie deni Programm nicht ein paar 
mal als gedrückt erkennt.

Es gibt Anwendungen da ist das ok:
zb Rollo fährt hoch, SOLANGE eine Taste gedrückt ist
zb Autofenster fährt rauf/runter, SOLANGE eine Taste gedrückt ist.

Willst du abre auf einen einmaligen Tastendruck hin, nur EINMAL eine 
Aktion auslösen, dann wirst du um eine Flankenerkennung nicht 
umhinkommen.
zb. LED wechselt von ein auf aus
zb. Cursor geht zum nächsten Menüpunkt
etc.

> Meiner Meinung nach erkenne ich den
> Flankenwechsel mit einer kontinuierlichen Abfrage ala: if(!(PINB &
> (1<<PINB3)))...

Und wie soll das gehen?
Um einen Wechsel zu erkennen, muss man den jetzigen Zustand mit einem 
früheren Zustand vergleichen. Und das findet sich in deinem Code nun mal 
nicht.

Wenn ich dir sage, dass in meinem Badezimmer jetzt das Licht brennt, 
kannst du dann die Frage beantworten: Ist das Licht innerhalb der 
letzten halben Stunde eingeschaltet worden?
Nein kannst du nicht.
Wenn ich dir aber die Zusatzinfo gebe, dass vor einer halben Stunde das 
Licht noch nicht gebrannt hat, dann kannst du das entscheiden.

Wenn deine Aufgabe also lautet: Wenn das Licht eingeschaltet wird (und 
nur dann. Nicht wenn das Licht einfach nur brennt), dann schalte die 
Heizung aus, dann brauchst du beides: Den Zustand des Lichtes zum 
Zeitpunkt an dem du das letzte mal nachgesehen hast und den jetzigen 
Zustand. Aus der Differenz ergibt sich, ob in der Zwischenzeit das Licht 
eingeschaltet wurde. Das Licht kann stundenlang brennen und du kannst 
hunderte male feststellen dass es brennt. Interessant für die Aufgabe 
ist nur das Erkennen des Wechsels.

Und nein. Das Ganze hat mit Entprellen erst mal an sich überhaupt nichts 
zu tun. Das Entprellen sorgt nur dafür, dass du nicht auf jede kleine 
Flanke hereinfällst, wie sie nun mal bei Tastern durch den Prellvorgang 
unvermeidlich sind.

von Michael (Gast)


Lesenswert?

Herr Buchegger,

ich habe das Problem erkannt. Sie haben Recht.
Ich sehe aber gerade keine (andere) Möglichkeit den Flankenwechsel zu 
detektieren.
Ich habe mir das immer so vorgestellt:

Mein Standardzustand:
PINB3 = 1;

Nach Tastendruck:
PINB3 = 0;
nichts anderes bedeutet die Abfrage: if(!(PINB &(1<<PINB3))), oder?

Meine Abfrage im Main Loop:
PINB3 == 0 ? debounce_switch() : 0;

Meine debounce_switch() soll lediglich einem nicht durch einen Menschen 
ausgeführten Tastendruck filtern. Über die _delay_us() Zeit kann man 
streiten.

Was habe ich sonst für Möglichkeiten den Flankenwechsel zu erkennen?

von Michael (Gast)


Lesenswert?

Danke, hatte den Rest noch gar nicht gelesen...

von Michael (Gast)


Lesenswert?

void switch_state()
{
if(!(PINB & (1<<PINB3)) && switch_no != 0)
{
    if(debounce_switch(&PINB, PINB3))
    {
        ....
        switch_no = 0;
    }
}

if(!(PINB & (1<<PINB4)) && switch_no != 1)
{
    if(debounce_switch(&PINB, PINB3))
    {
        ....
        switch_no = 1;
    }
}
}

So müsste das dann aussehen...

von Michael (Gast)


Lesenswert?

void switch_state()
{
if(!(PINB & (1<<PINB3)) && switch_no != 0)
{
    if(debounce_switch(&PINB, PINB3))
    {
        ....
        switch_no = 0;
    }
}

if(!(PINB & (1<<PINB4)) && switch_no != 1)
{
    if(debounce_switch(&PINB, PINB4))
    {
        ....
        switch_no = 1;
    }
}
}

F**k copy & paste...

Jetzt aber..

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:

> Was habe ich sonst für Möglichkeiten den Flankenwechsel zu erkennen?

INdem man, wie gesagt, den jetzigen Zustand mit dem Zustand von der 
letzen Abfrage vergleicht
1
  uint8_t   KeyPressedPrevious;
2
  uint8_t   KeyPressedNow;
3
4
  KeyPressedPrevious = ( PINB & (1<<PINB3 );  // erst mal für eine
5
                                              // vernünftige Initialisierung sorgen
6
7
  while( 1 ) {              // und los gehts: Endlosschleife
8
9
    // wie ist die Taste jetzt?
10
    KeyPressedNow =  ( PINB & (1<<PINB3 ) );
11
12
    // unterscheidet isch das von der letzten Abfrage?
13
    if( KeyPressedNow != KeyPressedPrevious ) {
14
      // jawohl, tut es!
15
      // irgendwas muss also mit der Taste passiert sein.
16
      // Entweder wurde sie gedrückt oder losgelassen.
17
      // Was denn nun
18
      if( !KeyPressedNow ) {
19
        // Aha. Taste wurde gedrückt
20
        ....
21
        ....
22
      }
23
24
      // für den nächsten Schleifendurchgang den jetzigen
25
      // Zustand der Tasten als den alten merken
26
      KeyPressedPrevious = KeyPressedNow;
27
    }
28
  }
29
}

Das Entprellen kannst du jetzt selber mit dazu einbauen.

Flankenerkennung bedeutet immer, dass man den Zustand des Pins von 2 
Zeitpunkten miteinander vergleichen muss! Dazu muss man sich den alten 
dann eben in einer Variablen merken.

von Michael (Gast)


Lesenswert?

Ok, vielen Dank!!!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.