Forum: Mikrocontroller und Digitale Elektronik Programm zu groß für 1k Flash


von Dominik R. (vision)


Angehängte Dateien:

Lesenswert?

Hiho zusammen,

mein erstes etwas größeres uC-Projekt und irgendwie hakt es dauernd...
Mein aktuelles Problem ist, das das Programm zu groß geworden ist, 
nachdem ich alle Einzelteile zusammen gebaut habe.
Ich habe 1k Flash zur Verfügung, das Programm ist aber ca. 3k groß.
Liegt es an meiner umständlichen/ineffizienten Programmierung oder ist 
der Flash einfach nur zu klein für den Funktionsumfang?
Ich habe die '.c' mal angehängt. Vielleicht hat ja jemand kurz Zeit, 
sich das Gewurstel mal anzusehen...

Danke schonmal...

von Bernd N (Gast)


Lesenswert?

Welchen MSP verwendest du hier ? Optimizer angeschmissen ? Welcher C 
Compiler ?

von Dominik R. (vision)


Angehängte Dateien:

Lesenswert?

Sorry, falscher Stand der '.c'!!!
Hier noch einmal der aktuelle Stand.

von Max D. (max_d)


Lesenswert?

Wenns ein einzelstück sein soll: nimm nen größeren µC (wird vmtl. dann 
4kb werden)
Wenns Massenware sein soll: versuchs auf 2kb zu kriegen und nimm ne 2kb 
µC

Wenn du nicht grade mit debug-Optimierung und nur floating point 
berechnung gearbeitet hast, dann wirst du nie aus 3kb eines machen, da 
sind 2 schon sportlich.

von Dominik R. (vision)


Lesenswert?

Bernd N schrieb:
> Welchen MSP verwendest du hier ? Optimizer angeschmissen ? Welcher C
> Compiler ?

MSP ist der G2131, Optimierer auf kleinste Größe und Compiler ist der 
vom CCS.

von Daniel V. (danvet)


Lesenswert?

Ich kann mir nicht vorstellen, dass diese paar Zeilen 3k erzeugen.
Schau mal dein MAP-File an, was da noch alles drin ist.
Irgendwelche Libs dazugelinkt, die nicht gebraucht werden?

Ausserdem fehlt das While(1){} in der main.

: Bearbeitet durch User
von Udo S. (urschmitt)


Lesenswert?

Daniel V. schrieb:
> Ich kann mir nicht vorstellen, dass diese paar Zeilen 3k erzeugen.

So gings mir auch, ich habe auch mal kurz quer überflogen und habe weder 
floating point gefunden noch printf oder andere Dinge, die viel Platz 
brauchen.
Ich kenne die MSPs nicht, aber das bischen C Code gibt doch keine 3K?
Also MAP File, im Zweifel mal posten.

von Dominik R. (vision)


Lesenswert?

Ich habe zuletzt die "Dauermessung" mit dem WDT als Status-LED-Timer 
eingebaut.

Vorher hatte ich knapp 1k, jetzt bekomme ich 'ne Fehlermeldung, dass das 
Programm nicht in den Speicher passt und wenn ich die angegebene 
HEX-Zahl umrechne, bin ich bei gut 3kByte.
Andere LIBs hab ich nicht eingebunden...

Und die Endlosschleife habe ich weg gelassen, weil die bei den 
TI-Beispielen auch nicht da war, aber daran liegt es glaube ich auch 
nicht...

von Karl H. (kbuchegg)


Lesenswert?

Schreib das hier um
1
uint16_t wert10 = (uint16_t)(tarawert*0.1);
2
    uint16_t wert90 = (uint16_t)(tarawert*0.9);
so dass keine Floating Point Berechnung mehr auftaucht und dein 
Speicherverbrauch wird wieder sinken.

Du musst ja nicht mit 0.1 multiplizieren! Mal 10 durch 100 tuts auch. 
Mal 1 durch 10, bzw. mal 9 durch 10 ist noch besser, weil es die Gefahr 
eines Overflows während der Berechnung kleiner macht.
Aber diese beiden Multiplikationen ziehen einen ganzen Rattenschwanz mit 
ins Programm hinein.

: Bearbeitet durch User
von Dominik R. (vision)


Angehängte Dateien:

Lesenswert?

Hier ist noch das MAP.

