www.mikrocontroller.net

Forum: Projekte & Code Tasten Entprellen für N00bs


Autor: Marcel Raab (captaincrunch)
Datum:

Bewertung
0 lesenswert
nicht 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:
#define F_CPU 3686400


//Includes
#include <avr\io.h>
#include <util\delay.h>

// Wartefunktionen
void wait_ms(int miliSec) {
  _delay_loop_2(1*(F_CPU/(1000/4))*miliSec); //Schleifen-Funktion aus delay.h
  }


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:
int PINC_clean(){
  int tmp;
  if (!(PINC &0x00)) {             // falls C.0 und C.1 nicht betätigt
    wait_ms(20);            //warte 20 ms (je nach Schalter)
    tmp=PINC;               //Ist-Zustand zwischenspeichern
    while (!(PINC &0x00))   //Warte bis beide Tasten nicht betätigt
    return PINC;            //Ist-Zustand zurückgeben und Schleife verlassen
    }
  if (!(PINC &0x01)) {             // falls C.0 gedrückt C.1 nicht betätigt 
    wait_ms(20);
    tmp=PINC;
    while (!(PINC &0x00))
    return PINC;
    }
  if (!(PINC &0x02)) {             // falls C.1 gedrückt C.0 nicht betätigt
    wait_ms(20);
    tmp=PINC;
    while (!(PINC &0x00))
    return PINC;
    }    
  if (!(PINC &0x03)) {             // falls C.0 und C.1 betätigt
    wait_ms(20);
    tmp=PINC;
    while (!(PINC &0x00))
    return PINC;
    }
  }



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


Die Tastenabfrage kann dann so aussehen:
int Clock_DigitSet (int Digit, int MaxValue, int Line, int Row){
  lcd_goto( Line,  Row);
  while (PINC_clean() & 0x01){                        //Solange Mode (C.0) nicht gedrückt
    if (!(PINC_clean() & 0x02)) {              //Kann man mit Set (C.1) das Digit erhöhen
        if (Digit<MaxValue){
          Digit++;
          } else if (Digit>=MaxValue) {
          Digit=0x00;
          }
        Digit+=0x30;
      lcd_goto ( Line,  Row);
      lcd_write (Digit);
      lcd_goto ( Line,  Row);
      Digit-=0x30;
      while (!(PINC_clean() & 0x02));   //Das nächste Digit kann man erst erhöhen,
                                                             //wenn man die Taste (entprellt) losgelassen hat
      }
    
    }
  while (!(PINC_clean() & 0x01));                     //Nach dem Drücken auf Mode Taste loslassen
                                                             //und man kommt zum nächsten Digit der Uhr
  return Digit;
  }



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

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

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!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lupin (Gast)
Datum:

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

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Sinn von
    while (!(PINC &0x00))
    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...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marcel Raab (captaincrunch)
Datum:

Bewertung
0 lesenswert
nicht 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

-----

unsigned char PINC_clean(){
  if (!(PINC &0x00)) {
    wait_ms(20);
    return PINC;
    }
  if (!(PINC &0x01)) {
    wait_ms(20);
    return PINC;
    }
  if (!(PINC &0x02)) {
    wait_ms(20);
    return PINC;
    }    
  if (!(PINC &0x03)) {
    wait_ms(20);
    return PINC;
    }
  }

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.

Autor: Marcel Raab (captaincrunch)
Datum:

Bewertung
0 lesenswert
nicht 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!!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:
unsigned char PINC_clean(){
    wait_ms(20);
    return PINC;
  }

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

Autor: Hauke Radtki (lafkaschar) Benutzerseite
Datum:

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

Autor: Marcel Raab (captaincrunch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ATmega8, der hat 16kB Flash

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

Oh je vielleicht sollte ich erstmal nen Kaffee Trinken =D

Autor: Hmm... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow,3.8 Megabyte für eine Uhrenanwendung.Das nenne ich Rekord g
unsigned char PINC_clean()
{
  if(!(PINC & (1<<0x00))) 
  {
    wait_ms(20);
    return PINC;
  }
  if(!(PINC & (1<<0x01))) 
  {
    wait_ms(20);
    return PINC;
  }
  if(!(PINC & (1<<0x02))) 
  {
    wait_ms(20);
    return PINC;
  }    
  if(!(PINC & (1<<0x03))) 
  {
    wait_ms(20);
    return PINC;
  }
}

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Hmm... (Gast)

Das gibt dann schonmal ne dicke Verwarnung:

warning: control reaches end of non-void function


Peter

Autor: Marcel Raab (captaincrunch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh je Peter Du hast recht!

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

Also
unsigned char PINC_clean(){
    wait_ms(20);
    return PINC;
  }
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.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: nooby (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

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.