mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Tastenentprellung läuft nicht


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: __Son´s B. (bersison)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Hallo.
Hilfe - bin verzweifelt, da ich ordentliche Entprellung nicht hin 
bekommen...
ENTPRELL() gibt dauerhaft "0" zurück - aber warum?

#define ENTPRELL( port, pin ) /* von Peter Dannegger */ \
({                           /* aktiv-high-Eingang */ \
static uint8_t flag = 0;  \
uint8_t i = 0;             \
if( flag ){                \
for(;;){                 \
if( (port & 1<<pin) ){  \
i = 0;                \
break;                 \
}                      \
_delay_us( 98 );       \
if( --i == 0 ){      \
flag = 0;            \
i = 0;               \
break;                \
}                       \
}                       \
}else{                   \
for(;;){                \
if( !(port & 1<<pin) ){ \
i = 0;               \
break;              \
}                  \
_delay_us( 98 );   \
if( --i == 0 ){   \
flag = 1;        \
i = 1;          \
break;  \
}    \
}    \
}   \
i; \
})

int main(void)
{
DDRB &= ~(1<<PB2);    // Eingang, Taste
DDRA |= ((1<<PA1)|(1<<PA2));  // Ausgang, LED_F, LED_HL
// LED_HL_ON, LED_HL_OFF sind Macros, die gut funktionieren

while(1) // nur um Tastenrückgabe zu testen
{
while ((ENTPRELL(PINB,PB2))==1)  LED_HL_ON;  // auf 1 abfragen
while ((ENTPRELL(PINB,PB2))==0)  LED_HL_OFF; // aus 0 abfragen
}

Autor: Harald (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Nicht abkupfern was nicht funktioniert oder was du nicht verstehst. 
Nachdenken und selbst schreiben und vor allem: nicht jammern.

Autor: fop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde den Test so formulieren :
    while (1) /* nur um Tastenrueckgabe zu testen */
    {
        if  ((ENTPRELL(PINB, PB2)) != 0)
        {
            LED_HL_ON;    /* bei 1 */
        }
        else
        {
            LED_HL_OFF;    /* bei 0 */
        }
    }

Probier mal, was dann passiert.

Wenn's immer noch nicht geht, probier nochmal ohne Entprellung :
    while (1) /* nur um Tastenrueckgabe zu testen */
    {
        if  ((PINB & (1<<PB2)) != 0)
        {
            LED_HL_ON;    /* bei 1 */
        }
        else
        {
            LED_HL_OFF;    /* bei 0 */
        }
    }
Nicht dass Dir Deine Hardware ein Ei ins Nest legt.

Danach kann man mal in den Tiefen des Makros kramen...

Autor: Dieter F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> DDRB &= ~(1<<PB2);    // Eingang, Taste

Pullup vergessen (lies mal im Artikel nach)

Und was sagt Dir

"Wenn das Makro für die gleiche Taste (Pin) an mehreren Stellen 
aufgerufen werden soll, muss eine Funktion angelegt werden, damit beide 
Aufrufe an die gleiche Zustandsvariable flag auswerten [1]: "

mit diesem Beispiel:
// Hilfsfunktion
uint8_t debounce_C1( void )
{
  return debounce(PINC, PC1);
}

// Beispielanwendung
int main(void)
{
  DDRB  |=   1<<PB2;
  DDRB  |=   1<<PB3;
  DDRC  &= ~(1<<PC1);
  PORTC |=   1<<PC1; // Pullup für Taster

  for(;;){
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)
      PORTB ^= 1<<PB2;
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)
      PORTB ^= 1<<PB3;
  }
}

Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
fop schrieb:
> Ich würde den Test so formulieren :

Danke für deine konstruktive Rü.!
Deine Vorschläge decken sich mit meinen Versuchen. Hardware iO, mit dem 
Macro ENTPRELL() stimmt etwas nicht.

Dieter F. schrieb:
> Pullup vergessen (lies mal im Artikel nach)

"aktiv-high" wie beschrieben, daher ext.10k-Ableitwid.

Dieter F. schrieb:
> Und was sagt Dir

Das Problem steckt im Macro, nicht im Aufruf. Dein Versuch funktioniert 
genau so wenig!

