PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interrupt löst nicht zuverlässig aus



Kagerer
13.05.2008, 09:27
Hallo,
ich hab ein Problem mit dem Interrupt an einem ATMega16. Und zwar hab ich einen Taster an Int0 angeschlossen. Der Controller löst aber nicht zuverlässig die Interrupt-Routine aus, wenn ich den Taster betätige.
Hier mal der Code:


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

// Ports initialisieren
void port_init()
{
// Alle Pins bis auf PD2 & PD3 als Ausgang schalten
DDRA = 0xff;
DDRB = 0xff;
DDRC = 0xff;
DDRD = 0b11110011;

//Pullup-Widerstand von PD2 aktivieren
PORTD |= (1<<PD2);

// Interrupt vorbereiten
MCUCR |= (1 << ISC01); // INT0 läst bei fallender Flanke aus
GICR |= (1 << INT0); // INT0 aktivieren
}

// Funktion zum Einschalten der LEDs
void led_on(uint8_t led)
{
if(led == 1) PORTA |= (1 << PA3);
if(led == 2) PORTB |= (1 << PB4);
if(led == 3) PORTA |= (1 << PA2);
if(led == 4) PORTD |= (1 << PD0);
if(led == 5) PORTC |= (1 << PC5);
if(led == 6) PORTB |= (1 << PB7);
if(led == 7) PORTC |= (1 << PC6);
if(led == 8) PORTB |= (1 << PB6);
if(led == 9) PORTC |= (1 << PC7);
if(led == 10) PORTB |= (1 << PB5);
if(led == 11) PORTA |= (1 << PA5);
if(led == 12) PORTA |= (1 << PA4);
if(led == 13) PORTB |= (1 << PB3);
if(led == 14) PORTA |= (1 << PA1);
if(led == 15) PORTB |= (1 << PB2);
if(led == 16) PORTA |= (1 << PA7);
if(led == 17) PORTB |= (1 << PB1);
if(led == 18) PORTA |= (1 << PA6);
if(led == 19) PORTB |= (1 << PB0);
if(led == 20) PORTA |= (1 << PA0);
if(led == 21) PORTD |= (1 << PD6);
if(led == 22) PORTC |= (1 << PC0);
if(led == 23) PORTD |= (1 << PD7);
if(led == 24) PORTC |= (1 << PC4);
if(led == 25) PORTD |= (1 << PD1);
if(led == 26) PORTC |= (1 << PC3);
if(led == 27) PORTD |= (1 << PD4);
if(led == 28) PORTC |= (1 << PC2);
if(led == 29) PORTD |= (1 << PD5);
if(led == 30) PORTC |= (1 << PC1);
}

// Funktion zum Ausschalten der LEDs
void led_off(uint8_t led)
{
if(led == 1) PORTA &= ~(1 << PA3);
if(led == 2) PORTB &= ~(1 << PB4);
if(led == 3) PORTA &= ~(1 << PA2);
if(led == 4) PORTD &= ~(1 << PD0);
if(led == 5) PORTC &= ~(1 << PC5);
if(led == 6) PORTB &= ~(1 << PB7);
if(led == 7) PORTC &= ~(1 << PC6);
if(led == 8) PORTB &= ~(1 << PB6);
if(led == 9) PORTC &= ~(1 << PC7);
if(led == 10) PORTB &= ~(1 << PB5);
if(led == 11) PORTA &= ~(1 << PA5);
if(led == 12) PORTA &= ~(1 << PA4);
if(led == 13) PORTB &= ~(1 << PB3);
if(led == 14) PORTA &= ~(1 << PA1);
if(led == 15) PORTB &= ~(1 << PB2);
if(led == 16) PORTA &= ~(1 << PA7);
if(led == 17) PORTB &= ~(1 << PB1);
if(led == 18) PORTA &= ~(1 << PA6);
if(led == 19) PORTB &= ~(1 << PB0);
if(led == 20) PORTA &= ~(1 << PA0);
if(led == 21) PORTD &= ~(1 << PD6);
if(led == 22) PORTC &= ~(1 << PC0);
if(led == 23) PORTD &= ~(1 << PD7);
if(led == 24) PORTC &= ~(1 << PC4);
if(led == 25) PORTD &= ~(1 << PD1);
if(led == 26) PORTC &= ~(1 << PC3);
if(led == 27) PORTD &= ~(1 << PD4);
if(led == 28) PORTC &= ~(1 << PC2);
if(led == 29) PORTD &= ~(1 << PD5);
if(led == 30) PORTC &= ~(1 << PC1);
}

