Forum: Projekte & Code Tasten Entprellen für N00bs


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.
von Marcel R. (captaincrunch)


Lesenswert?

Folgende Entprellung verwende ich für den Zeit- und Datums-Einstellmodus 
einer Echtzeituhr. Das ganze läuft auf einem ATmega8 als Datalogger.
Im Wartungsmodus (Uhr einstellen) läuft der Log nicht weiter. Dies aber 
nur am Rande.

Meine Entprell-Methode ist wohl nur für wenige Tasten Interessant. Was 
mich aber nicht weiter stört, da ich ja nur Mode (PORT C.0) und Set 
(Port C.1) für die Uhr brauche. Weiterhin ist die Anwendung nicht 
zeitkritisch, also brauche ich nicht auf Interrupts und Timer 
zurückzugreifen.

Als erstes braucht man eine Warterotine:
1
#define F_CPU 3686400
2
3
4
//Includes
5
#include <avr\io.h>
6
#include <util\delay.h>
7
8
// Wartefunktionen
9
void wait_ms(int miliSec) {
10
  _delay_loop_2(1*(F_CPU/(1000/4))*miliSec); //Schleifen-Funktion aus delay.h
11
  }

Falls man das Include delay.h nicht verwenden möchte/kann oder eine 
andere Prozessorfamilie benutzt, kann man sich auch selber was basteln.

Nun die Entprell-Funktion:
1
int PINC_clean(){
2
  int tmp;
3
  if (!(PINC &0x00)) {             // falls C.0 und C.1 nicht betätigt
4
    wait_ms(20);            //warte 20 ms (je nach Schalter)
5
    tmp=PINC;               //Ist-Zustand zwischenspeichern
6
    while (!(PINC &0x00))   //Warte bis beide Tasten nicht betätigt
7
    return PINC;            //Ist-Zustand zurückgeben und Schleife verlassen
8
    }
9
  if (!(PINC &0x01)) {             // falls C.0 gedrückt C.1 nicht betätigt 
10
    wait_ms(20);
11
    tmp=PINC;
12
    while (!(PINC &0x00))
13
    return PINC;
14
    }
15
  if (!(PINC &0x02)) {             // falls C.1 gedrückt C.0 nicht betätigt
16
    wait_ms(20);
17
    tmp=PINC;
18
    while (!(PINC &0x00))
19
    return PINC;
20
    }    
21
  if (!(PINC &0x03)) {             // falls C.0 und C.1 betätigt
22
    wait_ms(20);
23
    tmp=PINC;
24
    while (!(PINC &0x00))
25
    return PINC;
26
    }
27
  }


Die Tasten erfüllen ihre jeweilige Funktion allerdings erst beim 
loslassen!


Die Tastenabfrage kann dann so aussehen:
1
int Clock_DigitSet (int Digit, int MaxValue, int Line, int Row){
2
  lcd_goto( Line,  Row);
3
  while (PINC_clean() & 0x01){                        //Solange Mode (C.0) nicht gedrückt
4
    if (!(PINC_clean() & 0x02)) {              //Kann man mit Set (C.1) das Digit erhöhen
5
        if (Digit<MaxValue){
6
          Digit++;
7
          } else if (Digit>=MaxValue) {
8
          Digit=0x00;
9
          }
10
        Digit+=0x30;
11
      lcd_goto ( Line,  Row);
12
      lcd_write (Digit);
13
      lcd_goto ( Line,  Row);
14
      Digit-=0x30;
15
      while (!(PINC_clean() & 0x02));   //Das nächste Digit kann man erst erhöhen,
16
                                                             //wenn man die Taste (entprellt) losgelassen hat
17
      }
18
    
19
    }
20
  while (!(PINC_clean() & 0x01));                     //Nach dem Drücken auf Mode Taste loslassen
21
                                                             //und man kommt zum nächsten Digit der Uhr
22
  return Digit;
23
  }


Das die Taste erst beum Loslassen reagiert ist zwar nicht sehr 
Benutzerfreundlich, aber da nur ich die Uhr bediene stört es niemanden 
=D

1
if (!(PINC &0x00)) {             // falls C.0 und C.1 nicht betätigt
2
  wait_ms(20);            //warte 20 ms (je nach Schalter)
3
  tmp=PINC;               //Ist-Zustand zwischenspeichern
4
  //while-Schleife entfernt//
5
         return PINC;            //Ist-Zustand zurückgeben und 
6
         }

