www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interrrupt Fehler


Autor: Manuel Schneider (doc-snyder)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich habe ein kleines Programm für meine eigens erstellte Ledleiste, 
bestehend aus 5 RGB Leds, geschrieben. Jetz hab ich ein Problem und 
komme trotz stundenlanger Fehlersuche auf keinen grünen Zweig.

Mein Problem:
Wenn ich den Taster drücke, dann wechselt, wie gewollt, die 
Farbe/Programm. Allerdings wechselt nach der gewählten Zeit (0,1sek) ab 
un zu noch einmal das Programm und ich verstehe einfach nicht warum.

Ich wäre euch sehr dankbar wenn ihr mal den Fehler für mich finden 
könntet.

Grüße Manuel

main.h
#define F_CPU 8000000UL
#define PWM_RES 255 // Bei Änderung Programmverlauf beachten wegen Datentyp

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


//ISR Variablen
volatile uint8_t pwm_cnt=0;
volatile uint16_t next_pwm_cnt=0;
volatile bool pwm_update = true;
volatile uint8_t program=0;
volatile bool prog_init = true;


//Sonstige Variablen
uint8_t pwm_setting[5][3];
uint16_t prog_delay = 2000;
uint16_t prog_cnt=0;
uint8_t fade;
uint8_t oxx=0;  
uint8_t up;
uint8_t down;

void runProgStep();
void pwmUpdate();
void initializeProgramm();

void allesWeiss();
void allesRot();
void allesBlau();
void allesGruen();
void allesLila();
void allesGelb();
void allesOrange();
void allesTuerkis();
void durchlauf();

main.c:
#include "main.h"

//--------------------------InterruptServiceRoutines-----------------------------------//
ISR(TIMER2_COMP_vect)
{
  if(pwm_cnt == next_pwm_cnt)    //Leds aktualidsieren wenn so weit
    pwm_update = true;
  pwm_cnt++;      
}

ISR(TIMER1_COMPA_vect) {
  TCCR1B = 0;        // Entprelltimer ausschalten
  GIFR &= ~(1<<INTF0);  // InterruptrequestFlag löschen
  GICR |= (1<<INT0);    // Extinterrupt (Taster) aktivieren
}



ISR(INT0_vect)
{
  program++;       //Programm wechseln
  if (program>8)
    program=0;
  prog_init=true;    // Programm initialisieren
  

    TCCR1B=(1<<WGM12)|(1<<CS12)|(1<<CS10);  // EntprellungsTimer AN  clkI/O/1024 (From prescaler) +CTC
    OCR1A=760;                // Entprellzeit ca 0.1s
    GICR &= ~(1 << INT0);          // Extinterrupt (Taster) deaktivieren
}
} 

//--------------------------Externe Funktionen-----------------------------------//
void pwmUpdate(){

  uint8_t tmpB =0xff;
  uint8_t tmpC =0xff;
  uint8_t tmpD =0xff;

  //RED
    if (pwm_setting[0][0] <= pwm_cnt) tmpC &= ~(1 << 2);
    if (pwm_setting[1][0] <= pwm_cnt) tmpD &= ~(1 << 0);
    if (pwm_setting[2][0] <= pwm_cnt) tmpD &= ~(1 << 3);
    if (pwm_setting[3][0] <= pwm_cnt) tmpB &= ~(1 << 7);
    if (pwm_setting[4][0] <= pwm_cnt) tmpD &= ~(1 << 7);
  //GREEN
    if (pwm_setting[0][1] <= pwm_cnt) tmpC &= ~(1 << 3);
    if (pwm_setting[1][1] <= pwm_cnt) tmpC &= ~(1 << 0);
    if (pwm_setting[2][1] <= pwm_cnt) tmpD &= ~(1 << 1);
    if (pwm_setting[3][1] <= pwm_cnt) tmpB &= ~(1 << 6);
    if (pwm_setting[4][1] <= pwm_cnt) tmpD &= ~(1 << 6);
  //BLUE
    if (pwm_setting[0][2] <= pwm_cnt) tmpC &= ~(1 << 4);
    if (pwm_setting[1][2] <= pwm_cnt) tmpC &= ~(1 << 1);
    if (pwm_setting[2][2] <= pwm_cnt) tmpC &= ~(1 << 5);
    if (pwm_setting[3][2] <= pwm_cnt) tmpD &= ~(1 << 4);
    if (pwm_setting[4][2] <= pwm_cnt) tmpD &= ~(1 << 5);

  PORTB = tmpB;
  PORTC = tmpC;
  PORTD = tmpD;

  //Berechne nächsten PWM-Ämderungszeitpunkt
  next_pwm_cnt = (PWM_RES*2);  
  for(int i=0; i<5; i++){
    for(int k=0; k<3; k++){
      if((pwm_setting[i][k] > pwm_cnt) && (pwm_setting[i][k] < next_pwm_cnt))
        next_pwm_cnt = pwm_setting[i][k];
    }
  }
  if(next_pwm_cnt == (PWM_RES*2))
    next_pwm_cnt=0;
}


int main (){

  // Ports als Ausgang setzen
  DDRB = (1 << DDB6) | (1 << DDB7);
  DDRC = (1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3) | (1 << DDC4) | (1 << DDC5);
  DDRD = (1 << DDD0) | (1 << DDD1) | (0 << DDD2) | (1 << DDD3) | (1 << DDD4) | (1 << DDD5) | (1 << DDD6) | (1 << DDD7);
  
  
  //FREQUENZGENERATOR
    TCCR2 = (1 << CS20)|(1 << WGM21);  //Enable Timer2 (Prescale 1) and CTC mode !! NOETIG FUER SOFT-PWM
  OCR2=255;              // Output Compare Register - OCR2  AKA PWMFREQUENZ

  // OCIE2: Timer/Counter2 Output Compare Match Interrupt Enable | Tim0 Overflow Enable |OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
  TIMSK |= (1<<OCIE2) | (1 << TOIE0) | (1 << OCIE1A);

  //TASTER
  MCUCR |= (1<<ISC01);    //MCU Control Register MCUCR
  GICR |= (1<<INT0);      //General Interrupt Control Register – GICR
  PORTD|=(1<<PB2);      //PullUp fuer Ext Interrupt

    sei();            // Interrupt freischalten

  while(1){
    //Wenn an der Zeit führe Nächsten Programmschritt aus
    if(prog_cnt==prog_delay){      
      runProgStep(program);
      prog_cnt=0;
      }
    //Führe Init aus wenn nötig
    if(prog_init==true){
      initializeProgramm(program);
      }
    // Führe PWMUpdate aus
        if(pwm_update == true){ 
      pwmUpdate();
      pwm_update = false;
      }
    prog_cnt++;
  }
  return 0;
}

//----------------------------Programmwahl-----------------------------------------------//
void runProgStep(int k){
  switch(k){
    case 0:  allesWeiss();
        break;
    case 1:  allesRot();
        break;
    case 2:  allesGruen();
        break;
    case 3:  allesBlau();
        break;
    case 4:  allesLila();
        break;
    case 5:  allesGelb();
        break;
    case 6:  allesTuerkis();
        break;
    case 7:  allesOrange();
        break;
    case 8: durchlauf();
        break;
    }
  }
void initializeProgramm(int k){

  switch(k){
    case 8:  allesRot();
        fade=1;
        up=1;
        down=0;        
        break;
    //default: 
    }
  }

