www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Term vereinfachen / ATMega48


Autor: Fred (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
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

Autor: µCnoob (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
if ((driving_old ^ driving) & 0x80)

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ µCnoob: Deine Name ist Programm, oder? :-P

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit den 8 Bit war eine Annahme von mir, da die Namen der Variablen 
darauf schließen lassen, dass 127 die Mitte der Wertebereichs ist.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Morin (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Fred (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
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.
//********************************************************************************
//* Description: calculate accelaration and driving speed                        *
//********************************************************************************
void driving_routine(void)
{
  
  if((driving <= 130) && (driving >= 128))
  {
    driving = 128;
  }
  
  if(driving_release == 0x05)
  {
    //diff decides over deceleration or accelerating
    int diff = (driving - driving_old);
      
    if(((driving_old <= 127) && (driving >= 128)) || ((driving <= 127) && (driving_old >= 128)))
    {          
      char h = 0;

      while(h <= 8)
      {
        wait_n_10us(250);
        h++;
      }

    }


    //forward drive
     if(driving >= 128)
     {
        //accelerate
      if( diff > 50 )          
        {
          diff = 50;
        driving_old += diff;
        }

      //decelerate
      else if( diff < -50 )      
         {
        diff = -50;
        driving_old += diff;
      }

      //maintain speed
      else            
        driving_old = driving;
    }

    //backwards drive
      else                
      {
      //decelerate
        if( diff > 50 )          
        {
           diff = 50;
        driving_old += diff;
        }

      //accelerate
        else if( diff < -50 )      
        {
        diff = -50;
        driving_old += diff;
      }

      //maintain speed
        else              
          driving_old = driving;
    }
          
    driving = driving_old;

    //calculate driving value
    if(driving <= 127)
    {
      driving = (-(driving - 127));
    }  
  }

  driving_release = 0x00;
}

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?!

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
if((driving <= 130) && (driving >= 128))
  {
    driving = 128;
  }


Diese Bedingung kann nicht wahr werden. Also raus!

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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--;
      }

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Moi

was ist daran jetzt besser`?

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dass der Vergleich auf 0 in Assembler schneller geht, als der Vergleich 
auf 8.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt da gibts ja nen eigenen Assembler Befehl

Autor: Fred (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einen Term hätt ich noch:
if((test < 190) && (test >= 150) && (driving >= 128) && (driving <=
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

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
if((test < 190) && (test >= 150) && (driving >= 128) && (driving <= 
130))

Keine Ahnung, ob es was bringt. Probier mal:

if (((test - 150) < 40) && ((driving - 128) < 3))

Autor: Olaf Dreyer (Firma: O.D.I.S.) (dreyero)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

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


Gruß

Olaf

Autor: Moi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Term ist doch schon lange optimiert! =)

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fred schrob:
//********************************************************************************
> //* Description: calculate accelaration and driving speed
> *
> //********************************************************************************
> void driving_routine(void)
> {
> 
>   if((driving <= 130) && (driving >= 128))
>   {
>     driving = 128;
>   }
> ...
> 

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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.