Tastenentprellung läuft nicht

OP #5401132
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
}
Gast #5401151
Lesenswert?

Ich würde den Test so formulieren :
1
    while (1) /* nur um Tastenrueckgabe zu testen */
2
    {
3
        if  ((ENTPRELL(PINB, PB2)) != 0)
4
        {
5
            LED_HL_ON;    /* bei 1 */
6
        }
7
        else
8
        {
9
            LED_HL_OFF;    /* bei 0 */
10
        }
11
    }

Probier mal, was dann passiert.

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

Danach kann man mal in den Tiefen des Makros kramen...
Gast #5401199
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:
1
// Hilfsfunktion
2
uint8_t debounce_C1( void )
3
{
4
  return debounce(PINC, PC1);
5
}
6

7
// Beispielanwendung
8
int main(void)
9
{
10
  DDRB  |=   1<<PB2;
11
  DDRB  |=   1<<PB3;
12
  DDRC  &= ~(1<<PC1);
13
  PORTC |=   1<<PC1; // Pullup für Taster
14

15
  for(;;){
16
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)
17
      PORTB ^= 1<<PB2;
18
    if( debounce_C1() )  // nicht: debounce(PINC, PC1)
19
      PORTB ^= 1<<PB3;
20
  }
21
}
OP #5401812
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...
Gast #5401820
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
#5401827
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:
1
if(debounce(PINB,PB2)) LED_HL ^= 1
2

3
if(LED_HL==0){
4
LED_HL_ON;
5
}else
6
LED_HL_OFF;

So in der Art!
#5401835
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?
OP #5402024
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?
#5402123
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?
OP #5402225
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!
OP #5402313
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.
Gast #5402610
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.
#5402721
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.
OP #5403041
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.
#5403137
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.
#5403194
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren