String zusammensetzen und Ausgabe auf LCD

Hallo zusammen,ich würde gern einen Text auf dem LCD ausgeben. Genauer gesagt möchte ich ein Wort ( oder mehrer) in einem Array im eeprom speichern und sie nach bedarf zusammen setzen und ausgeben.
z.B.: "Wasser" und "OK" und "Störung" , eine Variable bekommt einen Wert und dann soll , je nach Wert, der Text sich zusammen setzen : "Wasser OK" oder "Wasser Störung". Ich habe schon PROGMEN mir an gesehen aber so richtig steige ich nicht durch und bei String oder string verstehe ich den Unterschied nicht. Zur Zeit verwende ich noch LCD.print"........." , was ich ändern möchte.
Das LCD wird über i2c gesteuert , von einem Nano.

Danke :smiley:

MfG Marco

Verkneif Dir das zusammensetzen der Wörter zu einem String sondern gib sie einfach nacheinander auf das Display aus. Das Display fügt sie dann zusammen.
Grüße Uwe

Feste Texte kannst du besser mit PROGMEM nutzen. Würde die nicht zusätzlich noch ins Eeprom laden.
Im Eeprom reicht es, einfache Zahlen zu verwenden. CharArrays geht aber natürlich auch.

typedef struct
{
  uint8_t id1;
  uint8_t id2;
  uint8_t h;
  uint8_t m;
} SETTINGS;
SETTINGS settings;

void setup()
{
  eeprom_read_block((void*)&settings, 0, sizeof(SETTINGS));
}

void loop ()
{

// Wenn Wert von settings (z.B. id1) geändert wurde,
// das Eeprom mit 
// eeprom_write_block((void*)&settings, 0, sizeof(SETTINGS));
// beschreiben
}

EEPROM != Flash
Du meinst wahrscheinlich Flash.

Wenn du print() verwendest, brauchst du da gar nichts groß zu machen. Einfach so:

lcd.print(F("String im Flash"));

Dann belegt der String kein RAM mehr.

Ich würde da auch nicht lange rummachen und einfach zwei Strings nehmen. Einmal "Wasser OK" und "Wasser Störung". Dann muss man sich nichts überlegen wie man die aneinanderfügt.

Ansonsten braucht man ein Puffer im RAM, der Platz für den größten String + 1 hat. Kann man z.B. so machen:

const int STRING_BUFFER_SIZE = 21;
char stringBuffer[STRING_BUFFER_SIZE];

#define P(str) strcpy_P(stringBuffer, PSTR(str))

Dann kann man das P() Makro ähnlich wie F() verwenden. Das kopiert den String aus dem Flash ins RAM und strcpy_P() liefert einen Zeiger auf das Array zurück.

Das hat den Nachteil, dass Strings die man eventuell mehrmals verwendet auch mehrmals im Flash gespeichert werden. Was man so umgehen kann:

#define ProgmemCopy(str) strcpy_P(stringBuffer, str)

const char str1[] PROGMEM = "string1";
const char str2[]  PROGMEM = "string2";

Dann kann man mit ProgmemCopy(str1) den String aus dem Flash ins RAM kopieren und so z.B. an eine Funktion übergeben, die einen char* erwartet

Wenn man wirklich eine Liste von Strings im Flash speichern will, geht das so:

const char dayString0[] PROGMEM = "  Montag  ";
const char dayString1[] PROGMEM = " Dienstag ";
const char dayString2[] PROGMEM = " Mittwoch ";
const char dayString3[] PROGMEM = "Donnerstag";
const char dayString4[] PROGMEM = "  Freitag ";
const char dayString5[] PROGMEM = "  Samstag ";
const char dayString6[] PROGMEM = "  Sonntag ";
const char* dayStrings[] PROGMEM = { dayString0, dayString1, dayString2, dayString3, dayString4, dayString5, dayString6 };

Also erst die Strings speichern und dann ein Array auf die Strings. Dann kann man die Strings so auslesen:

