Forum: Mikrocontroller und Digitale Elektronik Tasterentprellung nach AVR-Tutorial


von Johannes (menschenskind)


Lesenswert?

Hallo

Lt. Tutorial ist es ja günstig, dieses RS-FlipFlop zu verwenden.
Kann man diese Schaltung auch benutzen, wenn man nur nen simplen Taster 
hat? bzw. diese ein wenig abwandeln, damit es klappt?

Danke

von Karl H. (kbuchegg)


Lesenswert?

Johannes Hofmann schrieb:
> Hallo
>
> Lt. Tutorial ist es ja günstig, dieses RS-FlipFlop zu verwenden.

Eigentlich macht man Tastenentprellung am besten in Software.
Das ist universeller, kostet nichts und funktioniert absolut 
zuverlässig.

von Johannes (menschenskind)


Lesenswert?

Ok, wenn ich mir die Komfortroutine für C anschaue und 2 Taster habe, 
die nicht gedrückt und dann gehalten werden, welche Teile des Codes 
benötige ich denn dann?

Das Problem ist nämlich, dass ich nen MP3-Player habe, dessen 
Spielroutine ich nur für 800us unterbrechen kann, weil der Datenstrom 
dann nämlich abreißt.

Deswegen wollte ich das eigentlich mit Hardware-Entprellung machen.
Wie würdest du das machen?

von Christian H. (sanjuro2k)


Lesenswert?

Hi,

die Entprellroutine vom Dannegger besteht doch nur aus ein paar binären 
Operationen.
Und wenn du nen Quarz mit z.b. 16 MHz hast, dann sind 800 µs doch ne 
Ewigkeit und reichen locker aus, um ein paar Tasten zu entprellen.

Ich hab auch schon nen MP3 Player mit nem VS1053 IC gebaut, an dem ich 
12 Taster hatte. Die konnte ich während des MP3-Abspielens ohne Probleme 
entprellen.

Gruß
C.H.

von Karl H. (kbuchegg)


Lesenswert?

Du brauchst
die Timer Overflow Routine
und natürlich die Auswertefunktionen

> Das Problem ist nämlich, dass ich nen MP3-Player habe, dessen
> Spielroutine ich nur für 800us unterbrechen kann

800us sind fast 1ms. Also massig Zeit. Solange braucht die Overflow 
Funktion ja gar nicht. Und ausserdem wird die ja nur alle heilige Zeiten 
aufgerufen (Du kannst auch die Zeitberechnung für das Nachladen des 
Timers aus der ISR rausnehmen. Wenn die ISR so alle 5 bis 20ms 
aufgerufen wird, dann reicht das. Das muss nicht sonderlich genau sein, 
mit dem Prescaler kommt man normalerweise ausreichend gut in einen 
vernünftigen Bereich hinein)

von Udo. R. S. (Gast)


Lesenswert?

Sorry aber etwas kapierre ich hier nicht.
Wenn ich das richtig im Kopf habe dann ist die Prellzeit von 
tastern/Schaltern durchaus im Millisekundenbereich, gerne auch mal bei 
nicht so hochwertigen mehr als 20 mS.
Wie bitte kann ich die innerhalb von weniger als 0,8yS dann 
softwareseitig entprellen????
Dazu müsste ich doch die Tastenausleseroutine in eine zyklisch (Timer) 
über Timer aufgerufene Routine machen, die sich die Zustände auch noch 
merkt.

von Esko (Gast)


Lesenswert?

Wie schon von Udo geschrieben, ist Entprellen hier der falsche Weg.
Solange hast du nicht Zeit.
Am einfachsten ist es mit der ersten Flanke einen Interrupt auszulösen 
und dann alle folgenden für ~20ms zu verwerfen.

von Peter D. (peda)


Lesenswert?

Udo. R. S. schrieb:
> Dazu müsste ich doch die Tastenausleseroutine in eine zyklisch (Timer)
> über Timer aufgerufene Routine machen, die sich die Zustände auch noch
> merkt.

Und genau das macht eben diese Entprellroutine.
Sie tastet 4-mal ab im Abstand von 10ms Timerinterrupt.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Esko schrieb:
> Wie schon von Udo geschrieben, ist Entprellen hier der falsche Weg.

Udo hat dasnur deswegen geschrieben, weil er noch nicht durchschaut hat, 
wie das funktioniert.