Harald schrieb:
> Nicht abkupfern was nicht funktioniert oder was du nicht verstehst.
> Nachdenken und selbst schreiben und vor allem: nicht jammern.

...zu blöde, daher...ohne herablassenden Kommentar...

Autor: Erwin D. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@TO: kein Gemecker, sondern gutgemeinter Hinweis:
Wenn du jede Zeile, also den gesamten Quelltext an den linken Seitenrand 
schiebst, ist der Text schlecht lesbar.
Deshalb bitte in Zukunft formatieren und in code-Tags einschließen.
Ok?

Gruß Erwin

Autor: Dominik K. (kilo81)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> ENTPRELL() gibt dauerhaft "0" zurück - aber warum?

Natürlich, weil debounce beim Tastendruck nicht "rastet"


__Son´s B. schrieb:

> while ((ENTPRELL(PINB,PB2))==1)  LED_HL_ON;  // auf 1 abfragen
> while ((ENTPRELL(PINB,PB2))==0)  LED_HL_OFF; // aus 0 abfragen
> }

debounce entprellt!
Das bedeutet, dass es keinen festen Zustand einnimmt und auch so bleibt!
Durch das debounce wird der Zustand auf 1 gesetzt und dann wieder auf 0.

probiere folgendes:
if(debounce(PINB,PB2)) LED_HL ^= 1

if(LED_HL==0){
LED_HL_ON;
}else
LED_HL_OFF;

So in der Art!

: Bearbeitet durch User
Autor: Peter D. (peda)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> mit dem
> Macro ENTPRELL() stimmt etwas nicht.

Wenn Du daran nichts geändert hast, dann stimmt es auch. Der Code wurde 
auf dem STK500 getestet.

Du kannst Dir aber das Leben erheblich erleichtern, wenn Du mal den Link 
auf das Original posten würdest. Und da ist bestimmt auch beschrieben, 
was das Macro macht und auch ein Beispielcode dabei. Der sah garantiert 
nicht so aus, wie Dein obiger Code.

Zu erwarten, daß jeder erstmal nach dem Original suchen soll, ist grob 
unhöflich. Ich hab jedenfalls nicht die Zeit dazu.
Oder weißt Du noch alles genau, was Du die letzten 20 Jahre irgendwo mal 
gepostet hast?

: Bearbeitet durch User
Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Zu erwarten, daß jeder erstmal nach dem Original suchen soll, ist grob
> unhöflich.

Originalcode;
https://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Tasty_Reloaded

Autor: Dominik K. (kilo81)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frage:

1. Hattest du meinen Codeschnippsel mal getestet?

2. Willst du beim gedrückthalten der Taste LED_HL_ON auslösen
und beim loslassen der Taste LED_HL_OFF auslösen?

Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dominik K. schrieb:
> debounce entprellt!
> Das bedeutet, dass es keinen festen Zustand einnimmt und auch so bleibt!
> Durch das debounce wird der Zustand auf 1 gesetzt und dann wieder auf 0.

DANKE - genau das war mein Denkfehler!
Mit einer Toggle-Anweisung klappts prima.

Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dominik K. schrieb:
> 2. Willst du beim gedrückthalten der Taste LED_HL_ON auslösen
> und beim loslassen der Taste LED_HL_OFF auslösen?

Genau das ist der nächste Schritt.
Und danach den Flankenverlauf. Rückgabe von i dann;
0...Eingang X/Taste low
1...Eingang X/Taste high
2...Eingang X, Flanke ansteigend
3...Eingang X, Flanke abfallend

Autor: Dominik K. (kilo81)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> DANKE - genau das war mein Denkfehler!
> Mit einer Toggle-Anweisung klappts prima.

Dachte ich mir! ;)
Das macro funktioniert nämlich ganz gut.

Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dominik K. schrieb:

> Dachte ich mir! ;)
> Das macro funktioniert nämlich ganz gut.

Durch die Änderung von i=0 auf i=2
(Quelle: 
https://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Tasty_Reloaded 
, untere Bemerkung)
habe ich alle Rückgabewerte zur Weiterverarbeitung.

Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> Und danach den Flankenverlauf. Rückgabe von i dann;
> 0...Eingang X/Taste low
> 1...Eingang X/Taste high
> 2...Eingang X, Flanke ansteigend
> 3...Eingang X, Flanke abfallend