So geht es bei mir auch mit Reaktion, beim drücken Taste. Aber ich trau 
der Sache nicht!


Es läuft Prima, bin aber für Vorschläge und Kritik immer offen!

von Peter D. (peda)


Lesenswert?

Mußte erstmal im Wiki nachsehen, was das bedeutet:

Noob steht für

    * einen nicht lernwilligen bzw. ignoranten Neuling


Da kann ich nur sagen, das stimmt.
Denn das Thema hatten wir schon ad nauseam.


Peter

von Lupin (Gast)


Lesenswert?

noob steht sinngemäß für neuling und ich glaube für solche ist das hier 
gedacht.

von Jan (Gast)


Lesenswert?

Den Sinn von
1
    while (!(PINC &0x00))
2
    return PINC;
muss ich aber nicht verstehen, oder?

Noch mehr erstaunt mich, dass die Funktion PINC_clean() funktionieren 
soll, bzw. irgendeinen anderen Wert zurückgibt als 0 - von zufälligen 
timing-Fällen mal abgesehen...

von Peter D. (peda)


Lesenswert?

@Jan,

Du hast recht, die Schleife dürfte komplett wegoptimiert werden.

Auch diese Write-Only Variable "tmp" erschließt sich mir nicht.


Der Code ist auch sehr gutes Futter für die "C ist ineffizient" 
Fraktion.

Wenn man immer alles auf 2 Byte (int) aufbläht, wo ein Byte (unsigned 
char) dicke reicht, muß C natürlich auch mindestens doppelt soviel Code 
erzeugen.


Das ist also von vorn bis hinten ein waschechter Noob-Code.


Peter

von Marcel R. (captaincrunch)


Lesenswert?

Erstmal Danke für die Rückmeldung!

Ich muss gestehen, ich hätte den Thread "Entprellung vom N00b für N00bs 
nennen sollen" =D
Den Code aus den anderen Threads konnte ich schlichtweg nicht vollkommen 
verstehen und dann verwende ich es auch nicht. Will lieber das Rad neu 
erfinden und Stück für Stück lernen es besser zu machen, bzw. den Code 
aus dem Forum nachzuvollziehen.

Aber davon mal abgesehen, der Code funtioniert!

Ich hatte vorher das Problem, dass im EinstellModus der Uhr der Cursor 1 
bis 5 Zeichen weiter gesprungen ist. Die Tasten reagieren nun wie 
vorgesehen und sprechen auch sofort an.

-----
@ Peter:

Den Vorschlag (unsigned char) statt (int) zu nehmen greife ich sofort 
auf und werde es auf sämtliche meiner Funktionen anwenden! Den Fehler 
hab ich ständig begangen (N00b halt g)

Die Variable tmp ist im ganz oberen Beispiel nötig, da die Tasten erst 
nach dem Loslassen ihren Dienst verrichten. Solange hängt das Programm 
in der Schleife und Beim Verlassen der Funktion ist die Tasterstellung 
wieder 0x00. Was in meinem Fall aber nicht schlimm ist, da im 
Wartungsmodus keine Daten geloggt werden.

Im unteren Beispiel ist tmp wirklich unnötig! Werde das gleich mal 
ändern!


Danke für die Hinweise!

-----
@ Jan:

OMG (Oh mein Gott) du hast natürlich recht!
return PINC; Was ein Unsinn. return tmp; sollte das natürlich oben sein!
Nur unten return PINC! Ist irgendwie beim copy/paste hochgerutscht!

Thx! So war das natürlich nicht am laufen =D

-----
1
unsigned char PINC_clean(){
2
  if (!(PINC &0x00)) {
3
    wait_ms(20);
4
    return PINC;
5
    }
6
  if (!(PINC &0x01)) {
7
    wait_ms(20);
8
    return PINC;
9
    }
10
  if (!(PINC &0x02)) {
11
    wait_ms(20);
12
    return PINC;
13
    }    
14
  if (!(PINC &0x03)) {
15
    wait_ms(20);
16
    return PINC;
17
    }
18
  }

So sieht das ganze jetzt aus! Es funktioniert =D
Tasten reagieren beim Drücken! Keine Digit-Übersprünge im Einstellmodus 
der Uhr.


Bin für noch mehr Vorschläge dankbar!
Vor allem warum es nicht funtionieren sollte und warum es schlecht ist!
Mein Ernst: Was hab ich nicht bedacht? Weil funktioniert ja in meinem 
Fall.

