mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Externe Interrupts am mega32


Autor: pille1990 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein Problem bei den externen Interrupts (INT0 und INT1) am 
mega32.
Ich habe sie auf steigende Flanke gestellt und will damit ein Druck von 
einem Taster erfassen. In dem Programm heissen die Taster "Stopptaster" 
und "Modustaster". Mit den Tastern werden unter anderem LEDs ein und 
ausgeschaltet. In der ISR wird auch noch ein Bit in einem Register 
"stop" und "modus" gesetzt bzw gelöscht.

Wenn ich nun einen Taster drücke funktioniert manchmal die ISR richtig 
und manchmal nicht. Im Klartext manchmal wird die entsprechende LED 
richtig geschaltet (beim ersten drücken geht sie an und beim nächsten 
drücken wieder aus) und manchmal passiert es, dass die LED beim drücken 
angeht und beim loslassen wieder ausgeht.
Die Taster sind die auf dem Pollin Zusatzentwicklungsboard (mit 
Kondensator und Widerstand entprellt). Die Flanken habe ich mit schon 
mit dem Oszi angeschaut...wunderbar...da prellt nichts.

Woran kann es liegen dass die ISR nicht immer richtig funktioniert?

Vielen Dank schon mal für Antworten!

Gruß
Pille
/**********************************************************************/
/************************Ambilight made by PiLLe***********************/
/******************************Version 11.0****************************/
/**********************************************************************/
/*Anschluss:                              */
/*OUT_RED:      OCR0 (PB3)                      */
/*OUT_GREEN:    OCR1A (PD5)                      */
/*OUT_BLUE:      OCR2 (PD7)                      */
/*Stopptaster:    PD2 (INT0)                      */
/*Modustaster    PD3  (INT1)                      */
/*Poti:        PA1                          */
/*Stop-LED      PA5                          */  
/*Durchlauf-LED:  PA6                          */  
/*AD-Wandler-LED:  PA7                          */    
/**********************************************************************/


/**********************************************************************/
//Includes
/**********************************************************************/

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

/**********************************************************************/
//Defines
/**********************************************************************/

#define OUT_RED       OCR0
#define OUT_GREEN       OCR1A
#define OUT_BLUE       OCR2
#define INT0_vect      _VECTOR(1)
#define INT1_vect      _VECTOR(2)

//merker für stop
volatile uint8_t stop = 0x00;

//merker für modus
volatile uint8_t modus = 0x00;

/**********************************************************************/
//Interruptroutinen
/**********************************************************************/
    
//ISR für stoptaster    
ISR(INT0_vect)
  {

  //interrupts ausschalten, damit während des interruptdurchlaufs nicht das nächste mal der interrupt ausgelöst wird
  cli();
  
  //wenn taster schon gedrückt wurde bit löschen, sonst bit setzen
  if(stop == 0x01)
    {
    stop = 0x00;

    //stop led aussschalten
    PORTA &= ~ (1 << PA5);

    //durchlauf led einschalten
    PORTA |= (1 << PA6);
    }

  else
    {
    stop = 0x01;

    //stop led einschalten
    PORTA |= (1 << PA5);

    //durchlauf led ausschalten
    PORTA &= ~ (1 << PA6);
    }


  //general interrupt flag register bit mit 1!! zurücksetzen, damit interrupt nicht gleich wieder startet 
  GIFR |= (1 << INTF0);
  
  //interrupts wieder erlauben
  sei();
  }


//ISR für modustaster
ISR(INT1_vect)
  {

  //interrupts ausschalten
  cli();
  
  //wenn taster schon gedrückt wurde bit löschen, sonst bit setzen
  if(modus == 0x01)
    {
    modus = 0x00;

    //ad-wandler led ausschalten
    PORTA &= ~ (1 << PA7);

    //durchlauf led einschalten
    PORTA |= (1 << PA6);

    //stopptaste wieder aktivieren
    GICR |= (1 << INT0);
    }

  else
    {
    modus = 0x01;
    
    //ad wandler led einschalten
    PORTA |= (1 << PA7);

    //durchlauf led ausschalten
    PORTA &= ~ (1 << PA6);

    //stopptaste deaktivieren
    GICR &= ~(1 << INT0);
    }
  
  //general interrupt flag register bit mit 1!! zurücksetzen, damit interrupt nicht gleich wieder startet 
  GIFR |= (1 << INTF1);

  //interrupts erlaufen
  sei();
  }
  
