SD-Datei statt Array - Aber wie?

Ich verwende einen Arduino Mega 2560 mit Ethernet-Shield. In meinem Sketch habe ich ein Array mit One-Wire Sensor-Daten. Hier das Array:

// SENSOR-ARRAY ----------------------------------------------------------------------------------
    typedef struct Sensor {             // Definition das Sensor-Arrays
        DeviceAddress address;          // 1. Sensor-ID, 1.Byte = Sensor-Typ, 2.-7. = ID, 8. = CRC
        char* name;                     // 2. Klarname
        char* typ;                      // 3. Raum, FB, Kessel, WW, Solar, aussen, ...
        byte aufloesung;                // 4. Auflösung
        float sollwert;                 // 5. Solltemperatur
        byte pinnr;                     // 6. Pin-Nummer gem. folgender Liste
    } Sensor;

    // Sensor-Array erzeugen
Sensor sensorList[] = { // address, name, typ, aufloesung, sollwert (mit Punkt), pinnr
    { {0x28, 0x5C, 0x62, 0x0A, 0x05, 0x00, 0x00, 0xF1}, "Links",  "Raum", 12, 24.0, 22 },
    { {0x28, 0x12, 0xD2, 0x51, 0x05, 0x00, 0x00, 0x94}, "Mitte",  "Raum", 12, 23.0, 24 },
    { {0x10, 0x6B, 0x48, 0x90, 0x02, 0x08, 0x00, 0xCF}, "Rechts", "Raum",  9, 23.5, 26 } };
int AnzahlSensoren = 3;                 // Anzahl Sensoren

Nun wird die Anzahl der Sensoren viel größer. ca. 40. Damit würde das Array auch größer werden. Und so überlege ich, ob es besser wäre alles in einer Datei auf der SD zu haben. Das wäre sicherlich auch pflegeleichter.
Nur, habe ich scheinbar eine Denkblockade und weiß nicht, wie ich das angehen soll. Wie ist die beste Anordnung der Daten und wie lese ich die verschiedenen Daten wieder aus. Die Sensordaten werden regelmäßig in einer for-Schleife verwendet.
Bin für Ideen und Hilfe dankbar.
Gruß Gerd

Wenn ist dir nur darum geht RAM zu sparen, kann man auch probieren die Daten mit PROGMEM im Flash abzulegen. Man kann auch structs im Flash ablegen und dann Byte-weise auslesen. Das Auslesen kann man wie ein Byte Array betrachten und danach auf ein struct casten.

Auf SD schreibst du jeden Datensatz in eine eigene Zeile. Da alles durch Komma getrennt ist, kann man dann immer von Linefeed zu Linefeed lesen für die Zeile und von Komma zu Komma für die einzelnen Teile.
Du kannst auch die SdFat Lib verwenden. Die hat mit fgets() eine Methode um eine Zeile auf einmal auszulesen. Da das dann i.d.R. ein String ist, muss man noch die Teil-Strings wieder in Zahlen wandeln. Dafür gibt es Methoden wie atoi() und atof()

Ich habe bei mir nur Zahlen drin, die so aussehen:

071,001,040,008
070,001,041,020
070,-05,045,017
070,007,050,011

Mit SdFat kann ich das dann einfach so lesen (wobei stringBuffer ein globaler Puffer ist):

bool getLine(const char* filename, int line)
{
	if(sd.begin())
	{	
		if(file.open(filename, O_READ))
		{
			int count = 1;

			while(file.fgets(stringBuffer, STRING_BUFFER_SIZE) > 0)
			{
				if(count == line)
					break;
				count++;
			}
			file.close();

			if(count != line)
				return false;

			return true;
		}
	}

	return false;
}

Und z.B. so konvertieren:

void getCurveSettings(Curve* curve)
{	
	if(curve != NULL)
	{
		curve->tk_max = atoi(strtok(stringBuffer, ","));
		curve->ta_min = atoi(strtok(NULL, ","));
		curve->tk_min = atoi(strtok(NULL, ","));
		curve->ta_max = atoi(strtok(NULL, ","));
	}	
}

Hier wird der Methode ein Zeiger auf ein struct übergeben. strtok() gibt mir dann immer die Teil-Strings zurück und mit atoi() werden sie in Integer konvertiert. Für Details google die Namen der Funktionen.

Da die Zahlen immer gleich lang sind, könnte man hier auch mit festen Offsets arbeiten und auf strtrok() verzichten, aber so is es flexibler.

Der Code ist wie gesagt für SdFat und nicht die normale Arduino SD Lib. Es gibt hier aber mehrere Wege um hier ans Ziel zu kommen :slight_smile:

P.S.:
Du musst dann aber unbedingt dein struct so ändern, dass es char Arrays enthält und nicht nur Zeiger. Sonst bekommst du Probleme! Die Strings von der SD Karte kann man dann mit strncpy() in das struct kopieren.

Hallo,
ich habe jetzt geübt und gelernt.
Ich kann von Komma zu Komme oder bis zum Zeilenende auslesen, auch bis zum Dateiende.
Nun versuche das Auslesen und Umwandeln der Sensoradressen. Das gelingt mir nicht.
Beispiel: 0x28, 0x5C, 0x62, 0x0A, 0x05, 0x00, 0x00, 0xF1,

                        for (int j = 0; j < 8; j++) {             // 1-8 Sensoradresse
                           String  text = senDatei.readStringUntil(',');
                            text.trim();                            // Leerzeichen raus
                            DeviceAddress tempAdresse[j] = int(text); // Fehler
                        }

Wie wandle ich den Text in eine Hexzahl um? das will mir nicht gelingen.
Gruß Gerd

Da bist du wie so oft gleich auf die Limitationen der primitiven Arduino String Klasse gestoßen. Man kann einfach kaum was damit machen. In Standard C geht das ganz einfach mit strtoul:
http://www.cplusplus.com/reference/cstdlib/strtoul/
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#gaea44aa48bda8261f794dcb2d1e7ab2b2

Dabei kann man als dritten Parameter die Basis übergeben. Also 16 für Hex.

Mit C Strings ist aber auch das einlesen schwerer. Ein Kompromiss ist dass du toCharArray() verwendest um das String Objekt in einen C String zu wandeln. Schau dabei genau an wie das funktioniert:

Du musst da bei ein entsprechend großes Array als Parameter übergeben. Der muss eins größer als die Anzahl der Zeichen sein.

Dann kannst du den C String in eine Zahl konvertieren.

In deinem Sonderfall “0x” + 2 Zeichen mit führender Null, würde diese Funtion reichen

// x muss im Format "0xFF" sein
// F ist ein Zeichen 0 .. 9 oder A .. F (Grossbuchstaben)
byte getAddr(String x)
{
   byte result;
   char c =  x.charAt(2);
   if (if c >= 'A' ) result = c - 'A' + 10; else result = c - '0';
   result = result << 4; // high digit ( * 16 );
   c = x.charAt(3);
   if (if c >= 'A' ) result += c - 'A' + 10; else result += c - '0';
   return result;
}