//----------------------------Funktionen------------------------------------------
void allesWeiss(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = PWM_RES;
    pwm_setting[i][1] = PWM_RES;
    pwm_setting[i][2] = PWM_RES;
  }
}
void allesRot(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = PWM_RES;
    pwm_setting[i][1] = 0;
    pwm_setting[i][2] = 0;
  }
}
void allesBlau(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = 0;
    pwm_setting[i][1] = 0;
    pwm_setting[i][2] = PWM_RES;
  }
}
void allesGruen(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = 0;
    pwm_setting[i][1] = PWM_RES;
    pwm_setting[i][2] = 0;
  }
}
void allesAus(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = 0;
    pwm_setting[i][1] = 0;
    pwm_setting[i][2] = 0;
  }
}
void allesLila(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = PWM_RES;
    pwm_setting[i][1] = 0;
    pwm_setting[i][2] = PWM_RES;
  }
}
void allesGelb(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = PWM_RES;
    pwm_setting[i][1] = PWM_RES;
    pwm_setting[i][2] = 0;
  }
}
void allesTuerkis(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = 0;
    pwm_setting[i][1] = PWM_RES;
    pwm_setting[i][2] = PWM_RES;
  }
}
void allesOrange(){
  for(int i=0; i <5; i++) {
    pwm_setting[i][0] = PWM_RES;
    pwm_setting[i][1] = 70;
    pwm_setting[i][2] = 0;
  }
}
void durchlauf(){
  for(int i=0; i <5; i++) {
    if(fade==1){
      pwm_setting[i][up]++;
      if(pwm_setting[i][up]==PWM_RES){
        up+=1;
        fade=2;
        }
      }
    else{
      pwm_setting[i][down]--;
      if(pwm_setting[i][down]==0){
        down+=1;
        fade=1;
        }
      }
    }
  if(up>2) up=0;
  if(down>2) down=0;
}





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

Bewertung
0 lesenswert
nicht lesenswert
Deine Entprellung ist wirkungslos.

Hier
Entprellung
findest du ein paar erprobte Funktionen.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und sie ist in dieser Form deswegen wirkungslos, weil diese Zeile
  GIFR &= ~(1<<INTF0);  // InterruptrequestFlag löschen
falsch ist. Damit werden alle Flags in GIFR gelöscht, außer INTF0. Am 
besten schaust du nochmal in das Datenblatt, wie man Interrupt-Flags 
löscht.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>volatile uint8_t pwm_cnt=0;
>volatile uint16_t next_pwm_cnt=0;

>  if(pwm_cnt == next_pwm_cnt)    //Leds aktualidsieren wenn so weit

Ach nö:( 8 Bit und 16 Bit vergleichen nur wenn man
weiss was man tut;)

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

Bewertung
0 lesenswert
nicht lesenswert
Das ganze Programm ist irgendwie verkehrt herum.

Dinge die in einer ISR sein sollten (PWM) sind es nicht. Dinge die 
besser nicht mit einem Interrupt gemacht werden (Tastenabfrage) sind es 
schon.

Autor: Manuel Schneider (doc-snyder)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Deine Entprellung ist wirkungslos.
> Hier
> Entprellung
> findest du ein paar erprobte Funktionen.

Naja also ich hab mir sagen lassen (Elektotechnikingenieur), dass die 
Amplituden einer Prellung nur ca 50ms V_High bzw V_Low überschreiten.
Wieso sollte es nicht funtkionieren.

>Und sie ist in dieser Form deswegen wirkungslos, weil diese Zeile
>  GIFR &= ~(1<<0);  // InterruptrequestFlag löschen
>falsch ist. Damit werden alle Flags in GIFR gelöscht, außer INTF0. Am
>besten schaust du nochmal in das Datenblatt, wie man Interrupt-Flags
>löscht.

(1<<0)               //                0b00000001
~(1<<0)              //Komplement also 0b11111110
0b11111111 & ~(1<<0) //Konjugiert      0b11111110

Genau das was ich erreichen will. Bit 0 ist 0
Sag mir wenn da was falsch ist.

>Ach nö:( 8 Bit und 16 Bit vergleichen nur wenn man
>weiss was man tut;)

Vergleicht denke ich mal nur die unteren 8 Bit wenn du mich schon so 
fragst oder?^^

>Das ganze Programm ist irgendwie verkehrt herum.
>Dinge die in einer ISR sein sollten (PWM) sind es nicht. Dinge die
>besser nicht mit einem Interrupt gemacht werden (Tastenabfrage) sind es
>schon.