// Programmcounter
volatile uint8_t progcounter = 0;

// INT0
ISR(INT0_vect) {
if(progcounter < 3) progcounter++;
else progcounter = 1;
}

// Hauptprogramm
int main()
{
// Ports initialisieren
port_init();

// Interrupts global aktivieren
sei();

// Endlosschleife
while(1){
if(progcounter == 1) led_on(30);
if(progcounter == 2) led_off(30);
}
return(0);
}


Ich hoffe, dass mir jemand bei meinem Problem weiterhelfen kann.

MfG
Christian

Ceos
13.05.2008, 10:38
Der Controller löst aber nicht zuverlässig die Interrupt-Routine
meinst du, das er manchmal reagiert und manchmal nicht ?

ein taster prellt meist, kann doch sein das du 2, 4, 6, 8 oder ein höheres vielfaches von 2 lowflanken hast während du auf den taster drückst.

versuche mal statt auf eine flanke zu warten auf ein level zu warten, das könnte ETWAS stabiler sein, ansonsten den taster entprellen

EDIT: wenn du 2 - 8 Flanken hast musst du nicht unbedingt das superkurze flackern der LED bemerken, dazu ist der sehsinn meist zu langsam

EDITEDIT inkrementier bei jedem interrupt doch ... kA das PORTA Register

also



ISR()
{
PORTA++;
}

dann kannst du mitzählen wie oft die ISR aufgerufen wird bis zu 255 mal ^^

SprinterSB
13.05.2008, 10:48
Vermutlich gehen die IRQs, aber wegen fehlender Entprellung des Tasters werden mehr als 1 Flanke pro Druck ausgelöst.

Zudem fehlt ein Teil der Initialisierung, weil du zB mit


MCUCR |= (1 << ISC01);

nur 1 Bit auf 1 setzt (es muss noch ein Bit auf 0 gesetzt werden). Weiß jetzt net, wie das SFR beim Reset initialisiert wird, aber sauber ist sowas net.

Ceos
13.05.2008, 10:59
statt zu ODERN würd ich auch an deiner stelle das gesammte register in einem zug programmieren, sonst löst dein ISR eventuell zu früh aus wenn du mehrere operationen hintereinander ausführst, dann musst du das ISC00 nicht nachträglich auf 0 schreiben, da muss ich sprinter zustimmen

Kagerer
13.05.2008, 15:29
Erst mal danke für eure schnellen Antworten.


meinst du, das er manchmal reagiert und manchmal nicht ?
Ja genau.



ein taster prellt meist
Ich hab parallel zum Taster einen 47nF Kondensator geschalten der sollte doch eigenltich reichen um das Prellen zu verhindern. Hab ich nur vergessen zum schreiben.



Zudem fehlt ein Teil der Initialisierung
Werd ich dann gleich mal auf "MCUCR = 0b00000010;" ausbessern.

Kagerer
25.05.2008, 11:04
Also ich hab es jetzt mit den Interrupts aufgegeben. Ich frag den Taster nun mittels Polling ab und das funktioniert wie gewünscht.

Ceos
26.05.2008, 11:58
interrupts kann man doch auch auf PEGEL einstellen also nicht reagieren auf flanke sonder wenn ein bestimmter PEGEL anliegt, versuchs damit mal!

Kagerer
26.05.2008, 14:06
Habe ich schon versucht. Brachte aber keine Verbesserung.