/**********************************************************************/
//Hauptprogramm
/**********************************************************************/
         
int main()
{

//durchlauf led einschalten
PORTA |= (1 << PA6);

/**********************************************************************/
//Variablen
/**********************************************************************/

//pwm array
uint8_t pwm_value[192] =  { 0,   21,  41,  59,  76,  91,  105, 117, 129, 139, 149, 158, 166, 174, 181, 187, 
            193, 198, 203, 207, 211, 215, 218, 221, 224, 227, 229, 231, 233, 235, 237, 238, 
            240, 241, 242, 243, 244, 245, 246, 247, 247, 248, 249, 249, 250, 250, 251, 251,
            251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 

            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      
            255, 254, 254, 254, 254, 254, 253, 253, 253, 253, 253, 253, 252, 252, 252, 252, 
            251, 251, 251, 250, 250, 249, 249, 248, 247, 247, 246, 245, 244, 243, 242, 241,
            240, 238, 237, 235, 233, 231, 229, 227, 224, 221, 218, 215, 211, 207, 203, 198,
            193, 187, 181, 174, 166, 158, 149, 139, 129, 117, 105, 91,  76,  59,  41,  21};

  //zählvariablen
  uint8_t value_red = 0;
  uint8_t value_green = 0;
  uint8_t value_blue = 0;

  //wert für stehenden modus
  uint8_t color_value = 0;

  //geschwindigkeitsvariable
  uint16_t speed;

  //geschwindigkeitsmultiplizierfaktor
  uint8_t factor = 3;

  //maximum der zählschritte (durch array festgelegt)
  uint8_t maximum = 191;

/**********************************************************************/
//Interruptdefinition
/**********************************************************************/

  //Interrupt konfigurieren fallenden flanke
  MCUCR |= (1 << ISC00) | (1 << ISC01);
  MCUCR |= (1 << ISC10) | (1 << ISC11);


  //Interrupt aktivieren
  GICR |= (1 << INT0);
  GICR |= (1 << INT1);

/**********************************************************************/
//Ad-Wandlerdefinition
/**********************************************************************/

  //adc enable
  ADCSRA |= (1 << ADEN);

  //messvorgang starten
  ADCSRA |= (1 << ADSC);

  //freerunning mode starten
  ADCSRA |= (1 << ADATE);

  //prescaler auf 62 khz
  ADCSRA |= (1 << ADPS2);

  //AVCC als referenz nehmen
  ADMUX |= (1 << REFS0);

  //kanal 1 auswählen
  ADMUX |= (1 << MUX0);

  //ad-wandler auf 8bit stellen
  ADMUX |= (1 << ADLAR);


/**********************************************************************/
//Timerdefinition
/**********************************************************************/

  //prescaler einstellen
  TCCR0 |= (1 << CS00);

  TCCR1B |= (1 << CS10);
  
  TCCR2 |= (1 << CS20);


  //timer auf fast pwm mode stellen
  TCCR0 |=  (1 << WGM00);

  TCCR1A |= (1 << WGM10);
  TCCR1B |= (1 << WGM12);

  TCCR2 |= (1 << WGM20);


  //invertierte pwm
  TCCR0 |= (1 << COM00);
  TCCR0 |= (1 << COM01);

  TCCR1A |= (1 << COM1A0) | (1 << COM1A1);  
  TCCR1A |= (1 << COM1B0) | (1 << COM1B1);
  
  TCCR2 |= (1 << COM20);
  TCCR2 |= (1 << COM21);


  //hiermit wird der gewünschte pwm wert eingestellt
  OUT_RED = 0;

  OUT_GREEN = 0;

  OUT_BLUE = 0;


/**********************************************************************/
//Ausgänge definieren
/**********************************************************************/  
  
  //PD5 gehört zu timer1, PD7 zu timer2, PB3 gehört zu timer0, PA5-7 für Betriebszustandsleds
  DDRD |= (1 << PD5) | (1 << PD7);
  DDRB |= (1 << PB3);
  DDRC |= (1 << PC0);
  DDRA |= (1 << PA5) | (1 << PA6) | (1 << PA7);

  //verschiebung festlegen
  value_green = value_red + 64;
  value_blue = value_red + 128;


  //Interrupts erlauben
  sei();

  

/**********************************************************************/
//Hauptschleife
/**********************************************************************/

  while(1)
  {

    //wenn PD1 high ist in poti modus wechseln
    if(modus == 0x01)
    {

/**********************************************************************/
//Potimodus
/**********************************************************************/
    
      //ad-wandlung in eine variable schreiben (8bit)
      color_value = ADCH;

      //werte an die timer weitergeben
      OUT_RED = pwm_value[color_value];

      OUT_GREEN = pwm_value[color_value + 64];

      OUT_BLUE = pwm_value[color_value + 128];

    }

    else
    {
    
/**********************************************************************/
//Stehender Modus
/**********************************************************************/
  
      if(stop == 0x01)
        {
        _delay_us(1);
        }

      else
        {

/**********************************************************************/
//Durchlaufmodus
/**********************************************************************/

        //den ausgängen die werte zuweisen
        OUT_RED = pwm_value[value_red];

        OUT_GREEN = pwm_value[value_green];
  
        OUT_BLUE = pwm_value[value_blue];

        //ad-wandlung in speed laden
        speed = ADCH;

        //warten bis das nächste mal die werte zugewiesen werden
        _delay_ms(speed*factor);
  

        //zählvarialben hochzuählen und überprüfen ob sie voll sind, wenn ja auf 0 zurücksetzen
        value_red++;
  
        value_green++;

        value_blue++;

        if(value_red == maximum)
        value_red = 0;

        if(value_green == maximum)
        value_green = 0;

        if(value_blue == maximum)
        value_blue = 0;
        
        }
    }

  }


}


Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
pille1990 schrieb:
> Die Taster sind die auf dem Pollin Zusatzentwicklungsboard (mit
> Kondensator und Widerstand entprellt).

