mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega8 Taster an Interrupt löst zweimal aus


Autor: BeYourself (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abend,
ich bin gerade dabei ein kleines Programm für den Atmega zu schreiben, 
aber verzweifle an den ganzen Enprellgeschichten :(

Hier mal mein Code, das Problem ist, dass er nach 2,5 Sekunden wieder 
ausgelöst wird
ISR(INT0_vect) { //Interrupt an Pin INT0
  uart_puts("Taste gedrueckt\n");
  if(TIMSK & OCIE1A) {
    TIMSK |= (0<<OCIE1A);
    }
  else {
    TIMSK |= (1<<OCIE1A);
    }
  _delay_ms(2500);
}

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  _delay_ms(2500);

in der ISR. Sag mal, bist du des Wahnsinns?

Autor: Markus F. (5volt) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Während eine ISR ausgeführt wird, speichert sich der Controller alle 
weiteren Interrupts und führt sie nachher aus.
Durch das Prellen des Tasters wird INT0 mehrmals ausgelöst, kann aber 
nur einmal alle 2,5s ausgeführt werden. Daher wird der Interrupt zweimal 
nacheinander ausgelöst.
Abhilfe würde vermutlich bringen, in der ISR INT0 abzuschalten und am 
Ende wieder zu aktivieren.
Und 2,5s Wartezeit in einer ISR macht man normalerweise auch nicht...

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, ein Versuch einer Erklärung, was passiert.

1. Der Interrupt wird ausgelöst. Das interne Flag für die 
Interruptquelle wird zurückgesetzt.

2. Das Interruptflag im SREG wird gelöscht (dafür sorgt der Compiler).

3. Das bisschen Code vor dem delay wird abgearbeitet, dann beginnt das 
Delay

4. Der Taster prellt, das Flag für den INT0 wird gesetzt, wegen 
gesperrten Interrupts wird die ISR nicht nochmal aufgerufen.

5. Das Delay ist zuende nach 2,5 sec

6. Die Interrupts werden global wieder aktiviert (dafür sorgt der 
Compiler) und die ISR verlassen

7. INT0 steht an und Interrupts sind aktiv -> ISR wird angesprungen

Klar warum das alles eine schlechte Idee ist, was du da vorhast?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Wow. Ich kann zwar kein C, aber in dem Stück Code dürfte alles, was man 
in einer Interrupt-Routine falsch machen kann drin sein.

MfG Spess

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal angenommen, der TE ist nicht des Wahnsinns, sondern es ist nur zur 
Übung und nicht zur Verwendung in einem realen Programm.

Dann muss nach dem delay_ms() das Flag für INT0 rückgesetzt werden, denn 
das wurde zwar beim Aufruf der Interrupt-Routine automatisch 
rückgesetzt, danach aber gleich wieder durch Prellen gesetzt.  Deshalb 
kommt der Interrupt gleich wieder.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BeYourself schrieb:
> aber verzweifle an den ganzen Enprellgeschichten :(

Wobei denn konkret?

Hier z.B. mit einem Demoprogramm, welches die Entprellschritte im 
1s-Takt anzeigt:

http://www.avrfreaks.net/index.php?module=Freaks%2...


> Hier mal mein Code, das Problem ist, dass er nach 2,5 Sekunden wieder
> ausgelöst wird

Wirklich ein sehr schönes Beispiel, warum man doch besser eine 
Entprellroutine nehmen sollte.


Peter

Autor: BeYourself (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abend nochmal,
hab mir mal den Link angeschaut und versucht, das ganze auf einem 
Atmega8 zum laufen zu bringen. Anstatt dem Timer1 habe ich es so 
versucht, dass der zweite Timer verwendet wird (Den 16bit-Timer verwende 
ich schon in meinem Programm). Leider passiert nichts, wenn ich PB0 oder 
PB1 auf GND oder VCC ziehe :(

Und mein Code oben wollte nicht in einem "richtigen" Programm verwenden, 
sondern habe die Zeit erstmal einmal erhöht, um auszuschließen, dass die 
Zeit zwischen zwei Interrupts nicht zu schnell vorbeigeht.

Hier mal mein Versuch, der auch noch eine Warnung ausspuckt:
../tasten_entrpellen.c:112: warning: overflow in implicit constant 
conversion

Den Compiler habe ich mit "--std=c99" gestartet.
Werde mich dann morgen/heute nochmal dransetzen

MFG BeYourself
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys        */
/*      Sampling 4 Times        */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                                                                      */
/************************************************************************/

#include <util\atomic.h>    // need "--std=c99"


typedef unsigned char  u8;
typedef signed short  s16;

#define  XTAL    8e6    // 8MHz

#define KEY_PIN    PINB
#define KEY_PORT  PORTB
#define KEY_DDR    DDRB
#define KEY0    0
#define  KEY1    1

#define LED_DDR    DDRD
#define LED_PORT  PORTD
#define LED0    0
#define  LED1    1
#define LED3    3
#define LED4    4
#define LED5    5
#define LED6    6
#define LED7    7


u8 key_state;        // debounced and inverted key state:
          // bit = 1: key pressed
u8 key_press;        // key press detect

u8 ct0 = 0xFF, ct1 = 0xFF;    // internal debouncing states


ISR( TIMER2_COMP_vect )
{
  u8 i;

  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
}


u8 get_key_press( u8 key_mask )
{
  ATOMIC_BLOCK(ATOMIC_FORCEON){
    key_mask &= key_press;    // read key(s)
    key_press ^= key_mask;    // clear key(s)
  }
  return key_mask;
}


void display_debounce_key0( void )  // demonstrate debounce working
{
  u8 i;

  ATOMIC_BLOCK(ATOMIC_FORCEON){
    i = ct0 & 1<<KEY0;      // collect the two bits for KEY0
    if( ct1 & 1<<KEY0 )      // from vertical counter
      i |= 2;
  }
  switch( i ){        // LED7..4 = debounce counter for KEY0
    case 0:
        LED_PORT &= ~(1<<LED4);
        LED_PORT |= 1<<LED5;
        LED_PORT |= 1<<LED6;
        LED_PORT |= 1<<LED7;
        break;
    case 1:
        LED_PORT |= 1<<LED4;
        LED_PORT &= ~(1<<LED5);
        LED_PORT |= 1<<LED6;
        LED_PORT |= 1<<LED7;
        break;
    case 2:
        LED_PORT |= 1<<LED4;
        LED_PORT |= 1<<LED5;
        LED_PORT &= ~(1<<LED6);
        LED_PORT |= 1<<LED7;
        break;
    case 3:
        LED_PORT |= 1<<LED4;
        LED_PORT |= 1<<LED5;
        LED_PORT |= 1<<LED6;
        LED_PORT &= ~(1<<LED7);
        break;
  }
  if( key_state & 1<<KEY0 )    // LED3 = debounced state
    LED_PORT &= ~(1<<LED3);
  else
    LED_PORT |= 1<<LED3;
}


int main( void )
{
  TCCR2 = 0;
  TCCR2 = 1<<WGM21      // Mode 4: CTC
   ^ 1<<CS22^1<<CS20;    // divide by 1024
  OCR2 = XTAL / 1024.0 * 1 - 1;  // 1s
  TCCR2 = 0;
  TIMSK = 1<<OCIE2;      // enable T1 interrupt

  KEY_DDR = 0;        // input
  KEY_PORT = 0xFF;      // pullups on
  LED_PORT = 0xFF;      // LEDs off (low active)
  LED_DDR = 0xFF;      // LED output
  key_state = ~KEY_PIN;      // no action on keypress during reset
  sei();

  for(;;){          // main loop
    display_debounce_key0();

    if( get_key_press( 1<<KEY0 ))  // LED0 = toggle on keypress
      LED_PORT ^= 1<<LED0;

    if( get_key_press( 1<<KEY1 ))  // LED1 = toggle on keypress
      LED_PORT ^= 1<<LED1;
  }
}


Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  TCCR2 = 0;
  TCCR2 = 1<<WGM21      // Mode 4: CTC
   ^ 1<<CS22^1<<CS20;    // divide by 1024
  OCR2 = XTAL / 1024.0 * 1 - 1;  // 1s
  TCCR2 = 0;
Wenn du den Timer gleich nach der Konfiguration wieder abschaltest, ist 
es auch kein Wunder, wenn nichts passiert. ;-)

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
alles wird einfacher, wenn man taster nicht an einen interupt 
anschließt, sondern pollt

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BeYourself schrieb:
> Hier mal mein Versuch, der auch noch eine Warnung ausspuckt:
> ../tasten_entrpellen.c:112: warning: overflow in implicit constant
> conversion

Ja, da hat er auch recht.

Es ist ja explizit als Demo gedacht, damit man an den LEDs die einzelnen 
Phasen der Entprellung mitverfolgen kann.

In der Praxis is 1s Entprelltakt völliger Unsinn, da nimmt man etwa 
2ms..50ms. Und dann paßt der Reloadwert auch in 8Bit rein.


Peter

Autor: I. E. (anfaenger69)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ahem, Chef... das hier funktioniert nicht:

    TIMSK |= (0<<OCIE1A);

Es müsste lauten:

    TIMSK &= ~(1<<OCIE1A);

Vielleicht ist das der ganze Fehler weil Du den Timer nicht 
ausgeschaltet hast.

Autor: BeYourself (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Soo, ich habe mich nochmal dran gesetzt und möchte euch meine Lösung 
natürlich nicht vorenthalten ;-)

Erstmal hier meine Anpassung für  Peter Danneggers Entprellmethode für 
einen Atmega8 und den 2. Timer:
/************************************************************************/
/*                                                                      */
/*                      Debouncing 8 Keys        */
/*      Sampling 4 Times        */
/*                                                                      */
/*              Author: Peter Dannegger                                 */
/*                                                                      */
/************************************************************************/

#include <util\atomic.h>    // need "--std=c99"


typedef unsigned char  u8;
typedef signed short  s16;

#define  XTAL    8e6    // 8MHz

#define KEY_PIN    PINB
#define KEY_PORT  PORTB
#define KEY_DDR    DDRB
#define KEY0    0
#define  KEY1    1

#define LED_DDR    DDRD
#define LED_PORT  PORTD
#define LED0    0
#define  LED1    1
#define LED3    3
#define LED4    4
#define LED5    5
#define LED6    6
#define LED7    7


u8 key_state;        // debounced and inverted key state:
          // bit = 1: key pressed
u8 key_press;        // key press detect

u8 ct0 = 0xFF, ct1 = 0xFF;    // internal debouncing states


ISR( TIMER2_COMP_vect )
{
  u8 i;

  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
}


u8 get_key_press( u8 key_mask )
{
  ATOMIC_BLOCK(ATOMIC_FORCEON){
    key_mask &= key_press;    // read key(s)
    key_press ^= key_mask;    // clear key(s)
  }
  return key_mask;
}

int main( void )
{
  TCCR2 = 0;
  TCCR2 |= 1<<WGM21      // Mode 4: CTC
   ^ 1<<CS22^1<<CS20;    // divide by 1024
  OCR2 = XTAL / 1024.0 * 1 - 1;  // 1s
  TIMSK |= 1<<OCIE2;      // enable T1 interrupt

  KEY_DDR = 0;        // input
  KEY_PORT = 0xFF;      // pullups on
  LED_PORT = 0x00;      // LEDs off (low active)
  LED_DDR = 0xFF;      // LED output
  key_state = ~KEY_PIN;      // no action on keypress during reset
  sei();

  for(;;){          // main loop
    //display_debounce_key0();

    if( get_key_press( 1<<KEY0 )) {// LED on
      LED_PORT = 0xFF;
    }

    if( get_key_press( 1<<KEY1 )) {  // LED1 = toggle on keypress
      LED_PORT ^= 1<<LED0;
    LED_PORT ^= 1<<LED1;
    LED_PORT ^= 1<<LED3;
    LED_PORT ^= 1<<LED4;
    }
  }
}

@Igor:
Da hat du auch wieder recht, dass hat zwar glaubig mal funktioniert, ist 
aber auch nicht gerade schön, habe ich jetzt mal geändert.

Um noch einmal auf die Warnung zu sprechen zu kommen: Ich habe mich dann 
mal für die 2ms entschieden und es entsprechen angepasst:
TCCR2 |= 1<<CS22;    // divide by 64
    OCR2 = 6;

Bis jetzt funktioniert wieder alles und ich kann mal ein wenig 
weiterschreiben. Als nächstes muss ich gucken, wie ich verschiedene 
Variablen und Befehle vom PC oder einem anderen Controller (über RS/TWI) 
in den Controller bekomme.

Ich sage noch einmal danke für eure Mithilfe
BeYourself

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.