> Solange hast du nicht Zeit.

Braucht er auch nicht.

> Am einfachsten ist es mit der ersten Flanke einen Interrupt auszulösen
> und dann alle folgenden für ~20ms zu verwerfen.

Äh nein.
Das ist nicht einfacher. Wie machst du das denn 'die folgenden für 20ms 
verwerfen'?

Am enfachsten ist es die Entprellroutine zu benutzen.
Die verbraucht minimal Rechenzeit, entprellt zuverlässig, merkt sich 
einen gedrückte Taste, erkennt kurze und lange Tastendrücke und kann auf 
wunsch auch einen Autorepeat auf die Taste legen. Und das beste am 
ganzen: sie verbraucht praktisch keine Rechenzeit.

von Karl H. (kbuchegg)


Lesenswert?

Udo. R. S. schrieb:

> Wie bitte kann ich die innerhalb von weniger als 0,8yS dann
> softwareseitig entprellen????

Musst du auch nicht.
Die Entprellroutine erkennt einen Tastendruck dann als gültig an, wenn 4 
mal hintereinander, im Abstand von x Millisekunden die Taste als 
gedrückt erkannt wurde. Sobald die Taste das erste mal prellt, beginnt 
die 4-er Zähleung erneut zu laufen.

Der Code macht im Grunde nichts anderes als:
Schau alle x Millisekunden die Tasten durch, ob sich etwas verändert 
hat. Das geht schnell. Im Grunde ist das wie beim Autofahren: Du 
konzentrierst dich auf die Strasse und alle paar Sekunden wirfst du 
einen Blick in den Rückspiegel. Das geht schnell genug, damit dir nichts 
entgeht.

Genauso hier:
Alle x Millisekunden sieht die Overflow-ISR nach, ob eine Taste gedrückt 
wurde. Durch die Konstruktion der ISR gilt aber nicht jeder 1->0 
Übergang als Tasterndruck, sondern nur dann, wenn danach bei 4-maligem 
erneuten Hinschauen die 0 immer noch anliegt.

von Johannes (menschenskind)


Lesenswert?

Hallo

Wie mach ich das aber, wenn ich bei meinem Player Pause machen will und 
dies mittels dieser Schleife tun will:
while(PAUSE){}  ?
Da komm ich ja dann nicht mehr raus.

Denn ich wollte über den Interrupt diesen PAUSE-Wert togglen.
Aber das klappt ja dann nicht mehr in Software.

Deswegen würd ich nochmal gern wissen, ob ich mit nem RS-Flip-Flop und 
nem Taster arbeiten kann, oder ob das Ding nur bei einem Wechselschalter 
benutzbar ist.

von Johannes (menschenskind)


Lesenswert?

Weiterhin noch ne Frage:
In dem Tutorial wird das Timerinterrupt-Intervall so gesetzt.
Zu ersteinmal die Frage, was die beiden uint8 und int16 da zu bedeuten 
haben.
Und von denen wird dann der Wert 1,47 (bei 1e+06 als F_CPU) abgezogen. 
Daraus werd ich nicht ganz schlau.

TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);

Danke euch

von Karl H. (kbuchegg)


Lesenswert?

Johannes Hofmann schrieb:
> Hallo
>
> Wie mach ich das aber, wenn ich bei meinem Player Pause machen will und
> dies mittels dieser Schleife tun will:
> while(PAUSE){}  ?
> Da komm ich ja dann nicht mehr raus.

Wer oder was ist PAUSE

Im übrigen:
Du hast es immer noch nicht verstanden. Die Overflow ISR läuft 
eigenständig 'im Hintergrund' mit und überwacht die Tasten. Wann immer 
es dir passt rufst du get_key_short auf und die liefert der den Wert ob 
eine Taste gedrückt wurde.

Deine Schleife ist dann

   while( ! get_key_short( 1 << PAUSE_KEY ) )
     ;

wobei PAUSE_KEY die Pinnummer des Pause Tasters ist

Die musst du natürlich noch richtig konfigurieren. Welche Tasten hast du 
und an welchem Port und an welchem Pin sind sie angeschlossen. zb.:
1
#define KEY_DDR         DDRB
2
#define KEY_PORT        PORTB
3
#define KEY_PIN         PINB
4
#define START_KEY       PB0
5
#define STOP_KEY        PB1
6
#define PAUSE_KEY       PB2
7
#define FORWARD_KEY     PB3
8
#define BACK_KEY        PB4
9
#define ALL_KEYS        (1<<START_KEY | 1<<STOP_KEY | 1<<PAUSE_KEY | 1<<FORWARD_KEY | 1<<BACK_KEY)
10
11
#define REPEAT_MASK     (1<<FORWARD_KEY | 1<<BACK_KEY)       // repeat: key1, key2
12
#define REPEAT_START    50                        // after 500ms
13
#define REPEAT_NEXT     20                        // every 200ms

Sobald der Timer läuft, brauchst du dich um nichts mehr kümmern. Du 
rufst get_key_short auf und die Funktion teilt dir mit, ob die Taste 
seit dem letzten Aufruf gedrückt wurde oder nicht.

> Denn ich wollte über den Interrupt diesen PAUSE-Wert togglen.
> Aber das klappt ja dann nicht mehr in Software.

Doch, das klappt wunderbar.

> Deswegen würd ich nochmal gern wissen, ob ich mit nem RS-Flip-Flop und
> nem Taster arbeiten kann, oder ob das Ding nur bei einem Wechselschalter
> benutzbar ist.

Du machst dir zu viele Sorgen.

Dein main() wird dann in etwa so aussehen
1
....
2
3
4
int main()
5
{
6
   ....
7
8
  KEY_DDR &= ~ALL_KEYS;                // Tastenport konfigurieren
9
  KEY_PORT |= ALL_KEYS;                // Pull Up einschalten
10
 
11
  TCCR0 = (1<<CS02)|(1<<CS00);         // Entprellinterrupt: 1024
12
  TIMSK = 1<<TOIE0;                    // Overflow aktivieren
13
14
  ....
15
16
  sei();
17
18
  playing = FALSE;
19
20
  while( 1 ) {
21
22
    if( get_key_short( 1 << START_KEY ) ) {    // Taste "Start" gedrückt
23
      playing = TRUE;
24
    }
25
26
    if( get_key_short( 1 << STOP_KEY ) ) {     // Taste "Stop" gedrückt
27
      playing = FALSE;
28
    }
29
30
    if( get_key_short( 1 << PAUSE_KEY ) ) {    // Taste "Pause" gedrückt
31
      while( !get_key_short( 1 << PAUSE_KEY ) )  // warte auf erneutes Drücken
32
        ;
33
    }
34
35
                                               // Taste "Vorwärts" gedrückt
36
                                               // Diese Taste hat einen Autorepeat. D.h. wenn
37
                                               // der Benutzer sie länger drückt, liefert get_key_rpt immer wieder true
38
                                               // Siehe auch REPEAT_MASK
39
    if( get_key_press( 1<<FORWARD_KEY ) || get_key_rpt( 1<<FORWARD_KEY ) ) {
40
      if( playing )
41
        ... im gerade gespielten Song ein kleines Stück nach vorne spulen
42
      else
43
        songNr++;    // einen Song weiter
44
    }
45
46
                                               // Taste "Rückwärts" gedrückt
47
                                               // Diese Taste hat einen Autorepeat. D.h. wenn
48
                                               // der Benutzer sie länger drückt, liefert get_key_rpt immer wieder true
49
                                               // Siehe auch REPEAT_MASK
50
    if( get_key_press( 1<<BACK_KEY ) || get_key_rpt( 1<<BACK_KEY ) ) {
51
      if( playing )
52
        ... im gerade gespielten ein kleines Stück Song nach hinten spulen
53
      else
54
        songNr--;    // einen Song zurück
55
    }
56
57
58
    // Tastenbehandlung abgeschlossen, füttere den MP3 Chip mit genügend Daten, sodass
59
    // er was zu tun hat, während die while Schleife die nächste Runde
60
    // Tastenabfragen macht
61
    if( playing ) {
62
      feedMP3Chip( songnr, ... );
63
    }
64
  }
65
}

Die Hauptschleife dreht ständig ihre Runden
  Abfragen, ob irgendeine Taste gedrückt wurde und behandeln wenn ja
  Dem MP3 Chip wieder ein paar Daten vorwerfen, so dass er spielen
  kann, während die nächste Runde Tastenabfragen durchläuft.

