Hallo zusammen,
ich habe ein großes Problem mit dem Speicher.
Ich lasse mir auf einem LCD Display Datum und Uhrzeit anzeigen. (uRTCLib)
Hierzu habe ich mir zwei char Funktionen geschrieben, die mir die aktuellen Werte liefern.
Das läuft jede Sekunde und pro Durchlauf werden 24 Byte Speicher verwendet.
Nach fünf Minuten ist der Speicher voll und mein Mega 2560 hängt sich auf.
Wie bekomme ich es hin, dass der Speicher nicht jedes Mal neu verwendet wird.
Innerhalb von loop():
if (printRTCEveryPeriod(1, DATE_FORMAT_EUROPEAN)) {
printRTC(DATE_FORMAT_EUROPEAN);
printRTCTemperature();
Serial.println();
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(date2lcd());
lcd.setCursor(12, 2);
lcd.print(time2lcd());
}
Die beiden Funktionen für Datum und Uhrzeit lauten:
char* date2lcd() {
char tDateString[10];
sprintf_P(tDateString, PSTR("%02u.%02u.20%2u"), rtc.day(), rtc.month(), rtc.year());
char* ret = (char*)malloc(10);
return strcpy(ret, tDateString);
}
char* time2lcd() {
char tTimeString[9];
sprintf_P(tTimeString, PSTR("%02hhu:%02hhu:%02hhu"), rtc.hour(), rtc.minute(), rtc.second());
char* ret = (char*)malloc(10);
return strcpy(ret, tTimeString);
}
Gruß
combie
July 11, 2023, 10:37am
2
liebelein01:
malloc(10)
Wo sind die free()?
Überlebenstipp: RAII
Oder nach Möglichkeit ganz auf dynamische Allokierungen verzichten
mach bitte mal einen vollständigen kompilierbaren Sketch mit Links auf alle verwendeten Libraries.
Da gibts sicher eine bessere Variante als du es bisher umgesetzt hast.
PS: Spricht irgendwas für die Verwendung von sprintf_P ? Hast das oft im Sketch? Weil nur wegen DD.MM.YYYY und HH:MM:SS würde ich das nicht auf einem Mega verwenden.
Das "nach Möglichkeit" kannst du zur Vereinfachung einfach streichen.
Mach tTimeString und tDateString static
und liefere sie zurück.
Oder liefere einen char buf[11] als Parameter mit, dann brauchst du sogar nur insgesamt 11 byte, die abwechselnd mit Datum und Uhrzeit gefüllt werden, wenn du es mit dem RAM sparen übertreiben willst.
P.S.
Für "12.12.2001" reichen übrigens 10 byte nicht.
Mal ein Auszug aus meinem Tutorial , wie man das ohne sprintf & Co. machen kann:
int stunde = 3, minute = 29, sekunde = 7, tag = 7, monat = 8, jahr = 2016;
char puffer[20];
// Hängt die formatierte Uhrzeit an eine Zeichenkette an
void addZeit(char * ziel, int st, int mi, int se) {
char buf[9]; // 00:00:00
buf[0] = (st / 10) + '0'; // Zehner
buf[1] = (st % 10) + '0'; // Einer
buf[2] = ':';
buf[3] = (mi / 10) + '0';
buf[4] = (mi % 10) + '0';
buf[5] = ':';
buf[6] = (se / 10) + '0';
buf[7] = (se % 10) + '0';
buf[8] = 0; // die abschließende 0
strcat(ziel,buf);
}
// Hängt das formatierte Datum an eine Zeichenkette an
void addDatum(char * ziel, int ta, int mo, int ja) {
char buf[11]; // 00.00.0000
buf[0] = (ta / 10) + '0'; // Zehner
buf[1] = (ta % 10) + '0'; // Einer
buf[2] = '.';
buf[3] = (mo / 10) + '0';
buf[4] = (mo % 10) + '0';
buf[5] = '.';
buf[6] = (ja / 1000) + '0'; // Tausender
ja = ja % 1000; // Rest 3-stellig
buf[7] = (ja / 100) + '0'; // Hunderter
ja = ja % 100; // Rest 2-stellig
buf[8] = (ja / 10) + '0'; // Zehner
buf[9] = (ja % 10) + '0'; // Einer
buf[10] = 0; // die abschließende 0
strcat(ziel,buf);
}
void setup() {
Serial.begin(115200);
Serial.println("start");
strcpy(puffer,"Zeit: ");
addZeit(puffer,stunde,minute,sekunde);
Serial.println(puffer);
strcpy(puffer,"Datum: ");
addDatum(puffer, tag,monat,jahr);
Serial.println(puffer);
}
void loop() {
}
Gruß Tommy
2 Likes
Hallo,
vielen Dank für Eure Hinweise.
Ich habe die Funktionen nun wie folgt geändert und habe sogar noch ein paar wenige Bytes gespart.
char* date2lcd() {
static char tDateString[10];
sprintf_P(tDateString, PSTR("%02u.%02u.20%2u"), rtc.day(), rtc.month(), rtc.year());
return tDateString;
}
char* time2lcd() {
static char tTimeString[10];
sprintf_P(tTimeString, PSTR("%02hhu:%02hhu:%02hhu"), rtc.hour(), rtc.minute(), rtc.second());
return tTimeString;
}
Gruß
Ist immer noch zu kurz, das wurde Dir aber schon gesagt.
Gruß Tommy
combie
July 11, 2023, 12:39pm
9
Und dir damit gleich die nächsten Frikadellen ans Knie genagelt.
Unsinnig Speicher verplempert....
static, ohne Not.
Mag funktionieren, aber schön ist datt nich.
Na dann viel Spaß bei den Folgefehlern.
Du solltest Dir mal das von mir verlinkte Tutorial zu Gemüte führen, um die Grundlagen zu erlernen.
Gruß Tommy
Hi,
das stimmt, dass es bereits erwähnt wurde.
Ich überlege nur, warum das so sein soll.
Das Datum hat das Format 00.00.0000. Das sind 10 Zeichen.
Die müssten doch in ein 10 Zeichen char array passen. Oder was übersehe ich?
Zumindest funktioniert es und das Datum wird angezeigt.
Gruß
Ja.
Was wird hier erklärt.
Gruß Tommy
combie:
schön ist datt nich
Es gibt sicher Kriterien, nach denen das nicht schön ist.
Ich finde es schön, dass sowas in der Arduino-Programmierumgebung mit ihren Einschränkungen (z.B. nur single thread) überhaupt geht
liefere einen char buf[11] als Parameter mit
ist übrigens nicht übertrieben sparsam, wie ich vorhin schrieb, sondern (in unser beider Augen, richtig?) schöner.
Was ich definitiv seit Jahren lerne ist, dass Schön immer im Auge des Betrachters liegt und Code den der eine scheiße findet für einen anderen perfekt ist.
Wie auch in vielen anderen Dingen, gibt es wie immer viele Wege nach Rom.
Es wird auch weiterhin die Leute geben, die ihren Weg für richtig halten.
Da gibt es die volle Akzeptanz bei mir.
Die Lösung, die ich jetzt gewählt habe ist für mich der richtige Weg.
Ein Dreizeiler, der macht was er soll und auch noch ein paar Bytes weniger braucht, als der 11 Zeiler von Tommy56.
btw: Habe das Array auf 11 geändert. Keine Ahnung, warum mir das mit dem letzten Zeichen nicht wieder eingefallen ist.
Euch vielen Dank für die Denkanstöße.
combie
July 11, 2023, 1:51pm
16
struct RTC
{
int day() {return 1;}
int month() {return 2;}
int year() {return 3;}
int hour() {return 4;}
int minute() {return 5;}
int second() {return 6;}
};
RTC rtc;
template<size_t N> char *date2str(char (&buffer)[N], RTC &rtc)
{
static_assert(N>10,"Buffer zu klein");
snprintf_P(buffer, N, PSTR("%02u.%02u.20%02u"), rtc.day(), rtc.month(), rtc.year());
return buffer;
}
template<size_t N> char *time2str(char (&buffer)[N], RTC &rtc)
{
static_assert(N>8,"Buffer zu klein");
snprintf_P(buffer, N, PSTR("%02hhu:%02hhu:%02hhu"), rtc.hour(), rtc.minute(), rtc.second());
return buffer;
}
void setup()
{
Serial.begin(9600);
}
void loop()
{
char buf[20];
Serial.println(date2str(buf, rtc));
Serial.println(time2str(buf, rtc));
delay(5000);
}
nur wenn du snprintf sonst auch noch in Verwendung hast. Ansonsten ist die Version von @Tommy56 sicher sparsamer.
Ich würde ja Tommy und Combie kombinieren:
/*
Speicherfresser Problem
https://forum.arduino.cc/t/speicherfresser-problem-mit-char-funktion/1146860/16
2023-07-11 by noiasca
*/
struct RTC {
int day() {return 1;}
int month() {return 2;}
int year() {return 23;} // was gibt dein RTC wirklich retour?
int hour() {return 4;}
int minute() {return 5;}
int second() {return 6;}
};
RTC rtc;
template<size_t N> char *date2str(char (&buffer)[N], RTC &rtc) {
static_assert(N>10,"Buffer zu klein");
buffer[0] = (rtc.day() / 10) + '0'; // Zehner
buffer[1] = (rtc.day() % 10) + '0'; // Einer
buffer[2] = '.';
buffer[3] = (rtc.month() / 10) + '0';
buffer[4] = (rtc.month() % 10) + '0';
buffer[5] = '.';
buffer[6] = '2'; // Tausender
buffer[7] = '0'; // Hunderter
buffer[8] = (rtc.year() / 10) + '0'; // Zehner
buffer[9] = (rtc.year() % 10) + '0'; // Einer
buffer[10] = 0; // die abschließende 0
return buffer;
}
template<size_t N> char *time2str(char (&buffer)[N], RTC &rtc) {
static_assert(N>8,"Buffer zu klein");
buffer[0] = (rtc.hour() / 10) + '0'; // Zehner
buffer[1] = (rtc.hour() % 10) + '0'; // Einer
buffer[2] = ':';
buffer[3] = (rtc.minute() / 10) + '0';
buffer[4] = (rtc.minute() % 10) + '0';
buffer[5] = ':';
buffer[6] = (rtc.second() / 10) + '0';
buffer[7] = (rtc.second() % 10) + '0';
buffer[8] = 0; // die abschließende 0
return buffer;
}
void setup() {
Serial.begin(15200);
}
void loop() {
char buf[11];
Serial.println(date2str(buf, rtc));
Serial.println(time2str(buf, rtc));
delay(5000);
}
Run IoT and embedded projects in your browser: ESP32, STM32, Arduino, Pi Pico, and more. No installation required!
combie
July 11, 2023, 5:43pm
18
Solange ich nicht in Flashmangel stolpere würde ich den Fokus auf Wartbarkeit legen.
Zudem bin faul....
Am Rande:
Für ungenutzten Speicher gibts kein Geld zurück.
combie
July 11, 2023, 9:42pm
20
Immerhin scheint dir ja die Absicherung gegen unwillkommene Abschmierer gefallen zu haben.
Wenn auch der zweite Schutz, gegen Fehler/Irrtümer beim zusammenstoppeln, dabei unter den Tisch gefallen ist.
Nicht wirklich.
Ich habe mir die letzten Tage einfach mal Gedanken gemacht, wie ich es mit den ganzen Anregungen hier am Besten hinbekommen kann.
Ich bin jetzt auf die RTClib gewechselt und löse es folgend:
char germanDate[11];
formatGermanDate(rtc.now(), germanDate);
void formatGermanDate(DateTime dateTime, char* formattedDate) {
char d[3]; char m[3]; char y[5];
sprintf(d, "%02d", dateTime.day());
sprintf(m, "%02d", dateTime.month());
sprintf(y, "%04d", dateTime.year());
snprintf(formattedDate, 11, "%s.%s.%s", d, m, y);
}
combie
July 15, 2023, 7:45pm
22
Von hinten durch die Brust ins Auge!
Aber wenn es funktioniert......
(kann es ja nicht böse sein)