von Dominik R. (vision)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Schreib das hier um
>
1
> uint16_t wert10 = (uint16_t)(tarawert*0.1);
2
>     uint16_t wert90 = (uint16_t)(tarawert*0.9);
3
>
> so dass keine Floating Point Berechnung mehr auftaucht und dein
> Speicherverbrauch wird wieder sinken.
>
> Du musst ja nicht mit 0.1 multiplizieren! Mal 10 durch 100 tuts auch.
> Mal 1 durch 10, bzw. mal 9 durch 10 ist noch besser, weil es die Gefahr
> eines Overflows während der Berechnung kleiner macht.
> Aber diese beiden Multiplikationen ziehen einen ganzen Rattenschwanz mit
> ins Programm hinein.

Das werde ich nachher ausprobieren. Hätte nicht gedacht, das *0.9 was 
anderes macht als /10 *9...

von Ralf G. (ralg)


Lesenswert?

Dominik R. schrieb:
> Das werde ich nachher ausprobieren. Hätte nicht gedacht, das *0.9 was
> anderes macht als /10 *9...

sogar *9/10 ist noch was anderes!

von Rolf Magnus (Gast)


Lesenswert?

Dominik R. schrieb:
> Das werde ich nachher ausprobieren. Hätte nicht gedacht, das *0.9 was
> anderes macht als /10 *9...

0.9 ist eine Gleitkommazahl, also muß die Bibliothek für 
Gleitkomma-Berechneungen bemüht werden. 10 und 9 sind dagegen nur 
Integers, brauchen das also nicht.

von Karl H. (kbuchegg)


Lesenswert?

Dominik R. schrieb:

> Das werde ich nachher ausprobieren. Hätte nicht gedacht, das *0.9 was
> anderes macht als /10 *9...

1
23 / 10   ->  2
2
              2 * 9  -> 18
3
4
5
23 * 9    -> 207
6
             207 / 10  -> 20
7
8
23 * 0.9  ->  20.7
9
10
11
18 != 20 != 20.7
12
3 verschiedene Ergebnisse, je nachdem wie man rechnet

Die Grundlagen der Datentypen und ihre Verwendung bzw. wie sie 
Berechnungen beeinflussen solltest du aber schon kennen, wenn du was 
programmierst.

: Bearbeitet durch User
von Daniel V. (danvet)


Lesenswert?

Dominik R. schrieb:
> Hier ist noch das MAP.

.text ist nur 0x3d4 gross, also 980 Byte.

Wie kommst du auf 3k? Eventuell ist dein Hexfile 3k gross. Lade doch das 
Programm einfachmal auf deinen uC....

von Daniel V. (danvet)


Lesenswert?

Dominik R. schrieb:
> Ich habe zuletzt die "Dauermessung" mit dem WDT als Status-LED-Timer
> eingebaut.
>
> Vorher hatte ich knapp 1k, jetzt bekomme ich 'ne Fehlermeldung, dass das
> Programm nicht in den Speicher passt und wenn ich die angegebene
> HEX-Zahl umrechne, bin ich bei gut 3kByte.
> Andere LIBs hab ich nicht eingebunden...
>
> Und die Endlosschleife habe ich weg gelassen, weil die bei den
> TI-Beispielen auch nicht da war, aber daran liegt es glaube ich auch
> nicht...

Hab ich jetzt erst gesehen.

Ich tippe:
Map-File und C-File passen nicht zusammen.

von Dominik R. (vision)


Lesenswert?

Kann sein, dass das map-file noch eins von dem stand ist, wo ich die 
"dauermessung" noch nicht drin hatte. Ich überprüfe das nachher noch 
einmal und lade die aktuelle map noch mal hoch. Sorry.

Das ein integer etwas anderes ist als ein float ist mir bewusst. Ich war 
nur davon ausgegangen, dass eine implizierte konvertierung durchgeführt 
wird, wenn man zwei integer dividiert, bei denen ein Rest übrig bleibt.

Ich werde nachher die ...*0.9 durch (.../9)*10 und die ...*0.1 durch 
.../10 ersetzen. Damit müsste ich ja Platz schaffen können. Vielleicht 
passt es dann ja schon wieder.

von Ralf G. (ralg)


Lesenswert?

Dominik R. schrieb:
> (.../9)*10

*9/10

Außer, du willst da jetzt was ganz anderes ausrechnen...

von Amateur (Gast)


Lesenswert?

Bei manchen C-Compilern muss man die Bibliotheken, die plötzlich nicht 
mehr benötigt werden explizit aus den Listen entfernen. Sonst werden sie 
weiterhin unnötig hinzu gelinkt, zumindest der Rumpf.

von Dominik R. (vision)


Angehängte Dateien:

Lesenswert?

Ralf G. schrieb:
> Dominik R. schrieb:
>> (.../9)*10
>
> *9/10
>
> Außer, du willst da jetzt was ganz anderes ausrechnen...

