www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Code Reduzieren


Autor: Sascha H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi @ll,

ich bin grade dabei für mein Praktikum (Studium) den letzten C164
Versuch zu programmieren. Leider haben wir von Keil µVision nur
Evaluations Versionen und diese haben eine Beschränkung der Codelänge
auf 8KB.

Daher die Frage, wo kann man effektiv den Code verkürzen. Was sich
schon gut gemacht hat, war alle strncpy durch for-Schleifen zu
ersetzen. Außerdem lasse ich den Compiler schon auf Größe optimieren
[#pragma ot(7, size)].

Hat noch jemand Ideen für typische Konstrukte die man verkürzen kann.

Ich will den ganzen Code jetzt nicht posten, der wäre etwas zu lang.

Sascha

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm deinen Code zu kürzen ohne den zu kennen ist natürlich etwas
schwierig.
Du kannst alles kürzen was du kürzer schreiben kannst!

Autor: Sascha H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was auch noch ganz gut klappt, möglichst viele Variablen in den
near-Speierbereich legen. Um in far zu schreiben/lesen sind ja ein paar
Maschienenbefehle mehr nötig.

Autor: Richard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hinter vorgehaltener Hand: Wenn genug RAM, dann statt lokaler Variablen
möglichst globale Variablen verwenden, denn dann entfällt das gepushe
und gepoppe.

Autor: Sascha H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Idee mit den globalen Variablen ist auch gut. Ich denke da muss man
keine Hand vorhalten.

Außerdem habe ich bemerkt, dass die Variante A mehr Code braucht, als
die Variante B:

A:
UmdrehTime = UmdrehTime + ( (float) drehBuffUeber[i] * ( (float) 0xFFFF
) + (float) drehBuff[i] )* T8SETING;

B:
UmdrehTime = UmdrehTime + (float) drehBuffUeber[i] * ( (float) 0xFFFF )
* T8SETING;
UmdrehTime = UmdrehTime + (float) drehBuff[i] * T8SETING;

Autor: Gernot Frisch (gernotfrisch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Variablen wo's geht wiederverwenden.
Funktionen statt Makros.
Überlegen, ob eine Funktion über ein zusätzliches "Steuerbit" nicht 2
oder 3 Funktionen ersetzen kann usw...
Wenn man z.B. über ein Feld von XY immer wider verschiedene Funktionen
aufruft, kann man auch eine Funktion:
void ForEach(XY* pFirst, XY* pEnd, void (*foo)(XY* pA, XY* pB) );
machen, die dann die Schleife aufruft und dabei jedes Element mit
seinem Nachbarn einsetzt.
Beispiel (ungetestet)
void Drucken(XY* pA)
{
   LCD_out(pA->text);
}

void ForEach(XY* pFirst, XY* pEnd, void (*foo)(XY* pA) )
{
 XY* pA;
 for(pA=pFirst; pA!=pEnd; ++pA)
 {
      foo(pA);
 }
}

int main(int, char**)
{
  ...
  // pEnd = 1 nach dem letzen Element
  ForEach(sXY, sXY+xycount, Drucken);
}

Autor: Ronny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keine Format-Strings für printf verwenden und wenn´s doch nich anders
geht wenigstens auf Fliesskomma dabei verzichten.Man kann z.B auch eine
Fliesskommazahl in 2 Integer verwandeln und die dann formatiert
ausgeben.Bei einigen Compilern kann man das in den Compiler/Linker
Einstellungen angeben,das z.B keine Fliesskomma-Unterstützung erwünscht
ist.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Die Idee mit den globalen Variablen ist auch gut."

Genau das Gegenteil ist der Fall !

Lokale Variablen können oft in Registern gehalten werden und sind daher
viel effizienter, sowohl vom Code-Verbrauch, als auch von der
Geschwindigkeit.

Ich kenne den C164 nicht, aber dann muß der schon sehr vekorkst sein,
wenns bei dem wirklich andersrum wäre.


Sehr viel Code kann man auch sparen, wenn man statt float, int oder
long nimmt. Da sind durchaus 1..2kB Ersparnis drin.


Peter

Autor: HAL9000 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Funktionsaufrufen kann man manchmal sparen (zumindest beim 8051)
wenn ne funktion wenig Inhalt, aber viele Parameter hat, lieber den
inhalt direkt an der Aufrufstelle reinschreiben, als eine funktion zu
benutzen. Das Stack-geschiebe braucht schließlich viel platz.

Ist unsauber, ich weiß, (genau wie global RAM geschichte) aber wenn mal
tatsächlich die paar wenige bytes speicher fehlen, um das programm
raufzubraten, macht mans lieber.

Autor: Sascha H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also das mit dem NEAR scheint nur in manchen Fällen was zu bringen.
Manchmal wächst der Code dadurch auch. In den meisten Fällen bleibt er
scheinbar gleich. Wobei ich das jetzt nur durch rumprobieren getestet
habe, den Assembler zu zerlegen war mir jetzt zu aufwändig.

Auf jeden Fall passt es jetzt. Ich glaube die beste Lösung war doch,
dass mit den globalen Variablen. Damit kann man ohne großen Aufwand
schon mal einiges an Code gut machen. Auf jedenfall bin ich jetzt klein
genug zum Kompilieren.

Sascha

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist die Beschränkung auf Codegrösse realisiert - über "Abzählen"
oder über eine Beschränkung des Adressraums oder über einen Offset der
Codeposition im Speicherraum...?

Ersteres ist nicht so kritisch und kann bei der Entwicklung
berücksichtigt werden. d.h. vielleicht kannst du grössere Funktionen
zusammenfassen und als getrenntes Stück in den µC laden...

Dazu musst du rausfinden, wie du eine Funktion an eine von dir
gewünschte Position im Speicher legst und den Linker überredest dafür
zu relozieren.

Im abgespeckten Restcode verwendest du die ausgelagerten Funktionen
über Funktionspointer.

Du solltest Ausschau nach Funktionen halten, die wenige bis keine
Libraryfunktionen benutzen. Ich würde mir eine Initfunktion in dem
ausgelagerten Block schreiben, die mir eine Tabelle mit den benötigten
Funktionspointern zusammenbaut.

Mit den Aufrufen von Libraryfunktionen im abgetrennten Codestück
verfährst du im Prinzip gleich. Du baust dir eine Tabelle mit den
benötigten Funktionspointern im Hauptprogramm.

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn das ganze ein Praktikum ist und davon die letzte Aufgabe wundert es
mich schon ein wenig, wenn du 8Kb sprengst. Denn dann haben ja wohl auch
andere Studenten das Problem bestimmt schon gehabt und den Prof.
informiert.
Wenn du die Aufgabe nicht nur lösen willst, sondern dabei auch was
lernen willst: Mach dir Gedanken über deinen Algorithmus und deine
Datenstrukturen, denn dies bestimmt zum größtenteil wie effektiv oder
auch klein dein Programm wird.
Ich finde es sehr verwunderlich das ein ersetzen von allen strncpy
durch for-Schleifen einen kleineren Code ergibt.
Lass dir mal die Mapping Datei ausgeben, da siehst du welche Funktionen
den grössten Platzbedarf haben.

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ab und zu ist das sogar Absicht mit der Codegröße. Bei unserem letzten
Praktikum war es auch nur ganz knapp möglich alle gewünschten
Funktionen zu realisieren bevor einem der Speicher ausgegangen ist. War
sozusagen eine Qualitätskontrolle :-)

Autor: Sascha Haupt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Praktikum sieht halt so aus, dass man von Versuch zu Versuch zusätzliche
Funktionen zum Programm hinzufügt. Ich bin auch nicht der einzige der
das Problem hatte.

Zu den globalen Variablen:
Also nach genauerem Testen kann ich sagen, dass man nicht pauschal
sagen  ob das mehr oder weniger Code gibt. Das scheit echt davon
abzuhängen ob er die irgendwann auf den Stack schreibt, oder ob er sie
in einem Register hält. -> Ausprobieren

Wie die Codegröße vom Linker limitiert wird weis ich nicht. Da habe ich
mir auch noch keinen Kopf drum gemacht.

Auf jeden Fall habe ich das ganze auf die Reihe bekommen und jetzt
funktioniert es.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Globale Variablen sollten ebenso wie statische Variablen nicht auf dem
Stack landen, das tun nur automatische Variablen.

Autor: T.Stütz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zu "Zu den globalen Variablen:
Also nach genauerem Testen kann ich sagen, dass man nicht pauschal
sagen  ob das mehr oder weniger Code gibt. Das scheit echt davon
abzuhängen ob er die irgendwann auf den Stack schreibt, oder ob er sie
in einem Register hält. -> Ausprobieren"

Datentyp "sdata" verwenden (sdata ist im interen RAM des C16x und
wird mit einem Wort-Befehl angesprochen)

Bsp: unsigned int sdata wWort;

Variablen die nur zwei Zustände haben (AN/AUS,WAHR/FALSCH etc) auch als
"bit" deklarieren (Wieder ein Wort-Befehl)

Bsp: bit bSearch = 1;

Innerhalb Prozeduren/Funktionen kann per "register" Variablen im
Register gehalten werden.

Bei Interrupts die viele Register verwenden ist es sinnvoller eine
ganze Registerbank zu verwenden

Bsp: void NMIInt (void) interrupt 0x02 using TRAP_REG {}

Gruss

Autor: Robert Teufel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also wenn du mit float rechnest, dann hast du wohl schon verloren mit
der Eval Version. Vergiss LIB Aufrufe, unter keinen Umstaenden PRINTF
benuetzen. All die schoenen Dinge in "C" verbraten eine Unmenge
Speicher und somit Programmgroesse.

Robert

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.