Hallo,
ich habe eine globale volatile variable die ich in der ISR des adcs
verändere. Jetzt benötige ich den Wert in einer anderen ISR aber das
funktioniert nicht. Ausser halb der ISR ist die Variable aber OK.
Ist das normal?
Gruß
Florian
globale.h
volatile unsigned short adc_ergebnis[8];
volatile unsigned char adc_kanal[8];
volatile unsigned short kanal_index;
Separate datei
SIGNAL(SIG_OVERFLOW0)
{
//pos = adc_ergebnis[2];
f2 = f1;
f1 = f0;
f0 = (float)(pos-des_pos)/(float)1024.0;
Ua = Ua + (Kp+Ki*T_cnt0+Kd/T_cnt0) * f0 + (-Kp-Kd/T_cnt0) * f1 +
(Kd/T_cnt0) * f2;
if((pos-des_pos)<max_fehler || (des_pos-pos)<max_fehler)
{
//pwm_stop();
//return;
}
PORTD |= _BV(PD7);
/* if(pos-des_pos>0) */
init_pwm_oc1a();
/* else */
/* init_pwm_oc1b() */;
Te = ((float)Ua/(float)Vcc); /* Tein des PWM Signals
*/
int c = ((float)Te * (float)TOP);
setze_tastverhaeltnis(adc_ergebnis[2]);
//setze_tastverhaeltnis(Te * TOP / T_pwm);
PORTD &= ~_BV(PD7);
}
Separate Datei:
SIGNAL(SIG_ADC) //interrupte sind in ISR
automatisch ausgeschaltet
{
adc_ergebnis[kanal_index] = ADCL; //erst ADCL dann ADCH um
sicherzustellen
// das Werte aus
einer Wandlung stammen;
adc_ergebnis[kanal_index] += (ADCH<<8);
kanal_index++;
if(kanal_index==3)
kanal_index=0;
ADMUX = adc_kanal[kanal_index]; /* ca. 100 Zyklen seit der Interrup
ausgelöst wurde */
/*wir können also den mux neu muxen
*/
ADCSRA |= _BV(ADSC);
}
Es geht um adc_ergebnis[x]
Ahh hallo,
nichts für ungut. Ich bin ja kein Baby mehr. Abgesehen davon dürfte das
wohl einige arbeit werden das ins avrstudio zu bringen. Aber bitte im
anhang ist das projekt. Ich dachte nur ob jemand etwas in dem Zusammen
hang weiss. Ich habe es jetzt anders gemacht. Und zwar habe ich noch
einen zeiger auf adc_ergebnis erstellt. diesen benutze ich jetzt in der
ISR.
Ich habs mal angehangen. Es ist ein PWM Servotreiber.
fall jemand interesse an der Elektronik hat, ich bin unter
florian.hillen@web.de zu erreichen oder gleich hier.
Frohes neues Jahr!
> Abgesehen davon dürfte das> wohl einige arbeit werden das ins avrstudio zu bringen.
Halb so wild.
Eine ANgabe brauch ich noch.
Wie stellst du fest, dass da was mit den volatile
Variablen nicht stimmt?
Hast dus im Debugger gesehen oder ist das nur eine Vermutung?
Florian wrote:
> Abgesehen davon dürfte das> wohl einige arbeit werden das ins avrstudio zu bringen.
Stimmt, .tar.gz is nich so mein Ding.
XP kann von Haus aus nur .zip
Peter
Das einzige was ich bis jetzt im Debugger gesehen habe ist,
dass dein Overflow Interrupt zuviel Zeit braucht. Der Prozessor
arbeitet praktisch nur da drinnen. Sobald die ISR fertig ist,
beginnt auch schon der nächste ISR, weil der Timer in der
Zwischenzeit den nächsten Überlauf produziert hat.
Setzt mal den Vorteiler etwas höher.
Ansonsten klappt bei mir im Debugger der Zugriff auf das
Array einwandfrei. Ich wüsste auch keinen Grund warum das
nicht so sein sollte.
Ich habe mal den Vorteiler um eine Stufe erhöht. Seitdem
werden zwischendurch auch wieder Werte vom ADC abgeholt :-)
aha das werde ich einmal Probieren.
Ich habe festgestellt das da was nicht stimmt weil ich an meiner
Leistungselektronik einen Motor habe und der immer nur nach dem ersten
ADC Wert ging.
Ich probies direkt mal aus und meld mich nochmal. Vielen dank auch!
Florian
Also wars doch ganz gut das vollständige Projekt zu posten :-)
Merke: Wenn jemand glaubt dass er einen Compilerfehler entdeckt
hat, dann hat er zu 99% ein anderes Problem im Programm. Natürlich
haben auch Compiler so ihre Fehler. Aber nicht bei einem
simplen Variablenzugriff.
Möchte nur mal vorsichtshalber darauf hinweisen, dass
volatile unsigned short x;
ISR(suchesdiraus)
{
x = irgendwas;
}
main()
{
while(1)
tu_irgendwas_mit(x);
}
auf AVRs zwar 999 von 1000 mal wunderbar funktionieren wird, aber ab und
zu Schrott rauskommt. Siehe
http://www.mikrocontroller.net/articles/Interrupt#Atomarer_Datenzugriff.
> auf AVRs zwar 999 von 1000 mal wunderbar funktionieren wird,> aber ab und zu Schrott rauskommt.
Nun, der Schrott macht aber nicht der Compiler, sondern der
Programmierer, wie üblich. Die Lösung des Problems lautet:
volatile unsigned short x;
ISR(suchesdiraus)
{
x = irgendwas;
}
main()
{
unsigned short x_copy;
while(1)
{
cli();
x_copy = x;
sei();
tu_irgendwas_mit(x_copy);
}
}
Sollte die Funktion von cli(); und sei(); nicht der Grund sein, warum
man die Variable als volatile deklariert (mehr als 1 Byte zum Lesen)?
Sollte eigentlich automatisch vom Compiler erledigt werden.
Nein.
"volatile" sorgt dafür, dass die tatsächlich durchgeführten Zugriffe
denen im Quelltext entsprechen, d.h. dass da nichts wegoptimiert oder
umsortiert wird. Atomar werden die Zugriffe mit "volatile" jedoch nicht.
"Nun, der Schrott macht aber nicht der Compiler"
Wollte ich damit auch nicht ausdrücken. Ich hatte bei Florians Code
jedoch gleich den Verdacht, dass unabhängig vom eigentlichen Problem
jemand, der in Interrupts Floating-Point-Rechnungen durchführt, diese
Feinheit im Umgang mit globalen Variablen auch übersehen hatte - und
genau so ist es.
Hmm.. so wie ich das verstanden habe dient volatile (!beim AVR!) dazu,
Variablen, die außerhalb der Funktion 'main' behandelt werden, neu
einzulesen und während des Einlesens den globalen INT zu sperren, um
teilweises Lesen zu vermeiden, falls währenddessen ein INT auftritt.
Hatte auch noch nie Probleme in der Richtung.
Aber, falls das anders ist, wieder was gelernt.
Bei Ports und Steuerregistern muss er das ja auch nicht, da die
Byteorientiert sind. Dachte, nötig ist es nur bei Variablen >8 Bit, da
es mehrerer Leseoperationen für diese Typen bedarf. Lasse mich aber
gerne eines Anderen belehren.
Ist auch nur bei >8bit nötig, allerdings sind manche I/O-Register >8
breit (z.B. bei Timer, ADC). Aber das Philosophieren lässt sich ganz
einfach abkürzen: Guck in den Code und vertrau darauf, dass GCC sich
korrekt verhält. Stimmt fast immer.