Einfacher gesagt als getan.
Aus dem Macro kann nur ein Wert zurück gegeben werden "i".
Derzeit ist
i=1=ansteigende Flanke,
i=2=abfallende Flanke.

(1)
Nun könnte ich die beiden Rückgabewerte austauschen
i=3=Taste high,
i=4=Taste low.
(2)
Auch könnte ich eine Zeitstufe
i=1, 5ms später i=3,
i=2, 5ms später i=4
einsetzen. Blöde Sache mit der 5ms-Zeitverschwendung.
(3)
Oder die Zustandänderung in eine Funktion auslagern.

Habt jemand eine bessere Idee?

Autor: Dominik K. (kilo81)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nunja, es ist nunmal ein macro für Taster und nicht für Schalter!
Entweder tauscht du deinen Taster gegen einen Schalter aus oder du setzt 
ein Flag.
Also eine Variable togglen so wie oben beschrieben. Dann kannst du einen 
Taster verwenden.

Was genau hast du denn vor???
Ich dachte du willst einfach nur pro Tastendruck zwischen LED_HL_ON und 
LED_HL_OFF umschalten?

Autor: __Son´s B. (bersison)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dominik K. schrieb:

> Was genau hast du denn vor???
> Ich dachte du willst einfach nur pro Tastendruck zwischen LED_HL_ON und
> LED_HL_OFF umschalten?

Ich möchte dieses Entpreller-Macro, als Basisbaustein (All-In-One) so 
umbauen, dass es zukünftig für alle Gelegenheiten zur Eingangskontrolle 
her halten kann.
Egal ob irgend wann nur eine Flanke, oder der Tasten-/Schalterzustand 
benötigt wird. Ob nur eine Taste, oder mehrere Taster/Schalter innerhalb 
eines Programms verwendet werden.

So komme ich im Laufe der Zeit zu guten+stabilen Universal-Modulen, die 
ich nur noch Einfügen muss. Kleinen Mini-Anpassungen -> FERTIG!

Autor: __Son´s B. (bersison)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Folgendes klappt schon mal fehlerfrei;

int main(void)
{
... // div.Deklarationen

if ((ENTPRELL (PINB, PB2)) == 1) Sprung = 1; // Taste_gn, Flanke 
ansteigend
if ((ENTPRELL (PINB, PB2)) == 2) Sprung = 2; // Taste_gn, Flanke 
abfallend
if ((ENTPRELL (PINB, PB1)) == 1) Sprung = 3; // Taste_rt, Flanke 
ansteigend
if ((ENTPRELL (PINB, PB1)) == 2) Sprung = 4; // Taste_rt, Flanke 
abfallend

switch(Sprung)
{
 case 1:
  LED_GN_ON; //Led_gn on == Flanke ansteigend
  break;
 case 2:
  LED_GN_OFF; //Led_gn off == Flanke abfallend
  break;
 case 3:
  LED_RT_ON; //Led_rt on == Flanke ansteigend
  break;
 case 4:
  LED_RT_OFF; //Led_rt off == Flanke abfallend
  break;
}}

Auch mit mehreren Tasten, nur nicht bei zeitgleicher Zustandveränderung.

Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> Hilfe - bin verzweifelt, da ich ordentliche Entprellung nicht hin
> bekommen...

...dann fang an, mal _selber zu denken, anstatt blind irgendwelchen 
Fremdcode in deine Projekte zu kopieren.

Ich hab die Prinzipien hier in diesem Forum schon so oft den diversen 
Leuten erläutert, irgendwann mutiert die eigene Zunge zum 
Fransenteppich...

Zur Not guck in die Quellen der Lernbetty, da kannst du sehen, wie man 
ein paar Dutzend Tasten zuverlässig entprellt und dran etwas lernen. 
Dazu war die nämlich da.

W.S.

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> if ((ENTPRELL (PINB, PB2)) == 1) Sprung = 1; // Taste_gn, Flanke
> ansteigend
> if ((ENTPRELL (PINB, PB2)) == 2) Sprung = 2; // Taste_gn, Flanke
> abfallend

Du hast das Makro immer noch nicht verstanden, es darf je Taste nur an 
einer Stelle aufgerufen werden!

Bei 2 Aufrufen wird völlig unnütz doppelter Code erzeugt, d.h. Du 
entprellst die selbe Taste zweimal nacheinander.
Es kann daher passieren, daß der 1. Aufruf 1 und der 2. Aufruf 2 ergibt, 
und somit Dein Code den 1. Aufruf überschreibt.
Willst Du den Returnwert auf verschiedene Werte testen, schreib ihn eine 
Variable oder werte ihn mit switch/case aus.

Für eine Lib, die auch für größere Projekte verwendbar sein soll, ist 
allerdings die Interruptlösung eindeutig vorzuziehen. Sie verwartet 
keine Laufzeit und verliert auch keine Tastendrücke, wenn die Mainloop 
etwas mehr zu tun hat.

Die Makrolösung sollte man nur für kleine Projekte benutzen, die z.B. 
auf einem ATtiny13 laufen.

Autor: __Son´s B. (bersison)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Peter D. schrieb:
> Bei 2 Aufrufen wird völlig unnütz doppelter Code erzeugt, d.h. Du
> entprellst die selbe Taste zweimal nacheinander.
> Es kann daher passieren, daß der 1. Aufruf 1 und der 2. Aufruf 2 ergibt,
> und somit Dein Code den 1. Aufruf überschreibt.

Danke für Info!
Vorerst hatte ich den Entprellaufruf über eine Funktion pro Taste 
aufgerufen, hatte diesen dann aber weg rationalisiert, da der direkte 
Aufruf gut klappt(e).
Ev. doch nur Zufall...

Peter D. schrieb:
> Für eine Lib, die auch für größere Projekte verwendbar sein soll, ist
> allerdings die Interruptlösung eindeutig vorzuziehen. Sie verwartet
> keine Laufzeit und verliert auch keine Tastendrücke, wenn die Mainloop
> etwas mehr zu tun hat.

"Interrupt" - als Anfänger eher "abschreckend" - warum auch immer...
Werde mich dieses Jahr damit auseinander setzen, da es ein mächtiges 
Werkzeug dar stellt - gerade bei reaktionskritischen Änderungen.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:

> Peter D. schrieb:
>> Für eine Lib, die auch für größere Projekte verwendbar sein soll, ist
>> allerdings die Interruptlösung eindeutig vorzuziehen. Sie verwartet
>> keine Laufzeit und verliert auch keine Tastendrücke, wenn die Mainloop
>> etwas mehr zu tun hat.
>
> "Interrupt" - als Anfänger eher "abschreckend" - warum auch immer...
> Werde mich dieses Jahr damit auseinander setzen, da es ein mächtiges
> Werkzeug dar stellt - gerade bei reaktionskritischen Änderungen.

Du brauchst nicht unbedingt einen Interrupt, sondern Du musst die 
Entprellroutine nur mit einer konstanten Rate aufrufen. Im simpelsten 
Fall würde man einfach die entsprechenden Timerflags dazu verwenden.

Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__Son´s B. schrieb:
> "Interrupt" - als Anfänger eher "abschreckend"

ich bin ja auch kaum über Anfänger hinausgekommen.

Interrupt ist einfach,
ich mache einen 10ms Timerinterrupt um da Tasten zu entprellen 
(Dannegger), oder

IRMP von Frank(ukw) 64µs z.B. da zähle ich eine Hilfsvariable bis ich 
wieder bei 10ms bin um die Tasten nach Dannegger auszuwerten.

oder per Drehencoder Auswertung Interupt alle 1ms, Drehencoder (auch 
Dannegger) bis 10 zählen Tasten auswerten.

Die Tasten wenn alle auf einem Port liegen können es 8 Tasten 
gleichzeitig sein, wenn nicht schiebt man Tasten Bits von Port A Port B 
Port C eben in ein Hilfs Byte welches dann ausgewertet wird und wertet 
wieder 8 Tasten aus 3 Ports aus.

: Bearbeitet durch User

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.