Externe Interrupts am mega32

Gast #1582756
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
1
/**********************************************************************/
2
/************************Ambilight made by PiLLe***********************/
3
/******************************Version 11.0****************************/
4
/**********************************************************************/
5
/*Anschluss:                              */
6
/*OUT_RED:      OCR0 (PB3)                      */
7
/*OUT_GREEN:    OCR1A (PD5)                      */
8
/*OUT_BLUE:      OCR2 (PD7)                      */
9
/*Stopptaster:    PD2 (INT0)                      */
10
/*Modustaster    PD3  (INT1)                      */
11
/*Poti:        PA1                          */
12
/*Stop-LED      PA5                          */  
13
/*Durchlauf-LED:  PA6                          */  
14
/*AD-Wandler-LED:  PA7                          */    
15
/**********************************************************************/
16

17

18
/**********************************************************************/
19
//Includes
20
/**********************************************************************/
21

22
#include <avr/io.h>
23
#include <util/delay.h>
24
#include <avr/interrupt.h>
25

26
/**********************************************************************/
27
//Defines
28
/**********************************************************************/
29

30
#define OUT_RED       OCR0
31
#define OUT_GREEN       OCR1A
32
#define OUT_BLUE       OCR2
33
#define INT0_vect      _VECTOR(1)
34
#define INT1_vect      _VECTOR(2)
35

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

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

42
/**********************************************************************/
43
//Interruptroutinen
44
/**********************************************************************/
45
    
46
//ISR für stoptaster    
47
ISR(INT0_vect)
48
  {
49

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

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

61
    //durchlauf led einschalten
62
    PORTA |= (1 << PA6);
63
    }
64

65
  else
66
    {
67
    stop = 0x01;
68

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

72
    //durchlauf led ausschalten
73
    PORTA &= ~ (1 << PA6);
74
    }
75

76

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

84

85
//ISR für modustaster
86
ISR(INT1_vect)
87
  {
88

89
  //interrupts ausschalten
90
  cli();
91
  
92
  //wenn taster schon gedrückt wurde bit löschen, sonst bit setzen
93
  if(modus == 0x01)
94
    {
95
    modus = 0x00;
96

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

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

103
    //stopptaste wieder aktivieren
104
    GICR |= (1 << INT0);
105
    }
106

107
  else
108
    {
109
    modus = 0x01;
110
    
111
    //ad wandler led einschalten
112
    PORTA |= (1 << PA7);
113

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

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

124
  //interrupts erlaufen
125
  sei();
126
  }
127
  
128
/**********************************************************************/
129
//Hauptprogramm
130
/**********************************************************************/
131
         
132
int main()
133
{
134

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

138
/**********************************************************************/
139
//Variablen
140
/**********************************************************************/
141

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

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

158
  //zählvariablen
159
  uint8_t value_red = 0;
160
  uint8_t value_green = 0;
161
  uint8_t value_blue = 0;
162

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

166
  //geschwindigkeitsvariable
167
  uint16_t speed;
168

169
  //geschwindigkeitsmultiplizierfaktor
170
  uint8_t factor = 3;
171

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

175
/**********************************************************************/
176
//Interruptdefinition
177
/**********************************************************************/
178

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

183

184
  //Interrupt aktivieren
185
  GICR |= (1 << INT0);
186
  GICR |= (1 << INT1);
187

188
/**********************************************************************/
189
//Ad-Wandlerdefinition
190
/**********************************************************************/
191

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

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

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

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

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

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

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

213

214
/**********************************************************************/
215
//Timerdefinition
216
/**********************************************************************/
217

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

221
  TCCR1B |= (1 << CS10);
222
  
223
  TCCR2 |= (1 << CS20);
224

225

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

229
  TCCR1A |= (1 << WGM10);
230
  TCCR1B |= (1 << WGM12);
231

232
  TCCR2 |= (1 << WGM20);
233

234

235
  //invertierte pwm
236
  TCCR0 |= (1 << COM00);
237
  TCCR0 |= (1 << COM01);
238

239
  TCCR1A |= (1 << COM1A0) | (1 << COM1A1);  
240
  TCCR1A |= (1 << COM1B0) | (1 << COM1B1);
241
  
242
  TCCR2 |= (1 << COM20);
243
  TCCR2 |= (1 << COM21);
244

245

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

249
  OUT_GREEN = 0;
250

251
  OUT_BLUE = 0;
252

253

254
/**********************************************************************/
255
//Ausgänge definieren
256
/**********************************************************************/  
257
  
258
  //PD5 gehört zu timer1, PD7 zu timer2, PB3 gehört zu timer0, PA5-7 für Betriebszustandsleds
259
  DDRD |= (1 << PD5) | (1 << PD7);
260
  DDRB |= (1 << PB3);
261
  DDRC |= (1 << PC0);
262
  DDRA |= (1 << PA5) | (1 << PA6) | (1 << PA7);
263

264
  //verschiebung festlegen
265
  value_green = value_red + 64;
266
  value_blue = value_red + 128;
267

268

269
  //Interrupts erlauben
270
  sei();
271

272
  
273

274
/**********************************************************************/
275
//Hauptschleife
276
/**********************************************************************/
277

278
  while(1)
279
  {
280

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

285
/**********************************************************************/
286
//Potimodus
287
/**********************************************************************/
288
    
289
      //ad-wandlung in eine variable schreiben (8bit)
290
      color_value = ADCH;
291

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

295
      OUT_GREEN = pwm_value[color_value + 64];
296

297
      OUT_BLUE = pwm_value[color_value + 128];
298

299
    }
300

301
    else
302
    {
303
    
304
/**********************************************************************/
305
//Stehender Modus
306
/**********************************************************************/
307
  
308
      if(stop == 0x01)
309
        {
310
        _delay_us(1);
311
        }
312

313
      else
314
        {
315

316
/**********************************************************************/
317
//Durchlaufmodus
318
/**********************************************************************/
319

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

323
        OUT_GREEN = pwm_value[value_green];
324
  
325
        OUT_BLUE = pwm_value[value_blue];
326

327
        //ad-wandlung in speed laden
328
        speed = ADCH;
329

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

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

339
        value_blue++;
340

341
        if(value_red == maximum)
342
        value_red = 0;
343

344
        if(value_green == maximum)
345
        value_green = 0;
346

347
        if(value_blue == maximum)
348
        value_blue = 0;
349
        
350
        }
351
    }
352

353
  }
354

355

356
}
#1582877
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
#1582910
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.
Gast #1583037
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
Gast #1583880
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren