mikrocontroller.net

Forum: Compiler & IDEs Frage zu Code


Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo All!

Wahrscheinlich ein Anfängerproblem... Folgendes:

Habe zwei Variablen, die ich ich in meinem Hauptprogramm miteinander 
verarbeten will. Die eine ist global als volatile deklariert:

volatile uint16_t iGuthaben = 0;

Die andere im Hauptprogramm Lokal als flaot:

float fTemp2 = 0;

Im Hauptprogramm bezieht sich folgender Code auf die Variablen:

fTemp2 = (iGuthaben/3600);

Wenn ich diese Zeile lösche ist mein Speicher zu etwa 16% belegt 
(Optimierung 0s), wenn ich die Zeile drin hab ist der Speicher zu ca. 
61% belegt!!! Wieso?

Danke und Gruß
Waldemar

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
weil eine Division auf in Software gemachert werden muss und dabei auch 
etwas code benötigt. Divisionen sollte man vermeiden und erst recht mit 
float.

Wir vermuten mal alles das es um ein Atmel geht, richtig?

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, richtig... ATMega8...

Es liegt nicht an der Division...

Wenn ich den Gode so schreibe:

fTemp2 = iGuthaben;
cStunden = fTemp2/3600;

und dann die obere Zeige weglösche und kompiliere geht die Auslastung 
von 60,4% --> 18,3%. Es muss irgendwie an der zwischen einer Volatile 
und einer float liegen oder so...

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es liegt nicht an der Division...
> Wenn ich den Gode so schreibe:
> fTemp2 = iGuthaben;
> cStunden = fTemp2/3600;

wenn der compiler gut optimiert, dann macht er keine Division mehr.

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was willst du damit sagen?

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Was willst du damit sagen?
das man an den bisschen code sehr wenig ablesen kann, wenn der compiler 
feststellt das die Division eh nur mit Konstanten ausgeführt wird, dann 
passiert es schnell mal das er die division komplett weglässt.

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aha... Wenn ich das richtig sehe, sind die beiden keine Konstanten... 
Außerdem funktioniert die division (zumindest teils, aber das ist eine 
andere Sache).

Das ist aber keine Antwort auf meine Frage... Ich wollte vorest mal nur 
wissen, wieso ich plötzlich so viel code habe???

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im ersten Beispiel wird eine Integer-Division und eine Konvertierung von
Integer nach Float gemacht. Letztere braucht besonders viel Flash-
Speicher, weil du beim Linken das -lm weggelassen hast.

Im zweiten Beispiel wird nur eine Integer-Float-Konvertierung gemacht,
da du cStunden im weiteren Verlauf des Programm nicht mehr benutzt, so
dass die Division wegoptimiert wird.

Löscht du die Zeile

  fTemp2 = iGuthaben;

bleibt von den beiden Zeilen gar nichts mehr übrig, deswegen wird das
Programm deutlich kürzer.

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dann schau ins map file oder die asm datei. Vergleiche die Dateien mit 
und ohne dem volatile.

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok ich hol mal ein bisschen weiter aus...

Das Programm dient dazu eine 16Bit-Zahl (Sekunden) in Stunden und 
Minuten umzurechnn um dann den Wert auf einem Display auszugeben (in dem 
Fall als Timer-Funktion)

Hier der Relevante Teil des Codes:

// Variablendefinitionen Global
volatile uint16_t millisekunden = 0;
volatile uint16_t iGuthaben = 3670;

.
.
.

// Variable Headerdateien
#include <subs/interrupt.c> // Alle Interruptroutinen

.
.
.

// Programmstart
int main ()
 
{
//----------------------------------------------------------------------
// Variablendefinitionen lokal
  char cBuffer[20];
  float fTemp2 = 0;
  uint16_t temp1 = 0;
  uint8_t cSekunden = 0;
  uint8_t cMinuten = 0;
  uint8_t cStunden = 0;

.
.
.

// main loop

  do
  {

.
.
.

    temp1++;

    if (temp1 == 0x0FFF)
    {
    temp1 = 0;

    fTemp2 = iGuthaben;
    cStunden = fTemp2/3600;
    cMinuten = (fTemp2-(3600*cStunden))/60;
    cSekunden = (fTemp2-(60*cMinuten))/60;
                lcd_clear();
          _lcd_string("Zeit = ");

          itoa(cStunden, cBuffer, 10);
          _lcd_string(cBuffer);

    _lcd_data(58);              // 58 = :

    itoa(cMinuten, cBuffer, 10);
          _lcd_string(cBuffer);

    _lcd_data(58);              // 58 = :  

    itoa(cSekunden, cBuffer, 10);
          _lcd_string(cBuffer);

          _lcd_string("s");


    }

  }
}

