Hallo ich bin hier fast am verzweifeln, ich habe hier ein Programm, bei
dem der Compiler einen wichtigen wert wegoptimiert, Wie kann ich das
Verhindern?
1
C-Code
2
charadcwertermittlung(unsignedcharzeit_art)
3
{
4
//Fehler: zeit_art ist immer 0??? da wegoptimiert
5
6
7
adcteiler=1;
8
9
ADCSRA|=(1<<ADSC);
10
while(ADCSRA&(1<<ADSC))
11
adc_ergebnis=ADCH;
12
if(zeit_art==MINUTEN)
13
{
14
adcteiler=4;
15
}
16
if(zeit_art==STUNDEN)
17
{
18
adcteiler=10;
19
}
20
adc_ergebnis=adc_ergebnis/adcteiler;
21
22
if(adc_ergebnis>zeit_art)
23
{
24
adc_ergebnis=zeit_art;
25
}
26
returnadc_ergebnis;
27
28
}
Die Variable zeit_art wird immer wegotimiert, auch
Der Wert wird wohl in einem Register landen und nicht in einer
gesonderten Variable.
Das kannst Du dir im Listing File genauer ansehen.
Der Wert an sich sollte bei der Abfrage "if(zeit_art==MINUTEN)"
richtig ausgewertet werden.
Ich habe jetzt den Code noch mal so zusammen genommen, wie ich Ihn
Ursprünglich hatte.
Ich muss jetzt noch mal korrigieren, der Code Funktioniert beim
Debuggen, mit und ohne Optimierung, nur wenn ich alles auf den uC
spiele, wird die letzte Abfrage nicht ausgeführt.
Ich habe jetzt mal alles Angehängt.
VG Stefan
Hallo,
was dein code ein wenig schwer zu lesen machst ist, das du alle
variabeln oben deklariert hast.
adc_ergebnis wird nur in adcwertermittlung verwendet, warum dann nicht
dort deklarieren?
Stefan Rau schrieb:> Hier noch der passende Assembler Code:
Sieht doch alles korrekt compiliert aus.
Nur warum zwingst Du den Compiler, alles mit globalen Variablen zu
rechnen?
Das erzeugt doch nur unnützten Code (die ganzen LDS/STS).
Peter
Stefan Rau schrieb:> if (adc_ergebnis>zeit_art)adc_ergebnis = zeit_art;> // Fehler: Befehl nach Klammer wird nicht ausgeführt.
Der Befehl wird dann übersprungen, wenn adc_ergebnis kleiner oder gleich
zeit_art ist. Welche Werte haben die Variablen denn an der Stelle?
Stefan Rau schrieb:> nur wenn ich alles auf den uC> spiele, wird die letzte Abfrage nicht ausgeführt.
Woran genau erkennst du das?
Und was wird nicht ausgeführt, die ganze if-Abfrage oder die vom if
abhängige Zuweisung? Deine Beschreibungen sind hier nicht eindeutig.
@Jörg G
Du hast Recht. habe es korrigiert.
@PeterII
Da es nicht funtioniert hat habe ich angefangen alles zu ändern und habe
auch die Variablen rausgeholt.
@Helfer
zum Glück mal jemand der Assembler erklärt.
@Peter Dannecker
Siehe PeterII
Die Frage aber bleibt, warum funktioniert das nicht auf den uC?
Habe den uC auch noch mal extra gelöscht. Ändert sich aber nichts.
Auch noch mal das Hex File gelöscht, Pfade geprüft, ändert sich auch
nichts
Hier noch mal den C Code
1
C-Code
2
#define STUNDEN 24
3
#define MINUTEN 60
4
5
charadcwertermittlung(unsignedcharzeit_art)
6
{
7
unsignedcharadc_ergebnis;
8
unsignedcharadcteiler=1;
9
10
ADCSRA|=(1<<ADSC);
11
while(ADCSRA&(1<<ADSC));
12
adc_ergebnis=ADCH;
13
14
if(zeit_art==MINUTEN)adcteiler=4;
15
16
if(zeit_art==STUNDEN)adcteiler=10;
17
18
adc_ergebnis=adc_ergebnis/adcteiler;
19
20
if(adc_ergebnis>zeit_art)adc_ergebnis=zeit_art;// Fehler: Befehl nach Klammer wird nicht ausgeführt. Da wegoptimiert.
21
returnadc_ergebnis;
22
}
und der passende ASMCode
1
AVR-Assembler-Code
2
00000250 <adcwertermittlung>:
3
250: 28 2f mov r18, r24
4
252: 80 91 7a 00 lds r24, 0x007A
5
256: 80 64 ori r24, 0x40 ; 64
6
258: 80 93 7a 00 sts 0x007A, r24
7
25c: 80 91 7a 00 lds r24, 0x007A
8
260: 86 fd sbrc r24, 6
9
262: fc cf rjmp .-8 ; 0x25c <adcwertermittlung+0xc>
Der die Variable ADCergebnis nimmt nach dem Auslesen des ADC einen Wert
zwischen 0 und 255 an, in dem Beispiel hat er den Wert 253.
Die Rückgabe gebe ich auf einem Display aus.
Die Funktion wird mit
adc_reuckwert=(int)adcwertermittlung(MINUTEN); in Main aufgerufen.
Wenn ich nun an dem Poti drehen, der an dem ADC sitzt, den bewegt sich
der Wert zwischen 0 und 74, sollte aber zwischen 0 und 60 sein. Da ja in
der Abfrage steht:
Zeit Art ist MINUTEN also 60
if (adc_ergebnis>zeit_art)adc_ergebnis = zeit_art;
Wenn ich den Code im Simulator ausführe, dann wird bei 253 60
zurückgegeben.
Nach dem Laden auf den uC wird 74 ausgegeben.
> ADCSRA |= (1 << ADEN) | (1 << ADSC) | (1 << ADIE);
Dein Programm schmiert ab, sobald der ADC fertig ist.
Man gibt NIEMALS einen Interrupt frei, für den man keine ISR hat.
> Die Frage aber bleibt, warum funktioniert das nicht auf den uC?
Wie prüfst du das? Vielleicht hast du beim Testen auf dem µC andere
Eingangsbedingungen als im Simulator. Im Simulator macht der ADC
"nix", d.h. du gibst ihm in der Simulation Daten vor. Auf dem µC ist das
anders.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#ADC_.28Analog_Digital_Converter.29
"In der praktischen Anwendung wird man zum Programmstart den ADC erst
einmal grundlegend konfigurieren und dann auf verschiedenen Kanälen
messen. Diese beiden Dinge sollte man meist trennen, denn das
Einschalten des ADC und vor allem der Referenzspannung dauert ein paar
Dutzend Mikrosekunden. Ausserdem ist das erste Ergebnis nach dem
Einschalten ungültig und muss verworfen werden."
Hast du das beachtet?
Jetzt gehst du mal als erstes her und machst hier, hinter diese Ausgabe
lcd_setcursor(1,1);
lcd_string(adc_string);
noch ein Leerzeichen drann, nicht dass dich die Ausgabe narrt.
Und dann: Du hast ein LCD. Das kannst du benutzen um dir
Zwischenergebnisse ausgeben zu lassen.
Stefan Rau schrieb:
> itoa(adc_reuckwert,adc_string,8);
Hat es einen speziellen Grund, daß du dir den Wert in Basis 8 ausgeben
läßt? 74 oktal sind übrigens genau 60 dezimal.
@Heinz @Helfer
den Interrupt habe ich rausgenommen. Und eine Abfrage zum verwerfen des
ersten wertes duchgeführt.
ADMUX |= (1<<REFS0)|(1<<ADLAR);
ADCSRA |= (1 << ADEN) | (1 << ADSC);
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));
result = ADCH;
Ich habe auch die Variable ADC Ergebnis in ein int geändert, da ich
neuerdings werte von über 255 bekomme.
@Heinz die zweite
Wie Wo und wie soll ich ein Leerzeichen einfügen?
@Rolf
ja, ich habe die Diaplayansteuereung aus dem TUT genommen, ich wollte da
jetzt auch nichts ändern, daher gebe ich alles als char aus.
@all
Ich habe jetzt noch ein paar Diplayausgaben integriert und bei der
If-Abfrage die 60 hart kodiert.
und erhalte als Wert 334 67 67 hier der Code dazu
Anmerkung dazu: 334/4 sind 83 ??? kann der uC nicht rechnen? ;-)
1
C-Code
2
3
/*
4
Diese Routine liest den ADC Wert aus und gibt je nach aufgerufener Einheit den Stunden oder Sekundenwert zurück.
5
Aufgerufener Wert 24 dibt den ADC Wert so aufgelöst, dass ein Wert zwischen 0-24 zurückgegeben wird.
6
bei 60 das gleiche.
7
Bei anderen Werten ist der Wert die Obergrenze des zurückgegebenen Wertes.
8
*/
9
charadcwertermittlung(unsignedcharzeit_art)
10
{
11
unsignedintadc_ergebnis;
12
unsignedcharadcteiler=1;
13
chartempchar[8];
14
15
ADCSRA|=(1<<ADSC);
16
while(ADCSRA&(1<<ADSC));
17
adc_ergebnis=ADCH;
18
//Diplay Ausgabe 1
19
lcd_clear();
20
itoa((int)adc_ergebnis,tempchar,8);
21
lcd_string(tempchar);
22
_delay_ms(700);
23
24
if(zeit_art==MINUTEN)adcteiler=4;
25
26
if(zeit_art==STUNDEN)adcteiler=10;
27
28
adc_ergebnis=adc_ergebnis/adcteiler;
29
//Diplay Ausgabe 2
30
lcd_clear();
31
itoa((int)adc_ergebnis,tempchar,8);
32
lcd_string(tempchar);
33
_delay_ms(500);
34
35
36
if(adc_ergebnis>60)adc_ergebnis=60;// Fehler: Befehl nach Klammer wird nicht ausgeführt.
Stefan Rau schrieb:> und erhalte als Wert 334 67 67 hier der Code dazu> Anmerkung dazu: 334/4 sind 83 ??? kann der uC nicht rechnen? ;-)
Doch er kann rechnen.
Aber du kannst nicht in unterschiedlichen Zahlensystemen denken.
Rolf hats gesehen
Beitrag "Re: Optimierung Fehlerhaft?"
itoa((int)adc_ergebnis,tempchar,8);
Immer noch!
Die 8 als 3. Parameter sind nicht das, was du glaubst das es ist!
Doku zu itoa lesen!
Hallo Karl Heinz.
Danke für den Wink mit dem Baumstamm.... ich habe den Beitrag von Rolf
nicht verstanden.Ich dachte der 3. Parameter wäre die Länge...
Jetzt kommt meine 60 so wie es soll.
Danke an alle.
VG Stefan