Forum: Mikrocontroller und Digitale Elektronik Interrrupt Fehler


von Manuel S. (doc-snyder)


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
1
#define F_CPU 8000000UL
2
#define PWM_RES 255 // Bei Änderung Programmverlauf beachten wegen Datentyp
3
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
#include <stdbool.h>
8
9
10
//ISR Variablen
11
volatile uint8_t pwm_cnt=0;
12
volatile uint16_t next_pwm_cnt=0;
13
volatile bool pwm_update = true;
14
volatile uint8_t program=0;
15
volatile bool prog_init = true;
16
17
18
//Sonstige Variablen
19
uint8_t pwm_setting[5][3];
20
uint16_t prog_delay = 2000;
21
uint16_t prog_cnt=0;
22
uint8_t fade;
23
uint8_t oxx=0;  
24
uint8_t up;
25
uint8_t down;
26
27
void runProgStep();
28
void pwmUpdate();
29
void initializeProgramm();
30
31
void allesWeiss();
32
void allesRot();
33
void allesBlau();
34
void allesGruen();
35
void allesLila();
36
void allesGelb();
37
void allesOrange();
38
void allesTuerkis();
39
void durchlauf();

main.c:
1
#include "main.h"
2
3
//--------------------------InterruptServiceRoutines-----------------------------------//
4
ISR(TIMER2_COMP_vect)
5
{
6
  if(pwm_cnt == next_pwm_cnt)    //Leds aktualidsieren wenn so weit
7
    pwm_update = true;
8
  pwm_cnt++;      
9
}
10
11
ISR(TIMER1_COMPA_vect) {
12
  TCCR1B = 0;        // Entprelltimer ausschalten
13
  GIFR &= ~(1<<INTF0);  // InterruptrequestFlag löschen
14
  GICR |= (1<<INT0);    // Extinterrupt (Taster) aktivieren
15
}
16
17
18
19
ISR(INT0_vect)
20
{
21
  program++;       //Programm wechseln
22
  if (program>8)
23
    program=0;
24
  prog_init=true;    // Programm initialisieren
25
  
26
27
    TCCR1B=(1<<WGM12)|(1<<CS12)|(1<<CS10);  // EntprellungsTimer AN  clkI/O/1024 (From prescaler) +CTC
28
    OCR1A=760;                // Entprellzeit ca 0.1s
29
    GICR &= ~(1 << INT0);          // Extinterrupt (Taster) deaktivieren
30
}
31
} 
32
33
//--------------------------Externe Funktionen-----------------------------------//
34
void pwmUpdate(){
35
36
  uint8_t tmpB =0xff;
37
  uint8_t tmpC =0xff;
38
  uint8_t tmpD =0xff;
39
40
  //RED
41
    if (pwm_setting[0][0] <= pwm_cnt) tmpC &= ~(1 << 2);
42
    if (pwm_setting[1][0] <= pwm_cnt) tmpD &= ~(1 << 0);
43
    if (pwm_setting[2][0] <= pwm_cnt) tmpD &= ~(1 << 3);
44
    if (pwm_setting[3][0] <= pwm_cnt) tmpB &= ~(1 << 7);
45
    if (pwm_setting[4][0] <= pwm_cnt) tmpD &= ~(1 << 7);
46
  //GREEN
47
    if (pwm_setting[0][1] <= pwm_cnt) tmpC &= ~(1 << 3);
48
    if (pwm_setting[1][1] <= pwm_cnt) tmpC &= ~(1 << 0);
49
    if (pwm_setting[2][1] <= pwm_cnt) tmpD &= ~(1 << 1);
50
    if (pwm_setting[3][1] <= pwm_cnt) tmpB &= ~(1 << 6);
51
    if (pwm_setting[4][1] <= pwm_cnt) tmpD &= ~(1 << 6);
52
  //BLUE
53
    if (pwm_setting[0][2] <= pwm_cnt) tmpC &= ~(1 << 4);
54
    if (pwm_setting[1][2] <= pwm_cnt) tmpC &= ~(1 << 1);
55
    if (pwm_setting[2][2] <= pwm_cnt) tmpC &= ~(1 << 5);
56
    if (pwm_setting[3][2] <= pwm_cnt) tmpD &= ~(1 << 4);
57
    if (pwm_setting[4][2] <= pwm_cnt) tmpD &= ~(1 << 5);
58
59
  PORTB = tmpB;
60
  PORTC = tmpC;
61
  PORTD = tmpD;
62
63
  //Berechne nächsten PWM-Ämderungszeitpunkt
64
  next_pwm_cnt = (PWM_RES*2);  
65
  for(int i=0; i<5; i++){
66
    for(int k=0; k<3; k++){
67
      if((pwm_setting[i][k] > pwm_cnt) && (pwm_setting[i][k] < next_pwm_cnt))
68
        next_pwm_cnt = pwm_setting[i][k];
69
    }
70
  }
71
  if(next_pwm_cnt == (PWM_RES*2))
72
    next_pwm_cnt=0;
73
}
74
75
76
int main (){
77
78
  // Ports als Ausgang setzen
79
  DDRB = (1 << DDB6) | (1 << DDB7);
80
  DDRC = (1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3) | (1 << DDC4) | (1 << DDC5);
81
  DDRD = (1 << DDD0) | (1 << DDD1) | (0 << DDD2) | (1 << DDD3) | (1 << DDD4) | (1 << DDD5) | (1 << DDD6) | (1 << DDD7);
82
  
83
  
84
  //FREQUENZGENERATOR
85
    TCCR2 = (1 << CS20)|(1 << WGM21);  //Enable Timer2 (Prescale 1) and CTC mode !! NOETIG FUER SOFT-PWM
86
  OCR2=255;              // Output Compare Register - OCR2  AKA PWMFREQUENZ
87
88
  // OCIE2: Timer/Counter2 Output Compare Match Interrupt Enable | Tim0 Overflow Enable |OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
89
  TIMSK |= (1<<OCIE2) | (1 << TOIE0) | (1 << OCIE1A);
90
91
  //TASTER
92
  MCUCR |= (1<<ISC01);    //MCU Control Register MCUCR
93
  GICR |= (1<<INT0);      //General Interrupt Control Register – GICR
94
  PORTD|=(1<<PB2);      //PullUp fuer Ext Interrupt
95
96
    sei();            // Interrupt freischalten
97
98
  while(1){
99
    //Wenn an der Zeit führe Nächsten Programmschritt aus
100
    if(prog_cnt==prog_delay){      
101
      runProgStep(program);
102
      prog_cnt=0;
103
      }
104
    //Führe Init aus wenn nötig
105
    if(prog_init==true){
106
      initializeProgramm(program);
107
      }
108
    // Führe PWMUpdate aus
109
        if(pwm_update == true){ 
110
      pwmUpdate();
111
      pwm_update = false;
112
      }
113
    prog_cnt++;
114
  }
115
  return 0;
116
}
117
118
//----------------------------Programmwahl-----------------------------------------------//
119
void runProgStep(int k){
120
  switch(k){
121
    case 0:  allesWeiss();
122
        break;
123
    case 1:  allesRot();
124
        break;
125
    case 2:  allesGruen();
126
        break;
127
    case 3:  allesBlau();
128
        break;
129
    case 4:  allesLila();
130
        break;
131
    case 5:  allesGelb();
132
        break;
133
    case 6:  allesTuerkis();
134
        break;
135
    case 7:  allesOrange();
136
        break;
137
    case 8: durchlauf();
138
        break;
139
    }
140
  }
