Guten Morgen,
Ich bin zurzeit wieder am weiter programmieren meiner Wetterstation. Und
wollte gerne noch eine Anzeige Modus hinzufügen wo man die Minimale
Temperatur und die Maximale Temperatur sehen. Als ich es dann kompiliert
habe, kam im Atmel Studio 7 unten eine Fehler Nachricht. Dieses sieht so
aus:
Programm Memory Usage: 12788 bytes 39,0 % Full
Programm Memory Usage: 12788 bytes 39,0 % Full
Data Memory Usage: 2054 bytes 100,3 % Full (Memory
Overflow)
Hier nochmal als Bild: http://prntscr.com/bhug6u
Ich verwende denn ATMega328P mit 16 Mhz. Soweit ich weis und auch
gesehen wenn ich bei einen neuen Projekt denn Controllor auswähle, hat
dieser ein App./Boot Memory von 32 KBytes. Und auch im Datenblatt steht
das dieses 32 Kbytes hat.
Muss ich da vorher noch was einstellen damit ich mehr nutzen kann? Ein
anderen Controllor in meine Platine einzubauen ist nicht möglich. Da für
ein ATMega644 oder ATMega32/16 kein Platz ist.
Mfg Felix.
> Data Memory Usage: 2054 bytes 100,3 % Full (Memory Overflow)
Die Meldung bezieht sich nicht auf den Flash-Speicher (32 KBytes)
sondern auf das RAM (2 Bytes).
Felix N. schrieb:> Data Memory Usage: 2054 bytes 100,3 % Full (Memory> Overflow)
Das ist dein RAM, und der ist voll! Die 32 KB sind dein Flash-Speicher.
Flashspeicher != RAM Speicher!
klausr schrieb:> Das ist dein RAM, und der ist voll! Die 32 KB sind dein Flash-Speicher.> Flashspeicher != RAM Speicher!
Ja okay. Aber im RAM werden doch nur Temporäre Daten gespeichert. Und
nix dauerhaft.
Und was kann ich dagegen jetzt machen?
Felix N. schrieb:> Data Memory Usage: 2054 bytes 100,3 % Full (Memory> Overflow)
schaffe Platz im RAM
Texte aus dem Flash direkt
globale Variablen verringern, auf lokale umsteigen wo möglich
Platz für Variablen reservieren die mehrere Functions nutzen können
usw.
zeig mal deinen Code der alles RAM verbraucht
Joachim B. schrieb:> schaffe Platz im RAM>> Texte aus dem Flash direkt> globale Variablen verringern, auf lokale umsteigen wo möglich> Platz für Variablen reservieren die mehrere Functions nutzen können>> usw.>> zeig mal deinen Code der alles RAM verbraucht
Jo, aber nicht erschrecken es ist nicht grade wenig Code
Baltin schrieb:> Warum wird das Array mit 100 Bytes angelegt?
Ääää, weis nicht habe mal 1 mit 100 angelegt und dann immer wieder.
Reduziere sie mal auf 2 Bytes
wie vermutet, zuviel globales Zeugs!
Kann man ja machen wenn man SRAM ohne Ende hat, so aber nicht mit nur 2K
ich tippe mal deine ganzen lcd_print Texte brauchen auch RAM, die sollte
im freien Flash liegen und per strcpy_P nur bei Bedarf in eine
leerzeile_str kopiert werden
Es hat keinen Sinn für jede Ausgabe einen extra Stringbuffer
zu reservieren. Er braucht auch maximal so gross sein wie
die Zeilenlänge des Displays.
also mache
Deine Variable wie readingTemp, etc verbraten alle jeweils 100 Bytes
RAM. Gehe den Code durch und überlege dir wie viele Bytes du maximal
benötigst, und verringere die Größe der Arrays entsprechend.
Andere arrays wie z.B. minuten[10] ist wiederum zu kurz für die Daten
die du hinein schreibst und muss vergrößert werden.
Warum du in der Funktion avg_measurement() den selben Code 10 mal
hintereinander kopiert hast ist mir auch nicht ganz ersichtlich. Hier
kann man mit einer Schleife den code sicherlich verkürzen.
Der Tipp mit Strings in den flash verlegen wurde oben schon erwähnt. Wie
das geht findest du im AVR-GCC Tutorial. Jeder deiner Strings liegt im
RAM und verbraucht dort kostbaren Platz. Hier hast du auch oft quasi den
selben String mehrfach im RAM(z.B. in avg_measurements()), wo sich der
selbe String nur um eine Ziffer unterscheidet.
Joachim B. schrieb:> wie vermutet, zuviel globales Zeugs!>> Kann man ja machen wenn man SRAM ohne Ende hat, so aber nicht mit nur 2K>> ich tippe mal deine ganzen lcd_print Texte brauchen auch RAM, die sollte> im freien Flash liegen und per strcpy_P nur bei Bedarf in eine> leerzeile_str kopiert werden
Habe mal die ganzen Array auf 1 Byte gekürzt. Dann ich ja eh nur 1 Wert
reinschreibe. Und zak nur noch 69,5 % des RAM verwendet.
Keine Ahnung ob die lcd_print sachen in denn RAM schreiben: So sieht der
Code dazu aus: http://prntscr.com/bhuoh5
Thomas M. schrieb:> Jeder deiner Strings liegt im> RAM und verbraucht dort kostbaren Platz.
Kann man nicht mit free() denn RAM wieder freigeben von einer Methode.
Werde mal die avg_measuremnt mit einer vorschleife kürzen
Felix N. schrieb:> Keine Ahnung ob die lcd_print sachen in denn RAM schreiben:
ne die sind es nicht, es ist dein:
lcd_printlc(1, 1, "Das Ergebnis wird");
könnte man auch umformen
//globale LCD Zeile
char leerzeile[50]={0}; // Größe nach maximaler Zeichenlänge+1, global
vor PRG
strcpy_P(leerzeile, "Das Ergebnis wird");
lcd_printlc(1, 1, leerzeile);
Joachim B. schrieb:> könnte man auch umformen>> //globale LCD Zeile>> char leerzeile[50]={0}; // Größe nach maximaler Zeichenlänge+1, global> vor PRG>> strcpy_P(leerzeile, "Das Ergebnis wird");> lcd_printlc(1, 1, leerzeile);
Verbraucht dieses genau dieses Satz mehr RAM? Als die anderen?
Felix N. schrieb:>> strcpy_P(leerzeile, "Das Ergebnis wird");
Dort meckert er mit expected ')' before '(' token
Frickelfritze schrieb:> und mache deine ganzen Ausgaben in dieses Feld.
Wie meinst du das?
U. F. schrieb:> Deine ISR macht einen überladenen Eindruck!>> Auch sehe ich kein einziges "volatile".> Ich schätze mal, das wird auch noch für Fehlfunktionen sorgen.
1
while(1){
2
}
bei einer leeren Hauptschleife kann es keine Probleme mit Variabel in
der ISR geben.
U. F. schrieb:> Deine ISR macht einen überladenen Eindruck!
Ich nutze mit Absicht denn Overflow Timer. Damit ich zusätzlich noch mit
_delay_ms() arbeiten kann. Deswegen steht in der Hauptschleife auch nix
drin
Frickelfritze schrieb:> neu:> ............> sprintf(temp_str, "%d ms", basicTempTime);> lcd_printlc(3, 1, temp_str);> ............> sprintf(temp_str, "%d ms", basicMeasurementTime);> lcd_printlc(3, 1, temp_str);
Aso, du meinst einen Temporären String zu haben und diesen immer wieder
neu beschreiben.
Felix N. schrieb:> Aso, du meinst einen Temporären String zu haben und diesen immer wieder> neu beschreiben.
Genau das, so wie hier schon beschrieben.
Frickelfritze schrieb:> Es hat keinen Sinn für jede Ausgabe einen extra Stringbuffer> zu reservieren.
Frickelfritze schrieb:> Genau das, so wie hier schon beschrieben.>> Frickelfritze schrieb:>> Es hat keinen Sinn für jede Ausgabe einen extra Stringbuffer>> zu reservieren.
Ja kommt glaubig daher. Das ich bevor ich mit den Controllor angefangen
bin Java programmiert habe. Und dort für jede Sache eine Variable
angelegt zu habe. Denn beim Rechner mit ca. 4 bis 16 GB RAM ist das auch
so zimmlich egal ob er jetzt 500 mb oder 1 gb belegt. Aber ich habe nun
auch mal Variablen die ich nur innerhalb einer Methode benötige aus der
Globalen List oben entfernt und in die Funktion rein gepackt. So sind es
ja auch nur Temp Variablen oder?
Was hat das eigentlich mit diesen volatile auf sich. Ist das wichtig?
Felix N. schrieb:> Was hat das eigentlich mit diesen volatile auf sich. Ist das wichtig?
das die ISR die Variable immer liest und nicht welche aus dem Cache
nimmt.
Das ist wichtig das wirklich die Variable immer in der richtigen
Unterroutine mit den stimmigen Daten genommen wird.
Sub 1 x=10
ISR x++
ohne volatile ist in Sub 1 immer noch x=10
volatile kann man aber auch mal gurgeln
https://de.wikipedia.org/wiki/Volatile_(Informatik)
Joachim B. schrieb:> das die ISR die Variable immer liest und nicht welche aus dem Cache> nimmt.
Käse.
Es gibt beim Arduino (besser gesagt bei den AVR Controllern)
keinen Cache.
Joachim B. schrieb:> das die ISR die Variable immer liest und nicht welche aus dem Cache> nimmt.
Cache kann man gurgeln. Solltest du mal machen.
> volatile kann man aber auch mal gurgeln>> https://de.wikipedia.org/wiki/Volatile_(Informatik)
Scho ma deinem eigenen Link gefolgt? Solltest du ma mmachen.
kerle schrieb:> Cache kann man gurgeln. Solltest du mal machen.
Krümelkacker, ob das nun cache oder var auf dem Stack oder aus dem
Register r17 genannt wird ändert doch nix am Sachverhalt mit volatile
dem Compiler oder den Nachbarn anzuweisen die Variable immer neu
einzulesen.
kerle schrieb:> Scho ma deinem eigenen Link gefolgt? Solltest du ma mmachen.
ja, für dich den Tip an deinem Leseverständnis zu arbeiten, wenns dir
nicht wichtig ist werde Schaumschläger.
Joachim B. schrieb:> das die ISR die Variable immer liest und nicht welche aus dem Cache> nimmt.Arduinoquäler schrieb:> Käse.>> Es gibt beim Arduino (besser gesagt bei den AVR Controllern)> keinen Cache.kerle schrieb:> Cache kann man gurgeln. Solltest du mal machen.
Wenn Ihr beiden Trolle nicht imstande seid, zu verstehen was er
sagen wollte, solltet ihr euch auch nicht zu Wort melden.
Joachim B. schrieb:> kerle schrieb:>> Cache kann man gurgeln. Solltest du mal machen.>> Krümelkacker, ob das nun cache oder var auf dem Stack oder aus dem> Register r17 genannt wird ändert doch nix am Sachverhalt mit volatile> dem Compiler oder den Nachbarn anzuweisen die Variable immer neu> einzulesen.
Den tatsächlichen Sachverhalt im ATMega328p sollte man bei deiner
Antwort aber schon kennen, sonst hinterläßt sie mehr Verwirrung als
Klärung.
> kerle schrieb:>> Scho ma deinem eigenen Link gefolgt? Solltest du ma mmachen.>> ja, für dich den Tip an deinem Leseverständnis zu arbeiten, wenns dir> nicht wichtig ist werde Schaumschläger.
Danke an ufuf, der die Ursache für das Versagen des Links bei Anklicken
aufgeklärt hat. Du hast es ja nicht mal in deinem eigenen Post bemerkt.
Deine Antwort war einfach nur aufgeschlagener Schaum, dem man nur wegen
den daraus folgenden richtigstellenden Posts Berechtigung einräumen
könnte.
> Krümelkacker> aufgeschlagener Schaum
Es wäre ja zu schön gewesen, und eigentlich war alles bis zur 8. Antwort
geklärt.
Aber dann kommen die Rindviecher raus und meinen, sie müssten muhen.
Wieder mal ein schönes Beispiel für die Sozialkompetenz in diesem Forum.
kerle schrieb:> Danke an ufuf, der die Ursache für das Versagen des Links bei Anklicken> aufgeklärt hat
OK das mit den Links hier ist mir auch schon öfter aufgefallen und ja
ich hatte meinen Link vor dem Einstellen hier angeklickt nur nicht nach
dem Einstellen! (Nach der ersten Antwort kann man den "Fehler" nicht
mehr korrigieren)
Cowboy schrieb:> Wieder mal ein schönes Beispiel für die Sozialkompetenz in diesem Forum.
stimmt!
Cowboy schrieb:> Aber dann kommen die Rindviecher raus und meinen, sie müssten muhen.
und die "Cowboys" muhen mit.
> Wieder mal ein schönes Beispiel für die Sozialkompetenz in diesem Forum.
Dazu sage ich jetzt mal nichts weiter.
Hab schon besser kommentierten Quelltext gesehen.
Wenn man häufig sich wiederholende Routinen benötigt
wo sich nur EIN Datum ändert, kann man sicher einen
besseren Algorithmus programmieren, der das alles
zusammenfasst.
Felix N. schrieb:> Keine Ahnung ob die lcd_print sachen in denn RAM schreiben: So sieht der> Code dazu aus: http://prntscr.com/bhuoh5
Was meinst, wozu es hier die Funktion "Dateianhang" gibt?
Das meiste RAM verbrauchen sicher die Text-Literale, die beim AVR-GCC
ohne Überredung eben dort landen. Liegt an Harward vs. Neumann.
So wird der String im FLASH abgelegt und nur zu Weiterverarbeitung ins
RAM geladen:
1
#include<avr/pgmspace.h>
2
3
intfoo()
4
{
5
charstring_im_ram[40];
6
7
strcpy_P(string_im_ram,PSTR("Hallo Welt"));
8
}
Eventuell hat die LCD-Lib ja eine lcd_printstr_P() Funktion, die direkt
aus dem FLASH liest. Wenn nicht ist die nicht schwer zu bauen. Das Makro
PSTR() sorgt dafür das das String-Literal im FLASH landet.
Die ersten grob 700 Byte gehen in überflüssigen Puffern verloren, dann
noch mal ΠxDaumen 1000 Byte. Es werden also statisch 300 Byte gebraucht.
Wobei bedacht werden muß, das nichtstatisch sowas wie Stack zu den
anfänglichen 100,3% noch dazukommt.
@Carl Drexler (jcw2)
>Eventuell hat die LCD-Lib ja eine lcd_printstr_P() Funktion, die direkt>aus dem FLASH liest. Wenn nicht ist die nicht schwer zu bauen. Das Makro>PSTR() sorgt dafür das das String-Literal im FLASH landet.
#include "i2c.h"
#include "lcd.h"
Das ist mit hoher Wahrscheinlichkeit diese Library, sei es das Original
oder die von mir aufpolierte Version.
Beitrag "Re: I2CLCD Library für HD44780 LCDs"
Man ersetzte die Funktionsaufrufe lcd_printlc durch lcd_printlc_P
Aus
lcd_printlc(1, 1, "Wetterstation:");
wird
lcd_printlc_P(1, 1, PSTR("Wetterstation:"));
Weiterhin sollte man
sprintf(readingTemp, "Temp: +%-.2f *C", currentTemp);
durch
sprintf_P(readingTemp, PSTR("Temp: +%-.2f *C"), currentTemp);
ersetzen, damit landen die Formatstrings auch direkt im Flash, ohne
zusätzlich RAM zu verschwenden.
Und daß EIN einziger String für alle variablen Ausgaben reicht, wurde ja
nun schon mehrfach gesagt. Der muss auch nicht länger als eine LCD-Zeile
+ Terminator sein, d.h. 21 Zeichen sind ausreichend.
Man kann das Programm auch noch deutlich straffen, denn Programmierer
sind nicht nur (tipp)faul, sie sind auch im allgemeinen
Effizienzfanatiker ;-)
1
voidtempSavePage(void){
2
lcd_clear();
3
lcd_printlc_P(1,1,PSTR("Settings Page 1/2"));
4
lcd_printlc_P(2,1,PSTR("Delay Temperatur"));
5
lcd_printlc_P(3,1,PSTR("Speichere...."));
6
_delay_ms(750);
7
uint8_twriter=0x00;
8
9
switch(basicTempTime)(
10
case250:writer=0x01;break;
11
case500:writer=0x02;break;
12
case750:writer=0x03;break;
13
case1000:writer=0x04;break;
14
case1250:writer=0x05;break;
15
case1500:writer=0x06;break;
16
case1750:writer=0x07;break;
17
case2000:writer=0x08;break;
18
case2250:writer=0x09;break;
19
case2500:writer=0x10;break;
20
case2750:writer=0x11;break;
21
case3000:writer=0x12;break;
22
}
23
lastTempState=basicTempTime;
24
writeEEPROM(12,writer);
25
lcd_printlc_P(4,1,PSTR("Gespeichert!"));
26
_delay_ms(1000);
27
loadSettings();
28
}
Oder noch einfacher, wenn man ein bisschen Mathematik versteht ;-)
1
voidtempSavePage(void){
2
lcd_clear();
3
lcd_printlc_P(1,1,PSTR("Settings Page 1/2"));
4
lcd_printlc_P(2,1,PSTR("Delay Temperatur"));
5
lcd_printlc_P(3,1,PSTR("Speichere...."));
6
_delay_ms(750);
7
uint8_twriter;
8
9
if(basicTempTime<2500){
10
writer=basicTempTime/250;
11
}else{
12
writer=(basicTempTime/250)+6;
13
}
14
15
// ist das WIRKLICH so gewünscht oder eher ein Tippfehler?
16
// Soll 0x01-0x12 rauskommen (HEXADEZIMAL!)
17
// oder eher 1-12 (DEZIMAL)?
18
19
lastTempState=basicTempTime;
20
21
writeEEPROM(12,writer);
22
lcd_printlc_P(4,1,PSTR("Gespeichert!"));
23
_delay_ms(1000);
24
loadSettings();
Diese Arien an mehreren Stellen mit einem Dutzend if() else() kann man
so leicht wegrationalisieren. Das spart nicht nur massiv Tipperei,
sondern bringt vor allem Übersicht.
Falk B. schrieb:> Aus>> lcd_printlc(1, 1, "Wetterstation:");>> wird>> lcd_printlc_P(1, 1, PSTR("Wetterstation:"));>> Weiterhin sollte man>> sprintf(readingTemp, "Temp: +%-.2f *C", currentTemp);>> durch>> sprintf_P(readingTemp, PSTR("Temp: +%-.2f *C"), currentTemp);
Hallo Falk.
Nach diesen Änderungen im Code ist das alles nur am Buggen. Beim
verändern des Delays der Temperatur wenn ich dort um -250 verkleinern
will kommt dort "/no to change" in die Zeile. + 250 Addieren geht aber.
Beim Delay für das Measurment funktioniert es problemlos.
Vielleicht mal mit einfacher Ausgabe eines "Flash-Strings" starten, um
dieses Legosteinchen zu testen und dann erst alle potentiellen Fehler in
einen Topf schmeißen.
Bitte den Eingangssatz nicht falsch verstehen, aus deinem bisher
geschriebenen sprechen nicht unbedingt Jahrzehnte Programierpraxis.
Und selbst nach 35 Jahren muß man das manchmal, immer seltener
vielleicht, genau so machen. Stück für Stück.
S. Landolt schrieb:> Es scheint, als brächte er nicht nur seine Identitäten durcheinander.
Nein eigentlich nicht. Das kam daher das ich vom Laptop dieses
geschreiben habe und warum auch immer mit der E-Mail Adresse meines
Kumpels einloggt. Denn ich habe mal was eingestellt bei gmail. Und seit
dem meldet Mikrocontrollor.net mich immer mit seinen Account an. Der
übriges auch µC programmiert.
Zum Problem. Das Problem wahr das ich die ganze Zeit weiter sprintf mit
PSTR genutzt habe aber nich sprintf_P
@Jan Hampel (jan_h865)
>Nach diesen Änderungen im Code ist das alles nur am Buggen.
Du bist doch gar nicht der OP des Threads?
> Beim>verändern des Delays der Temperatur wenn ich dort um -250 verkleinern>will kommt dort "/no to change" in die Zeile. + 250 Addieren geht aber.>Beim Delay für das Measurment funktioniert es problemlos.
Das Programm hat so oder so noch einen Bug. In der ISR macht man keine
LCD Ausgaben! Erstens, weil das recht lange dauert und 2. weil sich das
mit den LCD-Ausgaben im Hauptprogramm überschneiden kann! Dann kommt
Mist raus, Stichwort reentrante Funktionen (die LCD-Funktionen sind es
NICHT!).
Die saubere Methode ist die Verwendung von Flags zwischen ISR und
Hauptprogramm.
https://www.mikrocontroller.net/articles/Interrupt#Steuersignale_zwischen_ISR_und_Hauptprogramm
Falk B. schrieb:> Du bist doch gar nicht der OP des Threads?
Wie bereits gesagt. Das die Antwort von ein anderen Account erstellt
wurde liegt daran das ich dieses Antwort vom Laptop ausgeschrieben habe.
Und ich mich bei GMail angemeldet habe um mein Kumpel zu helfen bei
Problem mit sein Mail Account. Mich aber vergessen abzumelden. Und weil
ich mich bei Mikrocontrollor.net mit dem Google Konto anmelde. Hat er
mich mit dem Account angemeldet. Weil ich mit diesen angemeldet wahr.
Und mich mit ein eigenen(Felix Neumann) abgemeldet habe. Ich hatte mich
nur vergessen um zu melden nachdem ich mein Kumpel geholfen habe.
Falk B. schrieb:> Das Programm hat so oder so noch einen Bug. In der ISR macht man keine> LCD Ausgaben! Erstens, weil das recht lange dauert und 2. weil sich das> mit den LCD-Ausgaben im Hauptprogramm überschneiden kann! Dann kommt> Mist raus, Stichwort reentrante Funktionen (die LCD-Funktionen sind es> NICHT!).> Die saubere Methode ist die Verwendung von Flags zwischen ISR und> Hauptprogramm.
Okay, werde das gleich mal lesen. Der Bugg wahr das ich die ganze Zeit
mit sprint und PSTR gearbeitet habe und nicht mit sprint_P nach der
Änderung auf sprint_P funktionierte alles wieder.
Felix N. schrieb:> Denn beim Rechner mit ca. 4 bis 16 GB RAM ist das auch> so zimmlich egal ob er jetzt 500 mb oder 1 gb belegt.
Klingt nach jemandem der Chrome programmiert hat.
Mit dieser besch..... Einstellung ist es kein Wunder das Anwendungen
immer mehr Speicher fressen.
Wenn man gezwungen ist, mit begrenztem Speicher zu programmieren lernt
man, das diese Einstellung nicht die Beste ist.
Frank B. schrieb:> Klingt nach jemandem der Chrome programmiert hat.> Mit dieser besch..... Einstellung ist es kein Wunder das Anwendungen> immer mehr Speicher fressen.> Wenn man gezwungen ist, mit begrenztem Speicher zu programmieren lernt> man, das diese Einstellung nicht die Beste ist.
Ja gut, aus Fehlern lernt man. Nun weis ich ja wie man es am besten
nicht machen sollte um viel Speicher zu fressen :D
Werde es mir nun angewöhnen, möglichstes RAM schonend zu programmieren.