Hallo,
bin mit meinem ATMega48 an der Speichergrenze angelangt und bräuchte
aber noch Platz für ein paar Zeilen.
Versuche nun noch etwas Speicher freizubekommen. Habe öfter Terme wie
diesen hier:
So einfach geht das nicht,
ich weiß jetzt nicht für was diese Bedingung gedacht ist, in welchem
Zusammenhang diese steht??
Die einzige Optimierungsmöglichkeit die ich hier (im Moment) sehe ist
den Assemblercode anzusehen und zu hoffen dass der Compiler nicht
optimal Compiliert hat.
Aber schick doch mal EINE komplette Beispielfunktion, so dass man sich
mal die Zusammenhänge des Ganzen ansehen kann und evtl. tipps für deren
Optimierung geben kann...
Gruß
Handelt es sich um 8-Bit Werte? Das ist nicht ersichtlich aus deinem
Code hier. Sonst klappt mois Vorschlag nicht!
Bei 8 - Bit Werten entspricht <=127 einer Prüfung des MSB auf '0'
>= 128 hesst hingegen, dass das MSB '1' ist.
Gruß Tobi
Mein Vorposter hat das schon sehr richtig geschrieben!
Das ganze nur nochmal zur Erklaerung:
Ausgangspukt:
if(
((driving_old <= 127) && (driving >= 128))
|| ((driving <= 127) && (driving_old >= 128))
)
uebersetzt:
wenn alter wert kleinerGLEICH 127 UND neuer Wert groesserGLEICH 128
ODER
wenn alter wert kleinerGLEICH 127 UND alter Wert groesserGLEICH 128
fuer sowas empfehle ich digital Logik
definiere:
kleinerGLEICH 127 entspricht "logisch null"
groesserGLEICH 128 entspricht "logisch eins"
stelle eine wahrheitstabelle auf:
DO: Driving old
D: Driving
DO | D | Ausgang
0 1 WAHR
1 0 WAHR
0 0 FALSCH
1 1 FALSCH
Welchem LogikTyp entspricht das?
Ich wuerde sagen, dass ist ein klassisches Exklusiv-Oder (EXOR).
128 = 0x80
Ein Wert muss als immer unter 128 sein und ein Wert ueber 127.
x = (DO & 0x80) ^ (D & 0x80);
jetzt kann man 0x80 ausklammener und erhaelt
x = (DO ^ D) & 0x80;
Der Compiler hat möglicherweise nicht erkannt, dass "x <= 127" und "x >=
128" logische Komplemente sind. Mir fällt aber (außer auf Assembler
runterzugehen) im Moment keine Möglichkeit ein, das auszunutzen.
Jetzt waere noch interessant was hier fuer den Compiler als
"optimierter" erscheint...
>Ein Wert muss als immer unter 128 sein und ein Wert ueber 127.>x = (DO & 0x80) ^ (D & 0x80);
hier wird schon mal das hoechste Bit maskiert.
Die EXOR Operation koennte so optimiert sein, dass sie nur noch das
hoechste Bit vergleicht...
>jetzt kann man 0x80 ausklammener und erhaelt>x = (DO ^ D) & 0x80;
hier werden beide Bytewerte bitweise "ver-exort" und DANN das hoechste
Bit ausmarkiert..
Ich denke es kommt aufs selbe raus
hab gerade nochmal den topic gelesen..
er versucht speicher freizumachen..
ich denke solche if-bedingen kann der compiler schon selbst ganz gut
optimieren..
such doch mal nach großen konstanten Strukturen, die evtl.
ueberdimensioniert sind, oder auch evtl im RAM liegen können.
vielleichst du unnoetige (nicht benutze) Funktionen, auch raus damit
oder auskommentieren...
hatte letzt auch so ein Problem mit meinem Controller, da war
(lizenzbedingt) der Speicher ausgeschoepft...
32 K ueberschritten...
haben jetzt ne Lizenz fuer 64 K ;-)
In Assembler wird immer das ganze Byte ver xor't (1 Taktzyklus),
ausmaskieren ist auch nur ein Befehl (also auch 1 Takt)
eor r16, r17
andi r16, 0x80
breq 'zieladresse nach if-block'
Meine Lösung kann also durch 3 Assembler Befehle ersetzt werden und
sollte somit optimal sein.
Danke für die Antworten!
Ja, es sind 8-Bit Werte. Was mir nicht ganz klar ist auf was die if
Abfrage sich bei
1
if((driving_old^driving)&0x80)
bezieht.
Zuerst wird ja eine "Exclusiv Oder Verknüpfung" und anschließend eine
Und-Verknüpfung durcheführt. Doch auf was fragt die if-Anweisung das
Ergebnis ab?
Hier mal der komplette Code der Routine. Wahrscheinlich gibt es da noch
einiges zu verbessern und zu vereinfachen.
Zitat vom OP: "Diese nehmen doch erheblich Speicher in Anspruch."
Es ging also explizit um diesen Term. Er selber schreibt, dass diese
Terme einiges an Speicher in Anspruch nehmen. Also wird er es auch
geprüft haben.
Ansonsten: Verwendest Du schon den Optimierungsgrad "size" -Os ?!
Die if Bedinung ist dann erfüllt, wenn der Ausdruck in der Klammer
ungleich 0 ist.
Übersetzt könnte man sagen, der if-Block wird ausgeführt, wenn das
Höchstwertigste Bit von driving_old und driving unterschiedlich sind.
if ((driving_old ^ driving) & 0x80)
die If-Bedingung wertet dann schluß-endlich nur noch aus
ob das hoechste Bit 1 ist.
Und das ist schon ok so!
Da die Werte vorher EXKLUSIV oder verknuepft wurden.
Damit werden deine beiden FALSCH Faelle ausgeschlossen...
x = (DO & 0x80) ^ (D & 0x80);
oder so, wenn das besser verstaendlich ist..
> if(driving <= 127)
> {
> driving = (-(driving - 127));
> }
sind das unsigned oder signed Werte?
Denn falls das unsigned Werte sind... ist das letzte -(...) unnoetig
bzw. falsch....
is das zufaellig ein ASURO ;-)
Ich bin mir nicht sicher ob der Compiler selber so intelligent ist.
Ersetze mal:
char h = 0;
while(h <= 8)
{
wait_n_10us(250);
h++;
}
durch
char h = 8;
while(h)
{
wait_n_10us(250);
h--;
}
Vielen vielen Dank für ausführliche Hilfe!
Bringt pro Zeile nen halben Prozent zusätzlichen Speicher.
>> if(driving <= 127)>> {>> driving = (-(driving - 127));>> }>sind das unsigned oder signed Werte?>Denn falls das unsigned Werte sind... ist das letzte -(...) unnoetig>bzw. falsch....>is das zufaellig ein ASURO ;-)
Ja, "driving" ist ein unsigned char. Bei der Abfrage so der Wert gedreht
werden. Aus einer 127 ne 0 und aus ner 0 ne 127:
Und ne, ist kein Azuro;-)
Einen Term hätt ich noch:
if((test < 190) && (test >= 150) && (driving >= 128) && (driving <=
130))
[/c]
Kann man den auch noch irgendwie vereinfachen?
Mhm, das ist bei den Zahlen ein bisschen schwierig ;-)
190 ist 1011 1110
150 ist 1001 0110
UND kommt wieder 150 raus...
und bei EXOR 40 (also die Differenz)....
wuesste aber jetzt nicht auf Anhieb wie das zur Optimierung beitraegt...
vielleicht sind einzelene (verschaltete if bedingungen) besser
sollte man bedenken, dass die überprüften Variablen unsigned char sind,
der Compiler aber aus Konstanten erstmal ein int macht.
D. h. Es werden immer 16bit Vergleiche ausgeführt.
Besser wäre vermutlich
naja mit den Variablen angaben hat er schon Recht.
Ich denke der Compiler rechnet intern mit höherer genauigkeit. was dazu
führt dass größere Konstanten im Code verwendet werden.
also durch konkrete Größen-Angaben wird der optimierte Code noch
optimierter ;-)
Offenbar verwendest Du mehrfach die gleiche(n) globalen/statischen
Variablen.
Ein Rumknaupen an den verwendeten Ausdrücken bringt kaum wass, denn bei
jedem Zugriff werden 4 Byte verplampert. Also:
Zu Beginn der Routine in lokalte Variablen kopieren und auf diesen
arbeiten. Geänderte Variablen am Ende natürlich zurückspeichern.
Eine eigene Frage?
Dieser Thread ist über 18 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.