Und nein, das Tastenabfragen kostet nicht viel. Das sind ein paar µs die 
dafür draufgehen. Die spürst du kaum bis gar nicht.

von Karl H. (kbuchegg)


Lesenswert?

Johannes Hofmann schrieb:
> Weiterhin noch ne Frage:
> In dem Tutorial wird das Timerinterrupt-Intervall so gesetzt.
> Zu ersteinmal die Frage, was die beiden uint8 und int16 da zu bedeuten
> haben.
> Und von denen wird dann der Wert 1,47 (bei 1e+06 als F_CPU) abgezogen.
> Daraus werd ich nicht ganz schlau.
>
> TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);

Das ist die Berechnung des Timerwertes, so dass der Timer zum Hochzählen 
von diesem Wert bis auf 255 ziemlich genau 10ms benötigt.
Wie gesagt: das kannst du meistens auch weglassen. Ob das jetzt 10ms 
sind oder 20, spielt keine allzugroße Rolle.

von Udo. R. S. (Gast)


Lesenswert?

@ Karl Heinz
Stimmt, ich habe mir die Routine nicht im Detail angesehen (zumal ich in 
AVR assembler mangels Übung etwas eingerostet bin :-)) und nebenbei 
arbeiten muss.
Wie ich aber aus den Beiträgen herauslese macht die Routine genau was 
ich gesagt habe, nämlich zyklisch über einen Timerinterrupt aufgerufen 
werden und sich die Zustände der Taster/Schalter merken (muss er ja 
sowiso bei autorepeat). Die eigentliche Portabfrage und der Vergleich 
des Istzustandes mit dem vorherigen Zustand braucht dann natürlich nur 
ein paar Taktzyklen.
Wenn ich tatsächlich mal wieder den Platz und die Zeit zum Basteln habe 
dann schaue ich mir die Routine genau an und bedanke mich schon mal im 
Voraus dafür die benutzen zu dürfen.

von Johannes (menschenskind)


Lesenswert?

Hallo Karl-Heinz,

Die Sache mit dem Timer-Interrupt hab ich verstanden, keine Angst ;)
PAUSE wird zwischen 0 und 1 hin und hergesetzt.
Das Problem ist halt, dass ich meinen Player gern mit 2 Tasten steuern 
möchte. Mit der einen Taste drücke ich mehrmals, je nachdem, ob ich 
Pause(1xdrücken), oder leiser(2x) oder lauter(3x) machen möchte und mit 
der anderen Taste bestätige ich diese Folge dann und die gezählten 
"Drücker" werden dann an eine Switch-Anweisung weitergegeben und 
ausgewertet.
Und diese beiden Taster hängen dann natürlich an den 
Interrupt-Eingängen.
Deswegen kann ich für die Pause-Anweisung auch nicht deine Variante 
nehmen.

Und deswegen auch nochmal die Frage bzgl. des RS-FFs.

von Peter D. (peda)


Lesenswert?

Johannes Hofmann schrieb:
> Das Problem ist halt, dass ich meinen Player gern mit 2 Tasten steuern
> möchte. Mit der einen Taste drücke ich mehrmals, je nachdem, ob ich
> Pause(1xdrücken), oder leiser(2x) oder lauter(3x) machen möchte und mit
> der anderen Taste bestätige ich diese Folge dann und die gezählten
> "Drücker" werden dann an eine Switch-Anweisung weitergegeben und
> ausgewertet.

Ist damit überhaupt kein Problem:
1
  static uint8_t action = 0;
2
  if(get_key(1<<taste1))
3
    action++;
4
  if(get_key(1<<taste2)){
5
    switch( action )
6
      case 1: action1(); break;
7
      case 2: action2(); break;
8
      case 3: action3(); break;
9
    }
10
    action = 0;
11
  }


Peter

von Peter D. (peda)


Lesenswert?

P.S.:
Muß natürlich get_key_press() heißen.


Peter

von MaWin (Gast)


Lesenswert?

> Lt. Tutorial ist es ja günstig, dieses RS-FlipFlop zu verwenden.
> Kann man diese Schaltung auch benutzen, wenn man nur nen simplen Taster
> hat? bzw. diese ein wenig abwandeln, damit es klappt?

Nein.
Deswegen gibt es unterschiedliche Schaltungen, je anch vorhandenm Taster

http://dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29.1


> Und diese beiden Taster hängen dann natürlich an den
> Interrupt-Eingängen.