SoftPwm ist für den Interrupt zu langsam. Zumindest war es das am Anfang 
meiner Implementierung.
Tastenabfrage soll 100% reagieren wenn geklickt. Deswegen der Interrupt.

Danke für die schnellen Antworten!

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So Pi * Daumen + 2 würd ich alles nochmal neu machen und das PWM über 
eine modulare Gerätesteuerung implementieren..

schau mal bei www.mocontronic.de vorbei dort könntest du was zu dem 
Thema finden...

Die Tasterabfrage könntest du über einen Attiny13 machen und die 
Fusebits per SPI an deinen Haupt µC senden, das würde dir mehr Leistung 
im ganzen System bringen und deine LED Leiste wäre um einiges schöner 
Dimbar.

Viel Glück noch

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel Schneider schrieb:
>>Und sie ist in dieser Form deswegen wirkungslos, weil diese Zeile
>>  GIFR &= ~(1<<0);  // InterruptrequestFlag löschen
>>falsch ist. Damit werden alle Flags in GIFR gelöscht, außer INTF0. Am
>>besten schaust du nochmal in das Datenblatt, wie man Interrupt-Flags
>>löscht.
>
> (1<<0)               //                0b00000001
> ~(1<<0)              //Komplement also 0b11111110
> 0b11111111 & ~(1<<0) //Konjugiert      0b11111110
>
> Genau das was ich erreichen will. Bit 0 ist 0
> Sag mir wenn da was falsch ist.

Das ist schon richtig so, aber trotzdem kannst du damit das 
Interrupt-Flag nicht löschen. Wenn ich sage "schau ins Datenblatt", dann 
bedeutet das, dass es bei den Interrupt-Flags eine Besonderheit gibt. 
Wenn einfach nur deine Bit-Arithmetik falsch gewesen wäre, hätte ich 
vielleicht gesagt "schau in dein C-Buch".

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Genau das was ich erreichen will. Bit 0 ist 0
>Sag mir wenn da was falsch ist.

Die Flags werden durch Schreiben einer 1 gelöscht.

MfG Spess

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

Bewertung
0 lesenswert
nicht lesenswert
Manuel Schneider schrieb:

> SoftPwm ist für den Interrupt zu langsam.

?
Ein 'was auch immer' mit 8 Mhz soll es nicht schaffen, 15 Stück 8_Bit 
PWM Kanäle anzusteuern?
Du beliebst zu scherzen.

> Tastenabfrage soll 100% reagieren wenn geklickt.
Das tut sie auch. Ganz ohne Interrupt.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> So Pi * Daumen + 2 würd ich alles nochmal neu machen und das PWM über
> eine modulare Gerätesteuerung implementieren..
>
> schau mal bei www.mocontronic.de vorbei dort könntest du was zu dem
> Thema finden...
>
> Die Tasterabfrage könntest du über einen Attiny13 machen und die
> Fusebits per SPI an deinen Haupt µC senden, das würde dir mehr Leistung
> im ganzen System bringen und deine LED Leiste wäre um einiges schöner
> Dimbar.
>
> Viel Glück noch



nimm dir das mal zu herzen......

Autor: Manuel Schneider (doc-snyder)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spess53 schrieb:
> Hi
>
>>Genau das was ich erreichen will. Bit 0 ist 0
>>Sag mir wenn da was falsch ist.
>
> Die Flags werden durch Schreiben einer 1 gelöscht.


When an event on the INT0 pin triggers an interrupt request, INTF0 
becomes set (one). If the I-bit in SREG and the INT0 bit in GICR are set 
(one), the MCU will jump to the corresponding Interrupt Vector. The flag 
is cleared when the interrupt routine is executed. Alternatively, the 
flag can be cleared by writing a logical one to it. This flag is always 
cleared when INT0 is configured as a level interrupt.

