mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Taster mehrmals gedrückt? mit Zähler?


Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo leute fuer euch Profis wahrscheinlich ein ganz simples Problem.
Ich möchte einen Taster abfragen ob er mehrmals gedrückt ist. 
Genauergesagt ober 5 mal gedrückt wurde.

Ich hätte jetzt gedacht an eine Schleife die 20 ms Sekunden warten und 
so eine Zählvariable raufzähl, jedoch funktioniert nicht wirklich?
Ist diese Idee von dem Grundkonzept brauchbar?, den aus dem Wiki Artikel 
werde ich als Laie nicht wirklich schlau daraus.



Ich hoffe ich geh auch nicht allzu sehr auf die Nerven falls doch 
Entschuldige ich mich gleich vorwegs.

mfG Lukas

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aufpassen. Taster neigen zum prellen. Dies
könnte auch schon als Tastendruck gewertet werden.
Sonst geht es mit einer Zählvariable.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mehrmaliges Drücken ist dadurch gekennzeichnet, dass es Gedrückt- und 
Losgelassen-Phasen bestimmter Mindestdauern und im Wechsel gibt. Beides 
kann man schon in einer Schleife abfragen.

Die Zeit 20ms für ein sicheres Erkennen eines Zustands 
("gedrückt/losgelassen wird nur registriert, wenn 20ms noch 
gedrückt/losgelassen ist") kann man nehmen. Das läuft dann auf das 
Warteschleifen-Verfahren bei der Softwareentprellung von Tastern raus 
(Entprellung)

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich hab jz den Code :
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                      With Repeat Function                            */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                      danni@specs.de                                  */
/*                                                                      */
/************************************************************************/
 
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#ifndef F_CPU
#define F_CPU           1000000                   // processor clock frequency
#warning kein F_CPU definiert
#endif
 
#define KEY_DDR         DDRD
#define KEY_PORT        PORTD
#define KEY_PIN         PIND
#define KEY0            7
#define KEY1            7
#define KEY2            7
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
 
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms
 
#define LED_DDR         DDRD
#define LED_PORT        PORTD
#define LED0            5
#define LED1            5
#define LED2            5
 
volatile uint8_t key_state;                                // debounced and inverted key state:
                                                  // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect
 
volatile uint8_t key_rpt;                                  // key long press and repeat
 
 
ISR( TIMER0_OVF_vect )                            // every 10ms
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;
 
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
 
  i = key_state ^ ~KEY_PIN;                       // key changed ?
  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
 
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}
 
int main( void )
{
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
  TIMSK = 1<<TOIE0;        // enable timer interrupt
 
  LED_PORT = 0xFF;
  LED_DDR = 0xFF;                     
 
  while(1){
    if( get_key_short( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;
 
    if( get_key_long( 1<<KEY1 ))
      LED_PORT ^= 1<<LED2;
 
                                                  // single press and repeat
 
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      uint8_t i = LED_PORT;
 
      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      
    }
  }
}



jedoch leuchtet bei Betätigung des Taster keine Led auf, die Definition 
meiner Ports müsste richtig sein

PD7--> Taster(High Active)
PD5--> Led

Ich frage mich schon ne Zeit woran das liegen könnte?

mfG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas Migi schrieb:

> PD7--> Taster(High Active)
> PD5--> Led

Du hast Taster und LED an ein und demselben Port

 TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
  TIMSK = 1<<TOIE0;        // enable timer interrupt
 
  LED_PORT = 0xFF;
  LED_DDR = 0xFF;

Gratuliere. Du hast soeben den komplette Port D auf Ausgang gestellt

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peinlich Peinlich :D
ich hab jz den Taster auf PortB gelegt:
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys                               */
/*                      Sampling 4 Times                                */
/*                      With Repeat Function                            */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                      danni@specs.de                                  */
/*                                                                      */
/************************************************************************/
 
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#ifndef F_CPU
#define F_CPU           1000000                   // processor clock frequency
#warning kein F_CPU definiert
#endif
 
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            1
#define KEY1            1
#define KEY2            1
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
 
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms
 
#define LED_DDR         DDRD
#define LED_PORT        PORTD
#define LED0            5
#define LED1            5
#define LED2            5
 
volatile uint8_t key_state;                                // debounced and inverted key state:
                                                  // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect
 
volatile uint8_t key_rpt;                                  // key long press and repeat
 
 
ISR( TIMER0_OVF_vect )                            // every 10ms
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;
 
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
 
  i = key_state ^ ~KEY_PIN;                       // key changed ?
  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
 
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}
 
int main( void )
{
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
  TIMSK = 1<<TOIE0;        // enable timer interrupt
 
  LED_PORT = 0xFF;
  LED_DDR = 0xFF;                     
 
  while(1){


    if( get_key_short( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;
 
    if( get_key_long( 1<<KEY1 ))
      LED_PORT ^= 1<<LED1;
 
                                                  // single press and repeat
 
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      uint8_t i = LED_PORT;
 
      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      
    }
  }
}

jedoch ist die Situation gleich geblieben ...

mfG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Überdenk das doch bitte noch mal
      uint8_t i = LED_PORT;
 
      i = (i & 0x07) | ((i << 1) & 0xF0);
      if( i < 0xF0 )
        i |= 0x08;
      LED_PORT = i;      

Nimm einfach mal an, so wie du das gemacht hast, dass LED_PORT am Anfang 
0xFF ist. Und dann gehe einfach alles durch und sieh nach, was da am 
Ende dabei rauskommt und wie das deine LED am Pin 5 beeinflusst.

Ich bin mir nicht ganz sicher, was da bei den Abfragen tatsächlich 
passiert. Aber warum teilst du den Tasten-Routinen mit, dass du 3 Tasten 
hättest, wenn dann alle Tasten am gleichen Pin sitzen. De Facto hast du 
damit ja nur 1 Taste. -> Hör auf die Routinen anzulügen und konfiguriere 
das richtig.
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            1
#define ALL_KEYS        (1<<KEY0)
 
#define REPEAT_MASK   // kein Repeat auf irgendeiner Taste

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hilft auch nichts.
Pull Up hab ich auch keinen Drauf da die Internen aktiv sind.
Häng ich in die While (1)schleife ne Led Rein leuchtet die ohne Mucken.
Irgendwie weis ich nicht woran das liegt?

mfG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast vergessen die Interrupts freizugeben

Taster an Port B, Pin 1
LED an Port B, Pins 4, 5, 6
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#ifndef F_CPU
#define F_CPU           1000000                   // processor clock frequency
#warning kein F_CPU definiert
#endif
 
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            1
#define ALL_KEYS        (1<<KEY0)
 
#define REPEAT_MASK     0                         // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms
 
#define LED_DDR         DDRB
#define LED_PORT        PORTB
#define LED0            4
#define LED1            5
#define LED2            6
 
volatile uint8_t key_state;                                // debounced and inverted key state:
                                                  // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect
 
volatile uint8_t key_rpt;                                  // key long press and repeat
 
 
ISR( TIMER0_OVF_vect )                            // every 10ms
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;
 
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
 
  i = key_state ^ ~KEY_PIN;                       // key changed ?
  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
 
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}
 
int main( void )
{
  uint8_t cnt;

  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
  TIMSK = 1<<TOIE0;        // enable timer interrupt
 
  LED_DDR |= ( 1 << LED0 ) | (1<<LED1) | (1<<LED2);

  cnt = 0;

  sei();

  while(1){

    if( get_key_press( 1<<KEY0 )) {
      cnt++;
      LED_PORT = (cnt << 4) | ALL_KEYS;
    }
  }
}

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
welche Interrupts meinst du?

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tut mir Leid, dass ich immer mit so Anfängerfragen nerve, ich will 
jedoch nicht nur Programme abkupfern sondern die auch einigermaßen 
verstehen.

Danke trotzdem für die hilfreichen Antworten!



mfG,
Lukas

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas Migi schrieb:
> welche Interrupts meinst du?

Die globale Interruptfreigabe mittels sei()

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh danke jetzt hab ichs!
Vielen DANK!
mfG
Lukas

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habs jetzt nochmals getestet jedoch funktioniert das auch mit der 
Änderung der Interrupts nicht.

Soll ich trotzdem einen externen Pullup verwenden?


mfG

Autor: Lukas Migi (luke_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt leuchte auf einmal 2 Leds dauerhaft und bei der 3ten passiert 
nichts?
Komisch irgendwie?
Achja verwenden tu ich einen Mega8




mfG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Benutze das Programm, das ich weiter oben gepostet habe.
Taster und Led so verdrahten wie angegeben.

Das wurde auf einem Mega16 getestet und läuft definitiv.
Bei jedem Tastendruck wird ein Zähler hochgezählt und der aktuelle 
Zählerstand an den 3 Led ausgegeben -> mit jedem Tastendruck ändert sich 
das Muster und du kannst die Binärzahlen an den Led erkennen.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Soll ich trotzdem einen externen Pullup verwenden?

Das ist schnurz, weil es höchstwahrscheinlich nicht am Pullup liegt, und 
auch nicht daran, dass der Controller defekt ist, und Dein Compiler hat 
auch keinen Bug. Es liegt schlicht an Deinem Programm.

Projektvorschlag: Eine LED + ein Taster. Sonst nix. Die LED geht beim 
Drücken (und Loslassen) der Taste an, und beim nächsten Drücken wieder 
aus, und immer so weiter. "Ist ja voll easy" mag man glauben, aber das 
Gegenteil trifft zu: Dies so zu realisieren, dass es einwandfrei und 
zuverlässig funktioniert ist eine erstaunlich anspruchsvolle 
Aufgabenstellung, denn dazu muss der Taster ordentlich entprellt 
werden.

Versuch, erstmal das hinzubekommen. Solange das nicht hundertpro klappt, 
kann auch alles weitere nicht richtig funzen. Step by Step heißt die 
Devise. Viel Erfolg.

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.