141
void initializeProgramm(int k){
142
143
  switch(k){
144
    case 8:  allesRot();
145
        fade=1;
146
        up=1;
147
        down=0;        
148
        break;
149
    //default: 
150
    }
151
  }
152
153
//----------------------------Funktionen------------------------------------------
154
void allesWeiss(){
155
  for(int i=0; i <5; i++) {
156
    pwm_setting[i][0] = PWM_RES;
157
    pwm_setting[i][1] = PWM_RES;
158
    pwm_setting[i][2] = PWM_RES;
159
  }
160
}
161
void allesRot(){
162
  for(int i=0; i <5; i++) {
163
    pwm_setting[i][0] = PWM_RES;
164
    pwm_setting[i][1] = 0;
165
    pwm_setting[i][2] = 0;
166
  }
167
}
168
void allesBlau(){
169
  for(int i=0; i <5; i++) {
170
    pwm_setting[i][0] = 0;
171
    pwm_setting[i][1] = 0;
172
    pwm_setting[i][2] = PWM_RES;
173
  }
174
}
175
void allesGruen(){
176
  for(int i=0; i <5; i++) {
177
    pwm_setting[i][0] = 0;
178
    pwm_setting[i][1] = PWM_RES;
179
    pwm_setting[i][2] = 0;
180
  }
181
}
182
void allesAus(){
183
  for(int i=0; i <5; i++) {
184
    pwm_setting[i][0] = 0;
185
    pwm_setting[i][1] = 0;
186
    pwm_setting[i][2] = 0;
187
  }
188
}
189
void allesLila(){
190
  for(int i=0; i <5; i++) {
191
    pwm_setting[i][0] = PWM_RES;
192
    pwm_setting[i][1] = 0;
193
    pwm_setting[i][2] = PWM_RES;
194
  }
195
}
196
void allesGelb(){
197
  for(int i=0; i <5; i++) {
198
    pwm_setting[i][0] = PWM_RES;
199
    pwm_setting[i][1] = PWM_RES;
200
    pwm_setting[i][2] = 0;
201
  }
202
}
203
void allesTuerkis(){
204
  for(int i=0; i <5; i++) {
205
    pwm_setting[i][0] = 0;
206
    pwm_setting[i][1] = PWM_RES;
207
    pwm_setting[i][2] = PWM_RES;
208
  }
209
}
210
void allesOrange(){
211
  for(int i=0; i <5; i++) {
212
    pwm_setting[i][0] = PWM_RES;
213
    pwm_setting[i][1] = 70;
214
    pwm_setting[i][2] = 0;
215
  }
216
}
217
void durchlauf(){
218
  for(int i=0; i <5; i++) {
219
    if(fade==1){
220
      pwm_setting[i][up]++;
221
      if(pwm_setting[i][up]==PWM_RES){
222
        up+=1;
223
        fade=2;
224
        }
225
      }
226
    else{
227
      pwm_setting[i][down]--;
228
      if(pwm_setting[i][down]==0){
229
        down+=1;
230
        fade=1;
231
        }
232
      }
233
    }
234
  if(up>2) up=0;
235
  if(down>2) down=0;
236
}