Im Timer2 werden die Millisekunden gezählt, und bei Tausend wird von 
iGuthaben halt eins abgezählt. So sollte es eigentlich funktionieren... 
Ich hoffe der Code ist nicht zu lang um ihn hier reinzuschreiben...

gruß
Waldemar

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
habe jetzt hier keine Möglichkeit zu testen aber ich versteht nicht 
warum du überhaupt float verwendest?

Versuche es mal ohne float,

auch geht soetwas bestimmt etwas schöner
>(fTemp2-(3600*cStunden))/60;

schau dir mal das %(modulo) an.

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mhh, ja, kann sein... Für vorschläge bin ich gerne offen! Allerdings 
liegt es ja nicht an der Division!

Habs ausprobiert... Wenn ich diese Zeile auser Kraft setze schrumpft mir 
mein Code auf 16% Auslastung!!!

    fTemp2 = iGuthaben;           //Auslastung = 61%

//  fTemp2 = iGuthaben;           //Auslastung = 16%


... Bin ratlos ...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Waldemar T. schrieb:
> mhh, ja, kann sein... Für vorschläge bin ich gerne offen! Allerdings
> liegt es ja nicht an der Division!

Es gibt eine int->float Konvertierung. Das geht nicht in Hardware 
sondern in Software und braucht eben Platz.

Übrigens ist float hier Overkill, das geht alles mit int-Arithmetik. 
float ist bequem, aber eben auch platzfressend...

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich diese Zeile auser Kraft setze schrumpft mir mein Code auf 16%
> Auslastung!!!

Klar, dann ist nämlich fTemp2=0. Das weiß auch der Compiler, berechnet
die Ausdrücke in den folgenden drei Zeilen selbst und lässt nur noch
folgendes stehen:
    cStunden = 0;
    cMinuten = 0;
    cSekunden = 0;

Das braucht nicht viel Speicher :)

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So geht's übrigens ohne Float und ohne Temporärvariable:
    cStunden  = iGuthaben / 3600;
    cMinuten  = iGuthaben / 60 % 60;
    cSekunden = iGuthaben % 60;

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey, es geht! :) Ohne Platzfressen! :))

Könntest du mir bitte erklären, was der code macht, oder wo ich das 
nachlesen könnte (war mir bisher nicht bekannt...)

Autor: Waldemar T. (sanchez251)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yalu schrieb:

> Klar, dann ist nämlich fTemp2=0. Das weiß auch der Compiler, berechnet
> die Ausdrücke in den folgenden drei Zeilen selbst und lässt nur noch
> folgendes stehen:

> cStunden = 0;
> cMinuten = 0;
> cSekunden = 0;

> Das braucht nicht viel Speicher :)

Johann L. schrieb:

> Es gibt eine int->float Konvertierung. Das geht nicht in Hardware
> sondern in Software und braucht eben Platz.


Jetzt versteh ich das ganze auch... Wusste nicht, wie der Compiler das 
handhabt...

Habe früher in Assembler programmiert, da wurde eben befehl für befehl 
abgearbeitet... ;)

Gruß waldemar

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Könntest du mir bitte erklären, was der code macht, oder wo ich das
> nachlesen könnte (war mir bisher nicht bekannt...)

iGuthaben ist die Zeit in Sekunden, also z.B. 10000.

Eine Stunde hat 3600 Sekunden, also muss iGuthaben durch 3600
dividiert werden, um die Anzahl der Stunden zu erhalten:
    cStunden  = iGuthaben / 3600;

Da sowohl iGuthaben als auch 3600 Integer-Werte sind, wird auch die
Division in Integer durchgeführt und damit die Nachkommestellen
abgeschnitten, was in diesem Fall auch erwünscht ist. Im Beispiel ist
das Ergebnis 10000/3600=2.

Entsprechend ergibt iGuthaben / 60 die Anzahl der Minuten, im Beispiel
also 10000/60=166. Davon müssen aber noch die 2 Stunden (=120 Minuten)
von oben abgezogen werden, so dass 46 Minuten übrig bleiben. Statt von
den 166 Minuten die 120 Minuten abzuziehen, kann man auch die Modulo-
funktion (%-Operator in C) verwenden: 166%60 berechnet den Rest der
Division von 166 durch 60, was ebenfalls 46 ergibt. Das führt dann zu
dem zweiten Ausdruck:
    cMinuten  = iGuthaben / 60 % 60;

Die übrigen Sekunden, die noch nicht in den berechneten Stunden und
Minuten berücksichtigt sind, ergeben sich aus dem Rest der Division der
Gesamtsekundenanzahl durch 60, im Beispiel also 10000%60=40:
    cSekunden = iGuthaben % 60;

Also sind 10000 Sekunden = 2 Stunden 46 Minuten und 40 Sekunden.

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.