Okay ich glaubs dir jetzt. Aber ich finde da sollte im Datasheet extra 
druaf hingewiesen werden.
"...interrupt request, INTF0 becomes set (one)" verwirrt etwas. Nach 
"Alternatively, the flag can be cleared by writing a logical one to it." 
ist dann Sense.

>Du beliebst zu scherzen.

Naja habs versucht. Der Atmega8 ist zu langsam. Die Leds flackerten 
zumindest damals noch als pwmUpdate() jeden pwm_cnt Takt aufgerufen 
wurden.


@Peter: Is mein erster µC-Code. Also lass mal^^


-----


Also ich vermute jetz einfach mal, dass es am dem Missverständnis mit 
dem IRQFlag lag. Aber ich kanns im Moment leider nicht testen. Danke 
euch allen für die Hilfe. Ich werde mich wieder melden.

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

Bewertung
0 lesenswert
nicht lesenswert
Manuel Schneider schrieb:

> Okay ich glaubs dir jetzt. Aber ich finde da sollte im Datasheet extra
> druaf hingewiesen werden.

> "...interrupt request, INTF0 becomes set (one)" verwirrt etwas. Nach
> "Alternatively, the flag can be cleared by writing a logical one to it."
> ist dann Sense.

Da stehst doch :-)

OK, keine Bange. Da fällt jeder beim ersten mal darauf herein.

> Naja habs versucht. Der Atmega8 ist zu langsam. Die Leds flackerten
> zumindest damals noch als pwmUpdate() jeden pwm_cnt Takt aufgerufen
> wurden.

Mit einem Prescaler von 1
8000000 / 1 / 256 = 31250 Hz ISR Frequenz
macht bei 8 Bit PWM: 31250 / 256 = 120Hz PWM-Frequenz
Auch wenn es Leute gibt, die das noch flackern sehen: 99% aller Menschen 
sehen da nichts mehr flackern.
Und 256 Takte reichen allemal für
ISR( ... )
{
  uint8_t tmpB =0xff;
  uint8_t tmpC =0xff;
  uint8_t tmpD =0xff;

  //RED
    if (pwm_setting[0][0] <= pwm_cnt) tmpC &= ~(1 << 2);
    if (pwm_setting[1][0] <= pwm_cnt) tmpD &= ~(1 << 0);
    if (pwm_setting[2][0] <= pwm_cnt) tmpD &= ~(1 << 3);
    if (pwm_setting[3][0] <= pwm_cnt) tmpB &= ~(1 << 7);
    if (pwm_setting[4][0] <= pwm_cnt) tmpD &= ~(1 << 7);
  //GREEN
    if (pwm_setting[0][1] <= pwm_cnt) tmpC &= ~(1 << 3);
    if (pwm_setting[1][1] <= pwm_cnt) tmpC &= ~(1 << 0);
    if (pwm_setting[2][1] <= pwm_cnt) tmpD &= ~(1 << 1);
    if (pwm_setting[3][1] <= pwm_cnt) tmpB &= ~(1 << 6);
    if (pwm_setting[4][1] <= pwm_cnt) tmpD &= ~(1 << 6);
  //BLUE
    if (pwm_setting[0][2] <= pwm_cnt) tmpC &= ~(1 << 4);
    if (pwm_setting[1][2] <= pwm_cnt) tmpC &= ~(1 << 1);
    if (pwm_setting[2][2] <= pwm_cnt) tmpC &= ~(1 << 5);
    if (pwm_setting[3][2] <= pwm_cnt) tmpD &= ~(1 << 4);
    if (pwm_setting[4][2] <= pwm_cnt) tmpD &= ~(1 << 5);

  PORTB = tmpB;
  PORTC = tmpC;
  PORTD = tmpD;
}

Da bleibt noch genug Zeit für anderes übrig, wie zb die Fading Steuernug 
oder Programm weiterschaltung. Ganz besonders dann, wenn man die Array 
Indizierung innerhalb der ISR so macht, dass der letzte Index am 
schnellsten abgearbeitet wird. Dann hat der AVR am wenigsten Arbeit mit 
den Arrayzugriffen.

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.