Das ist grober Schwachsinn, denn die Pellimpulse von den Tasten können 
so schnell kommen, schneller als dein uC den Interrupts folgen kann.
So eine Lösung wird auch nirgends vorgeschlagen.

Mach einen Interrupt der (länger als die Prellzeit der Taster, also 
z.B.) alle 20msec nachguckt, wie die Tastereingänge stehen.

on Timer_interrupt:
 copy Port -> Tastenzustandvariable aktueller_Zustand

und lass dein Hauptprogramm (in einer Schleife) entscheiden, was es tun 
soll, wenn sich der Tastenzustand geändert hat (nun gedrückt, nun nicht 
mehr gedrückt)

if alter_Zustand != aktuelle_Zustand
  tu was
  alter_Zustand:= aktueller_Zustand


Warum habne alle Leute so massive Probleme, zu verstehen, was prellen 
ist ?

von Karl H. (kbuchegg)


Lesenswert?

MaWin schrieb:

> Mach einen Interrupt der (länger als die Prellzeit der Taster, also
> z.B.) alle 20msec nachguckt, wie die Tastereingänge stehen.
>
> on Timer_interrupt:
>  copy Port -> Tastenzustandvariable aktueller_Zustand
>
> und lass dein Hauptprogramm (in einer Schleife) entscheiden, was es tun
> soll, wenn sich der Tastenzustand geändert hat (nun gedrückt, nun nicht
> mehr gedrückt)
>
> if alter_Zustand != aktuelle_Zustand
>   tu was
>   alter_Zustand:= aktueller_Zustand

mit anderen Worten:
nimm die PeDa Tastenentprellung :-)
und freu dich darüber, dass es funktioniert und geniesse den 
Zusatzkomfort

von Simon K. (simon) Benutzerseite


Lesenswert?

MaWin schrieb:
>> Und diese beiden Taster hängen dann natürlich an den
>> Interrupt-Eingängen.
>
> Das ist grober Schwachsinn, denn die Pellimpulse von den Tasten können
> so schnell kommen, schneller als dein uC den Interrupts folgen kann.
> So eine Lösung wird auch nirgends vorgeschlagen.

Ein im Mikrosekunden Bereich prellender Taster? Hui ;)

von MaWin (Gast)


Lesenswert?

> Ein im Mikrosekunden Bereich prellender Taster? Hui ;)

Natürlich, im Moment der Kontaktgabe bzw. des Kontaktöffnens bilden sich 
kleine Funken aus, und die sind (das Wort Funkstörungen kommen nicht 
ohne Grund daher) sehr schnell am Abreissen und neubilden, auch in 
weniger als Mikrosekunden.

Dass neben der Funkenströrung auch noch das mechanische Prellen 
hinzukommt, wo der Kontakt, wenn er schliesst, eventuell wieder 
"weghüpft" bevor er erneut schliesst, macht die Sache nicht einfacher.

von Simon K. (simon) Benutzerseite


Lesenswert?

Bei einem normalen Eingabetaster? Wo Ströme um die 1mA fließen? Wo hast 
du denn die Horrorgeschichte her!

von Johannes (menschenskind)


Lesenswert?

Ich bin ja sehr dankbar für euer Bemühen, aber wenn ich nun in einer 
Schleife mit while(PAUSE){} bin, dann komm ich doch gar nicht anders 
raus, als wenn PAUSE durch einen Interruptgenerierten Vorgang wieder auf 
0 gesetzt wird.

Und natürlich werden die Taster auch nicht direkt an die 
Interrupteingänge angeschlossen. Deswegen such ich ja nach so einer 
Vorbeschaltung.

Ich hab schon bei Conrad nach so nem Inverter mit 
Schmitt-Trigger-Eingängen gesucht, aber konnte keinen finden. Die haben 
ja auch eine blöde Suche.
Könnt ihr mir da weiterhelfen?