von Karl H. (kbuchegg)


Lesenswert?

Deine Entprellung ist wirkungslos.

Hier
Entprellung
findest du ein paar erprobte Funktionen.

von Stefan E. (sternst)


Lesenswert?

Und sie ist in dieser Form deswegen wirkungslos, weil diese Zeile
1
  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.

von holger (Gast)


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;)

von Karl H. (kbuchegg)


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.

von Manuel S. (doc-snyder)


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!

von Peter (Gast)


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

von Stefan E. (sternst)


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".

von Spess53 (Gast)


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

von Karl H. (kbuchegg)


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.

von Peter (Gast)


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......

von Manuel S. (doc-snyder)


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.

von Karl H. (kbuchegg)


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
1
8000000 / 1 / 256 = 31250 Hz ISR Frequenz
2
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
1
ISR( ... )
2
{
3
  uint8_t tmpB =0xff;
4
  uint8_t tmpC =0xff;
5
  uint8_t tmpD =0xff;
6
7
  //RED
8
    if (pwm_setting[0][0] <= pwm_cnt) tmpC &= ~(1 << 2);
9
    if (pwm_setting[1][0] <= pwm_cnt) tmpD &= ~(1 << 0);
10
    if (pwm_setting[2][0] <= pwm_cnt) tmpD &= ~(1 << 3);
11
    if (pwm_setting[3][0] <= pwm_cnt) tmpB &= ~(1 << 7);
12
    if (pwm_setting[4][0] <= pwm_cnt) tmpD &= ~(1 << 7);
13
  //GREEN
14
    if (pwm_setting[0][1] <= pwm_cnt) tmpC &= ~(1 << 3);
15
    if (pwm_setting[1][1] <= pwm_cnt) tmpC &= ~(1 << 0);
16
    if (pwm_setting[2][1] <= pwm_cnt) tmpD &= ~(1 << 1);
17
    if (pwm_setting[3][1] <= pwm_cnt) tmpB &= ~(1 << 6);
18
    if (pwm_setting[4][1] <= pwm_cnt) tmpD &= ~(1 << 6);
19
  //BLUE
20
    if (pwm_setting[0][2] <= pwm_cnt) tmpC &= ~(1 << 4);
21
    if (pwm_setting[1][2] <= pwm_cnt) tmpC &= ~(1 << 1);
22
    if (pwm_setting[2][2] <= pwm_cnt) tmpC &= ~(1 << 5);
23
    if (pwm_setting[3][2] <= pwm_cnt) tmpD &= ~(1 << 4);
24
    if (pwm_setting[4][2] <= pwm_cnt) tmpD &= ~(1 << 5);
25
26
  PORTB = tmpB;
27
  PORTC = tmpC;
28
  PORTD = tmpD;
29
}

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.

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.