Term vereinfachen / ATMega48

Gast #969836
Lesenswert?

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:
1
if(((driving_old <= 127) && (driving >= 128)) || ((driving <= 127) && (driving_old >= 128)))

Diese nehmen doch erheblich Speicher in Anspruch. Hat jemand ne Idee wie 
man diese Terme etwas Speichereffizienter gestalten kann.



Gruß Fred
Gast #969849
Lesenswert?

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ß
Gast #969864
Lesenswert?

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
Gast #969894
Lesenswert?

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;
Gast #969902
Lesenswert?

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.
Gast #969905
Lesenswert?

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
Gast #969912
Lesenswert?

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 ;-)
Gast #969914
Lesenswert?

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.
Gast #969915
Lesenswert?

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.
1
//********************************************************************************
2
//* Description: calculate accelaration and driving speed                        *
3
//********************************************************************************
4
void driving_routine(void)
5
{
6
  
7
  if((driving <= 130) && (driving >= 128))
8
  {
9
    driving = 128;
10
  }
11
  
12
  if(driving_release == 0x05)
13
  {
14
    //diff decides over deceleration or accelerating
15
    int diff = (driving - driving_old);
16
      
17
    if(((driving_old <= 127) && (driving >= 128)) || ((driving <= 127) && (driving_old >= 128)))
18
    {          
19
      char h = 0;
20

21
      while(h <= 8)
22
      {
23
        wait_n_10us(250);
24
        h++;
25
      }
26

27
    }
28

29

30
    //forward drive
31
     if(driving >= 128)
32
     {
33
        //accelerate
34
      if( diff > 50 )          
35
        {
36
          diff = 50;
37
        driving_old += diff;
38
        }
39

40
      //decelerate
41
      else if( diff < -50 )      
42
         {
43
        diff = -50;
44
        driving_old += diff;
45
      }
46

47
      //maintain speed
48
      else            
49
        driving_old = driving;
50
    }
51

52
    //backwards drive
53
      else                
54
      {
55
      //decelerate
56
        if( diff > 50 )          
57
        {
58
           diff = 50;
59
        driving_old += diff;
60
        }
61

62
      //accelerate
63
        else if( diff < -50 )      
64
        {
65
        diff = -50;
66
        driving_old += diff;
67
      }
68

69
      //maintain speed
70
        else              
71
          driving_old = driving;
72
    }
73
          
74
    driving = driving_old;
75

76
    //calculate driving value
77
    if(driving <= 127)
78
    {
79
      driving = (-(driving - 127));
80
    }  
81
  }
82

83
  driving_release = 0x00;
84
}
Gast #969918
Lesenswert?

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 ?!
Gast #969921
Lesenswert?

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.
Gast #969928
Lesenswert?

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 ;-)
Gast #969945
Lesenswert?

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?
Gast #969981
Lesenswert?

Einen Term hätt ich noch:
1
if((test < 190) && (test >= 150) && (driving >= 128) && (driving <=
2
130))


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
(Firma: O.D.I.S.) #970009
Lesenswert?

Hallo,

bei den if-Abfragen
1
if(((driving_old <= 127) && (driving >= 128)) || ((driving <= 127) && (driving_old >= 128)))
 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
1
if(((driving_old <= (unsigned char)127) && (driving >= (unsigned char)128)) || ((driving <= (unsigned char)127) && (driving_old >= (unsigned char)128)))
.


Gruß

Olaf
Gast #970022
Lesenswert?

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 ;-)
Persönliche Seite #970268
Lesenswert?

Fred schrob:
1
//********************************************************************************
2
> //* Description: calculate accelaration and driving speed
3
> *
4
> //********************************************************************************
5
> void driving_routine(void)
6
> {
7
> 
8
>   if((driving <= 130) && (driving >= 128))
9
>   {
10
>     driving = 128;
11
>   }
12
> ...
13
>

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren