PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem bei Programmablauf mit Interrupts -> Frequenz mes



Jericho_one
28.02.2007, 14:22
Hallo!

Ich habe mittlerweile mein Programm theoretisch soweit, dass es macht
was es machen soll -> nur wie immer kommt es immer anders als man denkt.

Die Programmteile einzeln (ADC-Auswertung (Interrupt);
Frequenzauswertung (Interrupt); Menü, Ausgabe) funktionieren, dies hab
ich getestet.

Nur beim Zusammenspiel hapert es, wenn die beiden Interruptroutinen
gleichzeitig im Programmablauf vorhanden sind.
Prinzipieller Programmablauf ist folgender:
(endlosschleife)

wenn adc mehr als 8 mal ausgewertet wurde -> auswertung
vornehmen,variable setzen, damit erst wieder Interrupt durchlaufen wird,
wenn Ausgabe erfolgt ist und "Erlaubnis" für Display geben;

wenn Frequenzmessung beendet -> auswertung vornehmen,variable setzen,
damit erst wieder Interrupt durchlaufen wird, wenn Ausgabe erfolgt ist
und "Erlaubnis" für Display geben;

wenn Ausgabe erlaubt -> Schreibe werte auf Display, setze
Interruptvariablen zurück;

(ende)

So als kurzer Auszug.(Teil des Quellcodes ist oben angehängt.)

Mein Poblem ist jetzt, dass bei der Frequenzmessung ca. jedes 3. mal
extrem falsche werte vorhanden sind -> und ich hab keine Ahnung warum?
Wäre super wenn sich dasjemand mal ansehen könnte.

MFG


P.S. Die Variablen die nicht lokal in der main() deklariert sind, sidn
alle global deklariert (ja, mit volatile ;-) )




ISR(ADC_vect){
if (adcbesch == 1){
return;
}
else{
adczaehler++;
adcspeicher += ADC;
}
}
//-------------------------------------------------------
ISR(TIMER1_CAPT_vect)
{
if( UpdateDisplay == 1 ) //auf vorherige Messung warten
return;

if (x == 0) // 1.High Flanke
{
ic_zp_A = ICR1;
overflow = 0;
x = 1;
}
else // 2.High Flanke
{
ic_zp_B = ICR1;
// Messung ist fertig, Display kann neu geschrieben werden
UpdateDisplay = 1;
x = 0;
}
}
//-------------------------------------------------------
ISR(TIMER1_OVF_vect)
{
overflow++;
}


int main(void){

verz(20);




//-------------------------------------------------------

float drehzahlwert = 0; //Speicherwert für Drehzahlwert
float leistung = 0;
long adcergebnis = 0;

Start_EEPROMLesen(); //Werte aus EEPROM lesen und in Variablen schreiben
LCD_Init(0); //Initialisierung des Displays
LCD_Clr(); //Display löschen
verz(4); //Pause fürs Display
Init(); //Taster-Initialisierung, ADC-Initialisierung, RS232- Initialisierung
Zaehler_EEPROM(); //Überprüfen der EEPROM Schreibzugriffe



TCCR1B = (1<<ICES1) | (1<<CS10) ; // Input Capture Edge, kein PreScale ->Taktfrequenz: 8MHz externer Quarz
TIMSK = (1<<TICIE1) | (1<<TOIE1); // Interrupts akivieren, Capture + Overflow
DDRD = 0x00;
verz(1);
sei();
drehmomentwert = drehmomentberechnung(700);
while(1)
{
if (adczaehler >= 8){

adcbesch = 1;
adcergebnis = adcspeicher/adczaehler;
drehmomentwert = drehmomentberechnung(adcergebnis);
adczaehler = 0;
adcspeicher = 0;
write = 1; //Display soll beschrieben werden
//UpdateDisplay = 1;

}

if( UpdateDisplay == 1 )
{
zw_Erg = ((overflow*65536) + ic_zp_B - ic_zp_A); // Overflow berücksichtigen
Erg = 8000000 / zw_Erg; //8MHz Quarz
drehzahlwert = drehzahlberechnung(Erg);
write = 1; //Display soll bechrieben werden


}



if ( write == 1){ //Ausgabe der Werte, je nachdem ob write gesetzt oder nicht

if ( ausgabemodus == 1){ //Ausgabe der Werte über LCD + RS232
leistung = leistungsberechnung(drehmomentwert,drehzahlwert);
Ausgabe_LCD();
}
else if (ausgabemodus == 2){ //Ausgabe der Werte nur über RS232 -> schnell !!Achtung!! Keine Leistungsberechnung/ausgabe
if (lcdbeschr == 0){
LCD_Clr();
verz(3);
LCD_WritePosString(0, 0,"RS232-Modus aktiv", 1);
LCD_WritePosString(1, 0,"Displayausgabe", 1);
LCD_WritePosString(2, 0,"ausgeschaltet", 1);
lcdbeschr = 1;
}
else if (lcdbeschr == 1){
Ausgabe_RS232();
}
}
write = 0;
adcbesch = 0;
UpdateDisplay = 0;
}



if (PIND &(1 << MENUETASTE)){ //Bedingung für Menüaufruf -> Messung wird gestoppt!!
cli();
verz(8);
men();
sei();
}

if (PIND &(1 << UEBERSICHTTASTE)){ //Bedingung für Aufruf der Übersicht -> Messung wird gestoppt!!
cli();
verz(8);
uebersicht();
sei();
}

}

return 0;

}

Jericho_one
01.03.2007, 10:28
niemand eine Idee?

SprinterSB
01.03.2007, 11:12
Es genügt nicht, die Variablen volatile zu machen. Die Zugriffe müssen atomar sein.

Jericho_one
01.03.2007, 13:43
-> atomar = ?

das seltsame ist, dass die Auswertung des ADC und die Auswertung der Frequenz mittles ICP/Timer in jeweils separaten Programmen wunderbar funktioniert... - das ist das was mich stutzig macht.

MFG

PICture
01.03.2007, 14:13
Hallo Jericho_one!

In multitasking Programms kann ich Dir aus eigener Erfahrung empfehlen keine Interrupts zu benutzen, sondern alle Unterprogramme in einer endlosen Schleife nacheinander aufzurufen. Sehr hilfreich sind selbst definierte Flags die nur nötige Tasks starten. Z.b. wenn Frequenz schon gemessen ist, startet Displayausgabe u.s.w.

MfG

Jericho_one
01.03.2007, 14:20
Hi!

Genau so habe ich es gemacht -> Also wenn z.B. Frequenzmessung zu Ende, also ein neuer Messwert da ist, dann darf erst wieder eine Ausgabe erfolgen.

Das andere Problem ist, dass ich ohne Interrupts wohl nicht auskomme, da ich einen Timer im Hintergrund laufen lassen muss.

Aber ich werds jetzt noch mal ein wenig umstellen - mal sehn ob was verbünftiges rauskommt.

Danke schon mal!

PICture
01.03.2007, 14:31
In dem Fall müsste man alle Unterprogramme, die der Timer aufruft duplizieren, damit er nichts in den von ihm unterbrochenen ändert. :)

MfG

Jericho_one
01.03.2007, 15:48
Hi!

Also ich habs jetzt so gemacht dass nur noch die Frequenzmessung mit Interrupts läuft - der Rest durch Polling - und es scheint zu laufen.

Danke für den Tip!

MFG

SprinterSB
01.03.2007, 16:43
Zu "atomar" folgst du den Links in
https://www.roboternetz.de/wissen/index.php/C-Tutorial/Interrupt-Programmierung

Ich hab momentan keine Zeit, den Artikel auszutexten. Aber der Punkt "atomar" ist ein Fehler, den ich im Forum oft sehe und die Stellen, die das Thema im Wiki behandeln sind zugegebenermassen schwer zu finden...

Bist du sicher, daß deine IRTs (Interrupt respond times) nicht zu lange werden? Du musst ja sicherstellen, daß nicht 2 InCapt geschehen und der vorheriger Wert überschrieben wird, bevor du ihn abholen konntest.

Was geschieht, wenn der OVF in der CAPT getriggert wird?
Was geschieht, wenn Overflow und InCapt zeitnah auftreten?
Wodurch ist die maximale IRT in deiner Applikation gegeben, und wie hannst du diese minimieren?