Ja, klar. *9/10 meinte ich.

Ich habe das jetzt auch geändert und bin somit auf 1258 Byte. Leider 
immer noch knapp 270 Byte zuviel... mal davon abgesehen, dass ich bisher 
immer dachte, 1 kByte wären 1024 Byte. Platz ist aber nur 992 Byte.

Noch irgend jemand 'ne Idee, wo man noch etwas optimieren kann?

Ach ja, hier noch das aktuelle Map-File.

von holger (Gast)


Lesenswert?

>  timerCount = (timerCount + 1) % 120;            //ca. 1 Min.

Mach da mal

 timerCount = (timerCount + 1) % 128;            //ca. 1 Min.

draus. Wird wohl egal sein obs etwas mehr als 1 Minute ist.

  volatile uint8_t m;
  for(m = 0; m < 60; m++){

Was soll das volatile da? Mach das weg.

von Karl H. (kbuchegg)


Lesenswert?

Wenn du deine Werte für ledstatus ein wenig intelligenter vergeben 
würdest, anstatt einfach von 0 beginnend durchzuzählen, dann würdest du 
dir hier
1
    switch(ledStatus){
2
      case 1:
3
        P1OUT ^= LED_GREEN;
4
        P1OUT |= LED_YELLOW + LED_RED;
5
        break;
6
      case 2:
7
        P1OUT &= ~LED_GREEN;
8
        P1OUT |= LED_YELLOW + LED_RED;
9
        break;
10
      case 3:
11
        P1OUT &= ~LED_YELLOW;
12
        P1OUT |= LED_GREEN + LED_RED;
13
        break;
14
      case 4:
15
        P1OUT &= ~LED_RED;
16
        P1OUT |= LED_GREEN + LED_YELLOW;
17
        break;
18
      case 5:
19
        P1OUT ^= LED_RED;
20
        P1OUT |= LED_GREEN + LED_YELLOW;
21
        break;
zb schon eine ganze Menge sparen.
Denn deine LED sind am Port sowieso an benachbarten Pins angeordnet, so 
dass du im Grunde nichts anderes tun musst, als ledStatus genau den 
binären 3-Bit Wert zu geben, den du ganz einfach am Port ausgeben 
kannst.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Irgendwie verteilst du volatile mit dem Gießkannanprinzip. Z.B. ist / 
messwert/ volatile und dann sowas. Das muß zu ineffizientem Code 
führen!
1
     if(messwert < 0){
2
          ledStatus = 1;
3
        }
4
        else if((messwert > 0) && (messwert < wert10)){
5
          ledStatus = 2;
6
        }
7
        else if((messwert > wert10) && (messwert < wert90)){
8
          ledStatus = 3;
9
        }
10
        else if((messwert > wert90) && (messwert < tarawert)){
11
          ledStatus = 4;
12
        }
13
        else if(messwert < tarawert){
14
          ledStatus = 5;
15
        }

von holger (Gast)


Lesenswert?

>Irgendwie verteilst du volatile mit dem Gießkannanprinzip.

Genau. Einfach einmal messwert in eine lokale Variable
holen und den ganzen Klimbim dann damit ausführen.
Sonst muss messwert ja jedesmal neu aus dem Speicher gelesen werden.

von Karl H. (kbuchegg)


Lesenswert?

So ganz hab ich noch nicht durchschaut, wozu du den Watchdog Timer 
benötigst.

Wenn ich das richtig sehe, dann ist der Watschdog doch sowieso nur an 
einer einzigen Programmsequenz aktiv - nämlich der Schleife in der die 
Messungen gemacht werden. An deren Ende steht aber ein delay. Da frage 
ich mich: Hä? Wozu der ganze Klimbim mit dem Watchdog - mach doch den 
Update der LEDs gleich in dieser Schleife und spar dir den ganzen 
Hackmack mit Watchdog aktivieren, konfigurieren und eigener ISR.
Oder übersehe ich da jetzt was?

: Bearbeitet durch User
von Dominik R. (vision)


Lesenswert?

Johann L. schrieb:
> Irgendwie verteilst du volatile mit dem Gießkannanprinzip. Z.B. ist /
> messwert/ volatile und dann sowas. Das muß zu ineffizientem Code
> führen!

Ja, stimmt schon.Ich bin mir halt unsicher, wann der Compiler vielleicht 
wichtige Dinge "wegoptimiert"...

Karl Heinz Buchegger schrieb:
> Denn deine LED sind am Port sowieso an benachbarten Pins angeordnet, so
> dass du im Grunde nichts anderes tun musst, als ledStatus genau den
> binären 3-Bit Wert zu geben, den du ganz einfach am Port ausgeben
> kannst.

da stehe ich jetzt etwas auf dem Schlauch. ledStatus 2 wäre dann z.B. 
0xC0 (also P1.7 HI, P1.6 HI, alles andere auf LO) oder wie muss ich mir 
das vorstellen?

von Dominik R. (vision)


Lesenswert?

Karl Heinz Buchegger schrieb:
> So ganz hab ich noch nicht durchschaut, wozu du den Watchdog Timer
> benötigst.
>
> Wenn ich das richtig sehe, dann ist der Watschdog doch sowieso nur an
> einer einzigen Programmsequenz aktiv - nämlich der Schleife in der die
> Messungen gemacht werden. An deren Ende steht aber ein delay. Da frage
> ich mich: Hä? Wozu der ganze Klimbim mit dem Watchdog - mach doch den
> Update der LEDs gleich in dieser Schleife und spar dir den ganzen
> Hackmack mit Watchdog aktivieren, konfigurieren und eigener ISR.
> Oder übersehe ich da jetzt was?

Ja, stimmt... vorher hatte ich den WDT auch noch für was anderes. Das 
ist aber irgendwann geändert worden und ich habe nicht daran gedacht, 
dass ich die LED-Anzeige dann ja auch ohne WDT machen kann...

von holger (Gast)


Lesenswert?

>Ja, stimmt schon.Ich bin mir halt unsicher, wann der Compiler vielleicht
>wichtige Dinge "wegoptimiert"...

Wer eine globale Variable "i" anlegt sollte sich um ganz andere
Dinge sorgen machen. Und diese ganzen Delays in den Interrupts.
Ganz klares NoGo.

von Dominik R. (vision)


Angehängte Dateien:

Lesenswert?

Das mit dem globalen i war nur ein Versuch, aus zwei Variablen, die ja 
auch etwas Speicher brauchen, eine zu machen, da ich an zwei Stellen 
eine Zähler-Variable brauchte, aber beide Stellen nie gleichzeitig 
zählen. Dass es das nicht gebracht hat, ist mir inzischen auch schon 
klar ;-)

Wo sollen die Delays denn sonst hin?

Anbei noch einmal die '.c' ohne WDT. Leider fehlen mir immer noch 148 
Bytes...

von ich kann lesen (Gast)


Lesenswert?

Man lese diesen Beitrag:
Beitrag "Re: MSP430G211 analoge Eingänge"
Der Code ist für ein Kundenprojekt. lol

Dem ganzen Projekt fehlt es an Struktur. Erst wurde die HW verbastelt, 
jetzt ist die SW dran.

Das bisschen Gefrickele passt doch locker in den 1k. Ein Blick in die 
Projektkonfiguration kann helfen.

von Dominik R. (vision)


Lesenswert?

ich kann lesen schrieb:
> Dem ganzen Projekt fehlt es an Struktur. Erst wurde die HW verbastelt,
> jetzt ist die SW dran.

Für die Hardware kann ich nunmal nichts, die habe ich so vorgegeben 
bekommen.
Und ja, jetzt ist die Software dran. Aber da ich wie gesagt noch ein 
ziemlicher Anfänger im Bereich uC bin und das eher als Hobby sehe, mit 
dem ich mir ein paar Euros dazu verdienen kann, weiss ich nicht, wo dein 
Problem ist.

Aber wenn du mir jetzt noch sagst, was ich in der Projektkonfiguration 
einstellen muss, damit das bisschen gefrickel auch in die 1k passt, wäre 
ich echt ein ganzes Stück weiter.

von ich kann lesen (Gast)


Lesenswert?

Daniel V. schrieb:
> Ausserdem fehlt das While(1){} in der main.

gute Frage,

Dominik R. schrieb:
> Und die Endlosschleife habe ich weg gelassen, weil die bei den
> TI-Beispielen auch nicht da war, aber daran liegt es glaube ich auch
> nicht...

falsche Antwort. Besser wäre: Aus dem LPM kommt der MSP nur per 
Interrupt. Nach Abarbeitung der ISR wird das Statuswort restauriert und 
damit wieder in den LPM geschaltet.

Karl Heinz Buchegger schrieb:
> spar dir den ganzen
> Hackmack mit Watchdog aktivieren, konfigurieren und eigener ISR.
> Oder übersehe ich da jetzt was?

Der Watchdog kann beim MSP als einfacher Timer genutzt werden.

von holger (Gast)


Lesenswert?

>Aber wenn du mir jetzt noch sagst, was ich in der Projektkonfiguration
>einstellen muss, damit das bisschen gefrickel auch in die 1k passt

Du kannst in den Projektoptionen nichts einstellen
was deinen vergurkten Code verbessert.

Die meisten deiner volatiles sind überhaupt nicht notwendig.
DA holst du dir dein Flash zurück.

von Dominik R. (vision)


Lesenswert?

holger schrieb:
>>Aber wenn du mir jetzt noch sagst, was ich in der Projektkonfiguration
>>einstellen muss, damit das bisschen gefrickel auch in die 1k passt
>
> Du kannst in den Projektoptionen nichts einstellen
> was deinen vergurkten Code verbessert.
>
> Die meisten deiner volatiles sind überhaupt nicht notwendig.
> DA holst du dir dein Flash zurück.

Die volatiles sind in der aktuellen Version gar nicht mehr drin.

ich kann lesen schrieb:
> Der Watchdog kann beim MSP als einfacher Timer genutzt werden.

Ich hatte den WDT als einfachen Timer genutzt, war aber - wie kbuchegg 
schrieb - gar nicht mehrnötig, also auch entfernt.

von hans (Gast)


Lesenswert?

Sind noch irgendwelche unnötigen Bib's drin?
Welche Variablen können vom Datentyp kleiner werden?
Auf gleiche Konstanten bei den Wartezeiten gehen!?
Delay über Timer?
Inlinefunktionen?
Anderer Algorithmus überlegen?
...

von ich kann lesen (Gast)


Lesenswert?

holger schrieb:
> Du kannst in den Projektoptionen nichts einstellen
> was deinen vergurkten Code verbessert.

:-D Das stimmt zu 100%!

Aber man kann einmal nachsehen, was noch so alles zum Kraut und Rüben 
Programm dazu kommt. ;-)