Sorry Mawin, aber dein Link zu diesem Kompendium lässt meinen FF 
abstürzen :(

von Karl H. (kbuchegg)


Lesenswert?

Johannes Hofmann schrieb:
> Ich bin ja sehr dankbar für euer Bemühen, aber wenn ich nun in einer
> Schleife mit while(PAUSE){} bin, dann komm ich doch gar nicht anders
> raus, als wenn PAUSE durch einen Interruptgenerierten Vorgang wieder auf
> 0 gesetzt wird.


Mit anderen Worten.
Du hast das alles schon fertig aufgebaut, hast festgestellt dass es 
nicht so richtig funktioniert und suchst nun nach einer Lösung wie du 
das verkorkste Design noch möglichst billig retten kannst.

nenn doch die Dinge beim Namen

von Simon K. (simon) Benutzerseite


Lesenswert?

Bei einer Liedpause den ganzen Mikrocontroller aufhören lassen zu 
rechnen ist nicht gerade klug.
Die Uhrzeit auf dem Display wird nicht mehr geupdatet. Er ist über 
Ethernet nicht mehr zu erreichen. Der USB Datenlink bricht ab.. ;)

von Johannes (menschenskind)


Lesenswert?

Quatsch!
Da ist noch nix fertig aufgebaut und wie kommst du auf "Billig 
retten"???
Ich hätte es nur gern so gemacht, wie ich es beschrieb. Und dafür 
benötige ich die Hardware-Entprellung.
Und somit steht wieder die Frage vom Thread-Anfang.
Doch leider killt ja der Link von MaWin meinen FF.

von Karl H. (kbuchegg)


Lesenswert?

Johannes Hofmann schrieb:
> Quatsch!
> Da ist noch nix fertig aufgebaut und wie kommst du auf "Billig
> retten"???

Weil ich lang genug hier im Forum mitlese :-)
Wenn sich jemand standhaft weigert eine Softwarelösung anstelle einer 
aufwändigeren Hardwarelösung einzusetzen, dann bedeutet das im Regelfall 
nur eines :-)

> Ich hätte es nur gern so gemacht, wie ich es beschrieb. Und dafür
> benötige ich die Hardware-Entprellung.
> Und somit steht wieder die Frage vom Thread-Anfang.

Im Artikel "Entprellung" ist ja dann auch noch die Hardware-Lösung für 
Einfachtaster angegeben. Ausser das die einfacher ist als das FF, was 
genau gefällt dir daran nicht?

http://www.mikrocontroller.net/articles/Entprellung#Einfacher_Taster

von Johannes (menschenskind)


Lesenswert?

Weil ich mir bei Pollin grad paar NAND-ICs gekauft habe. Leider hab ich 
das mit Wechselschalter und Taster übersehen.
Deswegen die Frage, ob man auch nen Taster mit ner Flip-Flop-Schaltung 
entprellen kann.
In jedem anderen Fall hätte ich natürlich sofort die Software-Lösung 
benutzt. Gar keine Frage.
Und meine Standhaftigkeit habe ich ja hoffentlich ausreichend erläutert.

Ne ganz harte Variante wäre ja auch die Nutzung eines 2. uC für die 
Entprellung. Oder wie war das mit den Kanonen und den Spatzen...

Könnt ihr anderen den Link vom MaWin öffnen?

von Peter D. (peda)


Lesenswert?

Johannes Hofmann schrieb:
> Ich bin ja sehr dankbar für euer Bemühen, aber wenn ich nun in einer
> Schleife mit while(PAUSE){} bin, dann komm ich doch gar nicht anders
> raus, als wenn PAUSE durch einen Interruptgenerierten Vorgang wieder auf
> 0 gesetzt wird.

Und wo ist dabei das Problem?
1
  while( pause ){
2
    if( get_key_press( 1<<taste1 ))
3
      pause = 0;
4
// usw.
5
  }

So einfach ist das mit den Entprellfunktionen.


Peter

von Johannes (menschenskind)


Lesenswert?

Aber nichtsdestotrotz probiere ich natürlich grade mit der Routine, auch 
zwecks Lerneffekt.
Doch leider will es nicht wie ich wohl will.

Im Moment sieht der Code bei mir so aus:
1
#define KEY_DDR         DDRD
2
#define KEY_PORT        PORTD
3
#define KEY_PIN         PIND
4
#define KEY1            1
5
#define KEY2            2
6
7
8
ISR( TIMER0_OVF_vect )                            // every 10ms
9
{
10
  static uint8_t ct0, ct1/*, rpt*/;
11
  uint8_t i;
12
 
13
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
14
 
15
  i = key_state ^ ~KEY_PIN;                       // key changed ?
16
  ct0 = ~( ct0 & i );                             // reset or count ct0
17
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
18
  i &= ct0 & ct1;                                 // count until roll over ?
19
  key_state ^= i;                                 // then toggle debounced state
20
  key_press |= key_state & i;                     // 0->1: key press detect
21
22
}
23
24
uint8_t get_key_press( uint8_t key_mask )
25
{
26
  cli();                                          // read and clear atomic !
27
  key_mask &= key_press;                          // read key(s)
28
  key_press ^= key_mask;                          // clear key(s)
29
  sei();
30
  return key_mask;
31
}
32
 
