PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ISR Fehlerhaft



Zille
20.01.2014, 14:22
Hallo zusamen,

ich habe ein Problem mit meiner ISR.
Ich habe im Wesentlichen ein Programm geschrieben, welches bei Auslösen von Int0 eine Variable incrementiert und bei Auslösen von Int1 diese decrimentiert. Soweit läuft es auch einwandfrei.
Nun habe ich allerdings den Fehler, dass hin und wieder bei Betätigung von einem der Interrupts anstatt "1" hinzu bzw abgezogen gleich "2" hinzu bzw abgezogen wird.
In den ISR habe ich bewusst nun eine delaytime von 10000ms eingetragen. Betätige ich den Schließenkontakt nun z.B 5x innerhalb der delaytime, so wird die Variable gleich um "5" verändert. Das möchte ich so natürlich nicht ;)

Daher meine Frage: Wie kann ich es verhindern, dass die ISR von z.B Int0 wärend Sie ausgeführt wird sich die weiteren Interrupts NICHT merkt und mit verarbeitet?

P.S.: cli() steht in jeder ISR direkt am Anfang.

Hier mein Code




/*
* Drehkreuz.c
*
* Created: 06.01.2014 15:53:43
* Author: Zille
*/


#include <avr/io.h>
#include <avr/interrupt.h> // Einbindungen
#include <avr/delay.h>
#include "lcd-routines.h"

#define F_CPU 8000000 // 8MHz Takt

volatile float Besucher_gesamt=0; // Speicher kostet ja nichts ;)
volatile float Besucher_aktuell=0;
char Ausgabe_aktuell[4]; // Für Ascii umwandlung
char Ausgabe_gesamt[4];


int main(void)
{
DDRD = 0b00100011; // PD0,1,5-->LEDs PD2,3,4--> Schließerkontakte,tastend

MCUCR |= 0b00001010; // Flankenauswahl fallende Flanke
GICR |= 0b11000000; // Int0 und Int1 freischalten
lcd_init(); // Display initialisieren
sei(); // Interrupts erlauben


while(1)
{

lcd_clear(); // Display löschen
dtostrf(Besucher_aktuell,4,0,Ausgabe_aktuell); // Double to String umwandeln --> fürs Display
lcd_string(Ausgabe_aktuell); // Ausgabe Inhalt Variable
lcd_string("Besucher");
lcd_setcursor(0,2); // Eine Zeiler tiefer im LCD springen
dtostrf(Besucher_gesamt,4,0,Ausgabe_gesamt);
lcd_string(Ausgabe_gesamt);
lcd_string("Insgesamt");

if (bit_is_set(PIND,4)) // Reset Taster

{
Besucher_aktuell=0;
Besucher_gesamt=0;
}
_delay_ms(100); // Verzug

}
}
ISR(INT0_vect) //Schaltkontakt für eingehende Besucher
{
cli();
Besucher_aktuell++;
Besucher_gesamt++;
PORTD |= (1<<PD5);
_delay_ms(10000); // Verzugzeit bewusst hoch gewählt um Problem besser darstellen zu können
PORTD &= ~(1<<PD5);
sei();
}

ISR(INT1_vect) // Schaltkontakt für ausgehende Besucher
{
Besucher_aktuell--;
if (Besucher_aktuell<0)
{
Besucher_aktuell=0;
}

PORTD |= (1<<PD1);
_delay_ms(10000); // Verzugzeit bewusst hoch gewählt um Problem besser darstellen zu können
PORTD &= ~(1<<PD1);
}




Danke im Vorraus :)

Gruß Zille

Che Guevara
20.01.2014, 15:43
Hi,

also zunächst mal würde ich Besucher_aktuell & Besucher_gesamt nicht als float deklarieren. Außerdem würde ich anstatt Besucher_aktuell++; Besucher_aktuell += 1; schreiben.
Cli() & Sei() kannst du weg lassen, Interrupts werden automatisch in der ISR gesperrt. Hast du die Taster entprellt?
Du kannst am Ende der ISR das INTX-Flag löschen, so wird kein zweiter Interrupt ausgeführt.

Gruß
Chris

Zille
20.01.2014, 16:39
Hi,

die taster dürften doch entprellt sein, da die Interrupts bei fallender Flanke ausgelöst werden,oder?
Das mit dem INTX-Flag werde ich gleich mal ausprobieren.

Danke für deine Antwort.

Gruß Zille

Bumbum
20.01.2014, 17:34
Hallo Zille,

die fallende Flanke hat nichts mit entprellen zu tun. Ich denke hier ist dein Problem. Entweder entprellst du per Hardware (z.B. mit Kondensator + Schmitt-Trigger), oder per Software. (z.B. den Interrupt nach Aufruf sperren bis der Eingang xx ms auf high war). Es gibt viele Wege zum entprellen. Ich denke Google wird dich da mit genügend Informationen füttern. ;-)

Das löschen des INTX-Flags in der ISR führt meiner Meinung nach NICHT zum Ziel. So ein Taster prellt üblicherweise öfter als 2x.

Viele Grüße
Andreas

Che Guevara
20.01.2014, 18:11
Das Löschen des Flags funktioniert natürlich nur, wenn nachher kein Prellen mehr stattfindet, sonst ist es umsonst.

Gruß
Chris