von holger (Gast)


Lesenswert?

>> Die meisten deiner volatiles sind überhaupt nicht notwendig.
>> DA holst du dir dein Flash zurück.
>
>Die volatiles sind in der aktuellen Version gar nicht mehr drin.

Ich habe nicht gesagt ALLE sollten kein volatile sein.
Wo ist denn der derzeitige Flash Bedarf?

von holger (Gast)


Lesenswert?

>Wo ist denn der derzeitige Flash Bedarf?

>Leider fehlen mir immer noch 148
>Bytes...

Ok Frage selber beantwortet;)

von Dominik R. (vision)


Lesenswert?

Ich verstehe nicht wirklich, wann der Compiler ggf. eine Variable 
wegoptimiert und diese somit als volatile gekennzeichnet werden muss...

von ich kann lesen (Gast)


Lesenswert?

Jetzt habe ich zum Spaß das Programm unverändert mit den 
Standardeinstellungen MAKEn lassen und
1
 984 bytes of CODE  memory
2
  62 bytes of DATA  memory (+ 20 absolute )
3
   3 bytes of CONST memory
4
5
Errors: none
6
Warnings: none

Geht doch!

von Daniel V. (danvet)


Lesenswert?

Dominik R. schrieb:
> Ich verstehe nicht wirklich, wann der Compiler ggf. eine Variable
> wegoptimiert und diese somit als volatile gekennzeichnet werden muss...