Ach ja, das Pollinboard. Da haben die "Entprellkondensatoren" schon 
vielen Ärger bereitet. Raus damit.


> Die Flanken habe ich mit schon
> mit dem Oszi angeschaut...wunderbar...da prellt nichts.

Einfach mal ne Entprellroutine nehmen. Wenns dann geht, hats wohl doch 
geprellt.


Und nächstes mal die Posting-Regeln lesen.


Peter

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
cli() zu Beginn und sei() am Ende einer Interrupt-Routine sind praktisch 
immer eine schlechte Idee.  Mach' Dir mal klar, was die CPU beim Aufruf 
einer Interrupt-Routine ganz von selber macht und was beim 
abschließenden „reti”.  Und mach' Dir klar, dass durch einen „sei” 
direkt vor dem Ende der Interrupt-Routine der nächste Interrupt noch in 
der Routine triggern kann und das Stack schön runterlaufen lässt.

Eine echte Hardware-Entprellung wäre ein RC-Glied gefolgt von einem 
Schmitt-Trigger (anders ausgedrückt: ein Monoflop), nicht aber ein 
RC-Glied allein.  Das sorgt nämlich für ein schlappe Flanke im 
Übergangsbereich zwischen log. 0 und log. 1 und dort triggert dann jedes 
Rauschen, selbst das Eingangsrauschen des ICs.  Dass die Entprellung 
wirklich nichts taugt, zeigt schon Dein Kommentar:

> //general interrupt flag register bit [...] zurücksetzen, damit
> interrupt nicht gleich wieder startet

Das wäre nämlich überflüssig, wenn's kein Prellen gäbe.

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
Auch hier wieder die Frage: warum um alles in der Welt, 
interuptgesteuerte Kontaktabfrage?
In der Regel sind Programmschleifen schnell genug, das die Kontakte per 
Pollen abgefragt werden können. Es macht keinen sin, eine ISR dafür zu 
benutzen um dann in der ISR möglicherweise durch Warteschleifen das 
Prellen abzuwarten.
Gruß oldmax

Autor: pille1990 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Danke erstmal für die ganzen Antworten.

Das der Interrupt nicht funktioniert liegt nicht an prellenden Tastern, 
sondern dass die Versorgungsspannung beim Drücken der Taster einbricht. 
Das liegt daran, dass die Kondensatoren zum entprellen einen Kurzschluss 
zwischen Vcc und Masse verursachen (Pollin Entwicklungsboard halt).
Dadurch wird der Controller Resetet.
Habe ich alles mit dem Oszi nachgemessen!

Mit cli und sei ist ein guter Tip. Da muss ich mich noch mal schlau 
machen.

Zu dem INTF Flag:
Muss man das am Ende der ISR nicht zurücksetzen???
Da stand mal was im AVR-GCC tutorial drin?!?!

Grüße

Pille

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.