Forum: Mikrocontroller und Digitale Elektronik Externe Interrupts am mega32


von pille1990 (Gast)


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
}

von Peter D. (peda)


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

von Hc Z. (mizch)


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.

von oldmax (Gast)


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

von pille1990 (Gast)


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

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.