Der Compiler wird nur Variablen "wegoptimieren", die nicht verwendet 
werden.

Hier aber wird er optimieren (nicht "wegoptimieren"):

Johann L. schrieb:
> if(messwert < 0){
>           ledStatus = 1;
>         }
>         else if((messwert > 0) && (messwert < wert10)){
>           ledStatus = 2;
>         }
>         else if((messwert > wert10) && (messwert < wert90)){
>           ledStatus = 3;
>         }
>         else if((messwert > wert90) && (messwert < tarawert)){
>           ledStatus = 4;
>         }
>         else if(messwert < tarawert){
>           ledStatus = 5;
>         }

"messwert" wird EINMAL in ein Register eingelesen und dann wird mit dem 
Register gerechnet.
Falls du "messwert" als volatile definiert hast, wird der Compiler 
"messwert" bei jedem Vergleich neu in ein Register lesen. Das macht die 
Kiste langsamer und den Code grösser.

Falls sich "messwert" während diesem Vergleich ändern kann (z.B. wenn 
die Variable in einem Interrupt verändert wird) UND du möchtest, dass 
immer mit dem aktuellen Wert gerechnet wird, dann ist "volatile" 
angesagt.
Ansosnten kannst du dir "volatile" sparen.

von Purzel H. (hacky)


Lesenswert?

>Ja, stimmt schon.Ich bin mir halt unsicher, wann der Compiler vielleicht
wichtige Dinge "wegoptimiert"...

Sowas gibt es gar nicht, resp darf es nicht geben. Das ist das 
Wichtigste. Man muss sich drauf verlassen koennen, dass das geschieht, 
was man will. Deswegen ist Debuggen auch Teil des Entwicklungsprozesses, 
und nicht etwas Unerwuenschtes, das man leider nachher noch anfuegen 
muss.

von Dominik R. (vision)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,

ich habe es leider immer noch nicht geschafft, das Programm so weit zu 
verkleinern, dass es in den uC-Speicher passt.

Auch diese Aussage hilft nicht wirklich weiter:

ich kann lesen schrieb:
> Jetzt habe ich zum Spaß das Programm unverändert mit den
> Standardeinstellungen MAKEn lassen und 984 bytes of CODE  memory
>   62 bytes of DATA  memory (+ 20 absolute )
>    3 bytes of CONST memory
>
> Errors: none
> Warnings: none
>
> Geht doch!

984+62+3 = 1049 Bytes => zu groß für den 992 Byte großen Speicher (oder 
wird DATA und CONST nicht im Flash abgelegt?)

Vielleicht kannst du mir auch noch sagen, was du für ein Compiler 
benutzt hast, denn wenn ich den Code mit CCS 5.5 und den 
Standardeinstellungen kompiliere, ist das Programm doch noch etwas 
größer.

Ich habe den Code noch weiter bearbeitet, so dass ich mit meinen 
Einstellungen auf 1060 Byte komme. So sind es aber leider immer noch 68 
Byte zuviel. Ich habe den aktuellen Stant noch einmal angehängt. Gibt es 
noch weiteres Einsparungspotential?

Da ich noch nicht so lange in C und mit Mikrocontrollern arbeite, würde 
ich auch gerne wissen, was strukturell vielleicht noch verbessert werden 
könnte. Ja, ich weiss, dass man von Interrupt-Routinen aus keine 
Methoden aufrufen sollte, schon gar nicht mit Delays, aber wenn ein 
Interrupt verschluckt wird, ist das hier nicht sooo tragisch. Außerdem 
weiss ich nicht, wie ich es besser machen sollte. Ist es ok, erst das 
Flag zu clearen und dann eine Methode aus der ISR heraus aufzurufen?

Was mir an meinem Code gar nicht gefällt ist diese if ... 3x else if ... 
else Katastrophe, aber ich habe auch keine Idee, wie ich das eleganter 
lösen sollte...

Danke schonmal.

von Hans Klein (Gast)


Lesenswert?

Dominik R. schrieb:
> Was mir an meinem Code gar nicht gefällt ist diese if ... 3x else if ...
> else Katastrophe, aber ich habe auch keine Idee, wie ich das eleganter
> lösen sollte...

Das ist nun wirklich das allerkleinste Problem an dem Code ...

Ganz ernst gemeinter Rat: Lösch den Murks und schreib es nochmal. Nimm 
es auch nicht als Vorlage für ein neues Programm. Fang nochmal mit einer 
leeren Datei an und schreib es ohne Interrupts und volatile, einfach 
geradeaus mit Polling. Danach ist das Programm nur noch halb so groß, 
verständlich und funktioniert auch sauber.

von Amateur (Gast)


Lesenswert?

Der Gedanke das obige Programm ins Flash zu bekommen, wo scheinbar nur 
noch so wenig "abzuschneiden" ist, ist aus sportlicher Sicht bestimmt 
reizvoll.
Bedenke aber bitte folgendes:
- Durch trickreiche Konstrukte kann man einiges an Speicher sparen,
  aber die Wartbarkeit auf null drücken.
- Bist Du Dir 100% sicher, das, kaum dass es passt, nicht noch
  irgendwas nachgerüstet werden muss? Dann landest Du nämlich auf
  direktem Weg in der Abteilung: "Typischer Fall von Denkste". Die
  liegt übrigens gleich neben der Abteilung: "Außer Spesen nix
  gewesen".

von Dominik R. (vision)


Lesenswert?

Ganz ohne Interrupts wird es nicht gehen, da sich der uC im LPM befinden 
soll, wenn gerade nich gemessen wird. Ich hab da keinen Schimmer, wie 
ich das umsetzen sollte.

Und nur, damit ich es das nächste Mal besser machen kann - was ist denn 
besonderer Murks (mal abgesehen von den Delays, die aus den ISR 
aufgerufen werden)? - vielleicht habe ich die rosarote Brille auf oder 
noch zu wenig Plan von C, aber ist es echt soo schlimm?

: Bearbeitet durch User
von ich kann lesen (Gast)


Lesenswert?

Dominik R. schrieb:
> wird DATA und CONST nicht im Flash abgelegt?

Richtig, DATA ist RAM.

Das Ganze wurde mit dem IAR erstellt. Aber auch das hilft dir nicht. Das 
Programm ist bestimmt noch nicht fertig, du brauchst mehr Speicher.

Dominik R. schrieb:
> Gibt es
> noch weiteres Einsparungspotential?

Sind die ganzen delays nötig? In einer ISR wird 5s gewartet!
Da würde ich dringend den Ablauf und die Struktur überdenken.

von Dominik R. (vision)


Lesenswert?

ich kann lesen schrieb:
> In einer ISR wird 5s gewartet!

Die LED soll 5s leuchten, bevor der Wert gespeichert wird. Und da in der 
Zeit weder auf Taster noch auf Timer reagiert werden soll, dachte ich, 
das das Delay in der ISR ok ist.

Aber wenn das Programm auf biegen und brechen nicht in den uC passt, 
hilft das alles nichts...

von holger (Gast)


Lesenswert?

>Gibt es noch weiteres Einsparungspotential?

Ja, gibt es. Mach keine Berechnungen oder Vergleiche
mit volatile Variablen. Vermeide überflüssige Berechnungen.
1
  uint16_t tmptara = tarawert;
2
  uint16_t tmpnullwert = nullwert;
3
4
  uint16_t wert10 = (tmptara-tmpnullwert)/10;      // wert10 = Schwelle 1 (10% Tara)
5
   uint16_t wert90 = ((tmptara-tmpnullwert)*9)/10;    // wert90 = Schwelle 2 (90% Tara)
6
7
  for(m=60; m > 0; m--)
8
  {                  // 15 Sek. messen (alle 1/4 Sek.)
9
    int16_t messwert = messung(2)-tmptara;
10
    P1OUT |= LED_GREEN + LED_YELLOW + LED_RED;      // alle LEDs aus
11
    if(messwert < 0)
12
    {
13
      if(++b == 2)
14
      {                  // bei jedem 2. Durchlauf LED an (blinken)
15
        P1OUT &= ~LED_GREEN;
16
        b = 0;
17
      }
18
    }
19
    else if(messwert < wert10)
20
    {
21
      P1OUT &= ~LED_GREEN;
22
    }
23
    else if(messwert < wert90)
24
    {
25
      P1OUT &= ~LED_YELLOW;
26
    }
27
    else if(messwert < tmptara)
28
    {
29
      P1OUT &= ~LED_RED;
30
    }
31
    else if(messwert > tmptara)
32
    {
33
      if(++b == 2)
34
      {
35
        P1OUT &= ~LED_RED;              // bei jedem 2. Durchlauf LED an (blinken)
36
        b = 0;
37
      }
38
    }
39
    else
40
    {
41
      P1OUT |= LED_GREEN + LED_YELLOW + LED_RED;
42
    }
43
    delay_ms(250);
44
  }

von Dominik R. (vision)


Lesenswert?

Danke für den Hinweis. Natürlich muss wert10 und wert90 nicht 60 mal 
berechnet werden. Hätte ich auch früher mal sehen können.

Hat 8 Byte gebracht. Bleiben leider immer noch 60 über. Ich denke, das 
wird nichts mehr.

Ist volatile bei den beiden Variablen überhaupt notwendig? Ich bin mir 
da nicht so ganz sicher. Normalerweise muss man ja volatile deklarieren, 
wenn sich der Wert einer Variablen während der Verarbeitung durch eine 
andere ISR ändern könnte, oder? Aber eigentlich kann / soll sich der 
Wert der beiden Variablen an der Stelle der Berechnung gar nicht ändern. 
Also ist Volatile hier notwendig?

: Bearbeitet durch User
von Hans Klein (Gast)


Lesenswert?

Dominik R. schrieb:
> Ganz ohne Interrupts wird es nicht gehen, da sich der uC im LPM
> befinden
> soll, wenn gerade nich gemessen wird. Ich hab da keinen Schimmer, wie
> ich das umsetzen sollte.

Ich kenne den Controller nicht, aber es sollte doch ausreichen, wenn er 
per Interrupt geweckt wird und dadurch wieder in die Hauptschleife 
springt? Der Interrupt selber muss dann gar nichts machen.

> Und nur, damit ich es das nächste Mal besser machen kann - was ist denn
> besonderer Murks (mal abgesehen von den Delays, die aus den ISR
> aufgerufen werden)? - vielleicht habe ich die rosarote Brille auf oder
> noch zu wenig Plan von C, aber ist es echt soo schlimm?

Äußerlich:
- Unsaubere Codeformatierung (fehlende Leerzeichen vor Klammern und 
teilweise in Ausdrücken)
- Unheitliche Bezeichner (timerCount, daycount), Deutsch und Englisch 
gemischt
- Unklare Bezeichner (interval15, praktisch alle Funktionsnamen)

Technisch:
- Kein static vor den Hilfsfunktionen (hier: alle außer main) und den 
Modulvariablen (hier: alle globalen Variablen). Alleine das könnte schon 
zur Größenreduktion reichen.
- Globale Variablen statt lokale (statische) Variablen. Z.B. wird 
timerCount nur in der ISR Timer_A benutzt, würde also als 
static-Variable in diese Funktion gehören.
- Unsinnige volatiles. Wie gesagt, ohne Interrupts bräuchte man 
überhaupt keine. Falls man eine volatile-Variable in einer Funktion mehr 
als einmal benutzt, lohnt es sich, sie in eine lokale Variable 
umzukopieren und nur mit der lokalen Variable zu arbeiten. Das kann der 
Compiler dann optimieren.
- Unklarer Programmfluss durch willkürliche Funktionen mit unklaren 
Namen. Normalerweise sollte alleine durch den Prototyp einer Funktion 
(Name, Rückgabewert, Parameter) klar sein, was sie tut und möglichst 
keine globalen Variablen verändern. Bei der Funktion "void 
dauerMessung(void)" ist exakt das Gegenteil der Fall ...

Ich weiß, gerade letzteres ist als Anfänger nicht so einfach zu 
erreichen, dazu braucht man Erfahrung. Bevor man aber willkürlich 
irgendwelche Funktionen definiert, halte ich es dann immer noch für 
besser, zunächst mal den kompletten Kontrollfluss in eine Funktion zu 
packen und die einzelnen Abschnitte sinnvoll zu kommentieren.

Wenn man darin dann einen Teil erkennt, der eine in sich geschlossene 
Funktionalität darstellt, am besten mit wenigen Eingabeparametern, ohne 
Nebenwirkungen und mit einem Ergebnis, das man zurückgeben kann, dann 
macht man daraus eine Funktion. Deren Name sollte mit einem Verb 
beginnen und genau das beschreiben was sie tut. Und sie darf dann auch 
nur genau das machen und nichts anderes. Nur so erhält man sinnvolle 
Funktionen, die beim Verständnis des Codes helfen.

Zuletzt dann noch die Delays ... Die will man eigentlich auch nicht 
haben, schon gar nicht im Interrupt. In einem einfachen Programm, das 
sonst nichts machen muss, als eine lineare Befehlsfolge abarbeiten, sind 
sie aber OK. Nur dann wie gesagt bitte keine Interrupts, das passt 
schlichtweg nicht zusammen.

von Dominik R. (vision)


Lesenswert?

Danke für die Hinweise. Ich werde die Ratschläge beherzigen und noch 
einmal versuchen, eine Poll-Version zu machen, die dann evtl. auch etwas 
kleiner ausfällt.

Ich wünsche noch eine gute Nacht.

von Martin H. (disjunction)


Lesenswert?

Probier mal statt
X &= ~BUTTON_T;

X &= ~(unsigned char) BUTTON_T

Das ergibt bei manchen Prozessorn aus einer "Oder" Operation eine 
Bitoperation

von Optimist (Gast)


Lesenswert?

Martin H. schrieb:
> Probier mal statt
...

Das sollte ein guter Compiler von selbst erkennen und optimieren.

von Martin H. (disjunction)


Lesenswert?

Dann frage ich mich, warum moderne Kompiller wie Keil für ihre 
Konstanten stets Typen für ihre Konstanten angeben.
1
// Flash Control Register definitions
2
#define FLASH_PG                ((unsigned int)0x00000001)
3
#define FLASH_SER               ((unsigned int)0x00000002)

Mein Tip war also vieleicht nicht hifreich, aber sicherlich nicht 
unnötig.

von Optimist (Gast)


Lesenswert?

Martin H. schrieb:
> für ihre
> Konstanten stets Typen für ihre Konstanten angeben

???

Martin H. schrieb:
> sicherlich nicht
> unnötig

Wo besteht der Zusammanhang mit Konstanten?
Oder meinst du, dass daraus durch den Cast eine Variable wird? ;-)))

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.