33
uint8_t get_key_short( uint8_t key_mask )
34
{
35
  cli();                                          // read key state and key press atomic !
36
  return get_key_press( ~key_state & key_mask );
37
38
int main(void){
39
40
char Counter=0;
41
 sei();
42
43
KEY_DDR = 0;                // konfigure key port for input
44
KEY_PORT = 255;
45
46
TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
47
TIMSK = 1<<TOIE0;        // enable timer interrupt
48
49
50
51
while(1){
52
      if( get_key_short( 1<<KEY1 ))
53
          Counter++;
54
    if( get_key_short( 1<<KEY2 )){
55
      if(Counter){
56
        LED_EVENT3(LED1,Counter);
57
        Counter=0;
58
      }
59
    }
60
}

Mein uC läuft mit 8 MHz. Muss ich da beim Timerinterrupt noch was 
anpassen?

von Peter D. (peda)


Lesenswert?

get_key_short und get_key_long darf man nur dann benutzen, wenn man die 
Drückdauer auswerten will und dann auch immer beide!


Peter

von Peter D. (peda)


Lesenswert?

Und entweder den Optimierungsschalter: -fno-inline-small-functions
oder key_press als volatile.


Peter

von MaWin (Gast)


Lesenswert?

> Wo hast du denn die Horrorgeschichte her!

Simon, Ball flachhalten, auch wenn du den Blitz nicht geissend hell aus 
dem Gehäuse rauskommen siehst, heisst das nicht, dass nicht welche 
entstehen. Sie entstehen bei jedem Stromfluss und jeder Spannung.

> Könnt ihr anderen den Link vom MaWin öffnen?

500kB Datei, dauert länger.

von Chris S. (hondaracer1)


Lesenswert?

taster entprellen mit einem FF geht nicht

allgemein steh ich nich auf hardwareloesungen wenn es auch per software 
geht, da die schaltung dann nur unnoetig groesser wird.
Taster hardwaremaesig entprellen noch dazu nicht zuverlaessiger als eine 
brauchbare software loesung, ausser das man die hardware hirnlos 
nachbauen kann ;-)

Ach das mit der "Horrorgeschichte" stimmt natuerlich, auch bei kleinen 
Spannungen entstehen Funken wenn sich kontakte naehern. Das manche 
taster mehr und manche weniger prellen haengt daher mit der mechanik und 
der beschaffenheit der kontaktflaechen ab.   Es gibt natuerlich auch 
entprellte schalter aber die sind dann natuerlich nicht rein mechisch

von Johannes (menschenskind)


Lesenswert?

Hello again.
So mein Code sieht jetzt so aus. Klar hatte ich key_state und key_press 
als volatile, ich hatte bloß vergessen es in meinem letzten Post 
hinzuschreiben.
1
TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
2
TIMSK = 1<<TOIE0;        // enable timer interrupt
3
4
while(1){
5
      if( get_key_press( 1<<KEY1 ))
6
          Counter++;
7
    if( get_key_press( 1<<KEY2 )){
8
      if(Counter){
9
        LED_EVENT3(LED1,Counter);
10
        Counter=0;
11
      }
12
    }
13
}

Doch seltsamerweise wird beim Starten des uC einmal ohne mein Zutun KEY1 
"gedrückt", sodass natülrich 'Counter' inkrementiert wird.

Habt ihr da ne Idee, was da für "Geister" am Werk sind?
Habe auch den Prescaler auf 8 gesetzt um wirklich eine zuverlässige 
Abtastung zu erreichen.Doch das brachte auch keine Besserung.
Auch wenn die Taster gar nicht an den Ports hängen wird ein "Drücken" 
detektiert.

von Peter D. (peda)


Lesenswert?

Taster gegen VCC und externe Pulldowns, statt gegen GND und interne 
Pullups?


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.