char* getDayStr(byte day)
{
	return strcpy_P(stringBuffer, (char*)pgm_read_word(&dayStrings[day]));
}

Man greift also auf dem Index im String Array zu, kopiert mit pgm_read_word() die entsprechende Adresse aus dem Flash und übergibt dann die Adresse an strcpy_P() um den String aus dem Flash ins RAM zu kopieren

Danke für die schnelle Hilfe :smiley:
Eine Frage hätte ich noch, was bedeutet das sternchen bei char* ? Multiplizieren?

MfG Marco

Zeiger auf char:

Arrays aus Strings sind Arrays aus char*, da Strings in C nur Arrays aus char sind. Und Array Variablen sind Zeiger auf das erste Element.

Hi, habe nun versucht den String auf´s Display zubekommen aber nur mit Fehlermeldung.
Die #include <avr/pgmspace.h> habe ich. Fehlt noch eine *.h ? oder was ist der Fehler?

LCD.ino:20: error: initializer fails to determine size of '__c'

if (blumen_G != alt_blumen_G)
	{
		lcd.clear();
		lcd.setCursor(0, 1);
		lcd.print(F(string_5));  // mit ("string_5") geht auch nicht
	}
prog_char string_0[] PROGMEM = "Licht: AN";   // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "Licht: OK";
prog_char string_2[] PROGMEM = "WC: AN";
prog_char string_3[] PROGMEM = "WC: OK";
prog_char string_4[] PROGMEM = "WC: Störung";
prog_char string_5[] PROGMEM = "Blumen: AN";
prog_char string_6[] PROGMEM = "Blumen: OK";
prog_char string_7[] PROGMEM = "Blumen: Störung";
prog_char string_8[] PROGMEM = "Kühlschrank 12V";
prog_char string_9[] PROGMEM = "Kühlschrank 220V";


// Then set up a table to refer to your strings.

PROGMEM const char *string_table[] = 	   // change "string_table" name to suit
{
	string_0,
	string_1,
	string_2,
	string_3,
	string_4,
    string_5,
	string_6,
	string_7,
	string_8,
	string_9
	 };

char buffer[20];    //

MfG Marco

Nicht gelesen was ich oben geschrieben habe? Wie soll das den gehen? Das F() Makro arbeitet ähnlich wie PSTR() und erstellt einen String im Flash. Damit kann man aber keinerlei wo anders definierte Daten aus dem Flash auslesen.

Mach es so:

char* getString(byte str)
{
     static char buffer[21];
     return strcpy_P(buffer, (char*)pgm_read_word(&string_table[str]));
}

Dann übergibst du der Funktion den Index des Strings und kannst einfach das machen (da die Funktion einen Zeiger auf das Array zurückgibt):

Serial.println(getString(1));

EDIT:
Mit dem "ö" bekommst du wahrscheinlich Probleme, da das nicht teil des ASCII Zeichensatzes ist. Beim HD44780 Controller hat das "ö" den Code 0xEF. Das hier sollte also funktionieren:

prog_char string_4[] PROGMEM = "WC: St\xEFrung";
prog_char string_7[] PROGMEM = "Blumen: St\xEFrung";

Wenn nach dem Hex Code ein Zeichen kommt, dass auch als Hex interpretiert werden kann (0-9, a-f, A-F), muss man den String stückeln:

prog_char string_4[] PROGMEM = "WC: St\xEF" "rung";

EDIT 2:
Oder wenn du lieber statt dem Index die String Variable übergeben willst, lass das Array aus char* (string_table) weg, und mach getString() so:

char* getString(const char* str)
{
     static char buffer[21];
     return strcpy_P(buffer, str);
}

Dann kann man das machen:

Serial.println(getString(string_0));

Der Unterschied ist dabei wo die Adressen der Strings abspeichert werden. Hier hat man die Adresse direkt. Bei dem Array aus Strings muss man die Adresse erst von wo anders im Flash auslesen (mit pgm_read_word())