von Marcel R. (captaincrunch)


Lesenswert?

Wow!!

Danke nochmal Peter!!

Ich hab jetzt konsequent alle (char) und (int) in (unsigned char) 
geändert!

Beim compilen hab ich 700kB weniger Programm und es funktioniert 
weiterhin wie gewünscht =) d.H. eine Verbesserung von ~4500kB auf 
~3800kB!

Fantastisch! freu


Werde in Zukunft versuchen immer auf die richtige Wahl der Deklarationen 
zu achten!
Und mich auch nochmal schlau machen, bevor ich euch wieder sowas 
auftische ;)


Thx!!

von Peter D. (peda)


Lesenswert?

Marcel Raab wrote:

> So sieht das ganze jetzt aus! Es funktioniert =D

Bist Du sicher ?

Du hast die Funktion nämlich nicht verstanden.

Sonst hättest Du ja das hier geschrieben:
1
unsigned char PINC_clean(){
2
    wait_ms(20);
3
    return PINC;
4
  }

Das ist alles, was der Compiler noch davon übrig läßt.
Der Rest wird komplett wegoptmiert.
Sieht man im Assembler-Listing sehr schön.


Peter

von Hauke R. (lafkaschar) Benutzerseite


Lesenswert?

500kB Weniger Speicher? Hast ja nen netten µC, dass das schon vorher da 
rein gepasst hat.

von Marcel R. (captaincrunch)


Lesenswert?

ATmega8, der hat 16kB Flash

Lol!! Meinte natürlich von 4500Byte auf 3800Byte!!!

Oh je vielleicht sollte ich erstmal nen Kaffee Trinken =D

von Hmm... (Gast)


Lesenswert?

Wow,3.8 Megabyte für eine Uhrenanwendung.Das nenne ich Rekord g
1
unsigned char PINC_clean()
2
{
3
  if(!(PINC & (1<<0x00))) 
4
  {
5
    wait_ms(20);
6
    return PINC;
7
  }
8
  if(!(PINC & (1<<0x01))) 
9
  {
10
    wait_ms(20);
11
    return PINC;
12
  }
13
  if(!(PINC & (1<<0x02))) 
14
  {
15
    wait_ms(20);
16
    return PINC;
17
  }    
18
  if(!(PINC & (1<<0x03))) 
19
  {
20
    wait_ms(20);
21
    return PINC;
22
  }
23
}

von Peter D. (peda)


Lesenswert?

@Hmm... (Gast)

Das gibt dann schonmal ne dicke Verwarnung:

warning: control reaches end of non-void function


Peter

von Marcel R. (captaincrunch)


Lesenswert?

Oh je Peter Du hast recht!

Sah aber für mein ungeschultes Auge ganz hübsch aus so...

Also
1
unsigned char PINC_clean(){
2
    wait_ms(20);
3
    return PINC;
4
  }
scheint wirklich zu reichen als Entprellung in meiner Anwendung..

Ich frag jetzt mal vorsichtig: Ist es überhaupt eine Art Entprellung was 
ich da mache? Beginne stark an mir zu Zweifeln.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Naja, es hat einen gewissen Effekt, aber Entprellung kann man es nicht 
wirklich nennen.

Das Nonplusultra was Entprellung angeht ist Peter Danneggers Routine 
(siehe Artikel Entprellung).

von nooby (Gast)


Lesenswert?

ja und das Non-plus-ultra wäre auch gewesen, das Peter seine sources 
weniger kryptisch und besser dokumentiert hätte, genau wie Marcel es 
beschrieb.

Als Bleistift:
"
 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: key press 
detect
"

mag gut sein, dass sein Code funktioniert und dazu kurz ist, aber ein 
Anfänger hat sicher seine Probleme damit den auch zu verstehen und nicht 
nur simpel in sein Projekt rein zu kleben.

mfg

von Peter D. (peda)


Lesenswert?

nooby wrote:

> mag gut sein, dass sein Code funktioniert und dazu kurz ist, aber ein
> Anfänger hat sicher seine Probleme damit den auch zu verstehen

Ein Anfänger sollte aber keine Probleme haben, Fragen zu stellen, wenn 
er etwas nicht versteht. Nur so kann er etwas lernen.

Hellsehen, was dem Anfänger Probleme bereitet, kann ich nicht.


Peter

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.