Sensoradressen indirekt

Hallo,
Ich habe vor, viele Temperatursensoren per OneWire auszulesen. Die IDs sind bekannt, möchte aber auch Klarnamen dabei haben. Dabei verheddere ich mich in den Deklarationen und Datentypen und hoffe, mir kann jemand den richtigen Weg zeigen.
Hier der entsprechende Code. OneWire.h und DallasTemperature.h sind deklariert und gestartet, Seriell auch. Der Sketch läuft auf Arduino Mega mit Ethernet Shield.

sensors.begin();
DeviceAddress Links  = {0x10, 0x8B, 0xCD, 0x4D, 0x02, 0x08, 0x00, 0x63}; // Links
DeviceAddress Mitte  = {0x10, 0x64, 0x1F, 0xAD, 0x02, 0x08, 0x00, 0xFA}; // Mitte
DeviceAddress Rechts = {0x10, 0x6B, 0x48, 0x90, 0x02, 0x08, 0x00, 0xCF}; // Rechts
char* SensorName[] = {"Links", "Mitte", "Rechts"};

        for (int i = 0; i < AnzahlSensoren; i++) {
        char* str = SensorName[i];
        Serial.print(str);
        Serial.print(" ");
        float tempC = sensors.getTempC(SensorName[i]);
        Serial.println(tempC);
        }

Ich möchte gern SensorName durchlaufen und dafür die SensorAdresse anwenden. Es gibt aber Fehler bei sensors.getTempC(). Wenn ich den Klarnamen, zB. Links einsetzen geht's. Aber so stelle ich mir das nicht vor.
Gruß Gerd

Die Lib kann natürlich mit dem String Array nichts anfangen. Wie auch? Die geht nur nach Adressen oder Indices.

Du musst dir entweder ein Array aus DeviceAdress anlegen, oder zusätzlich ein Array aus Zeigern auf DeviceAdress

Ich habe es so:

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress sensorList[] = {  { 0x28,0x68,0x2A,0xA4,0x05,0x00,0x00,0xAB },
		                { 0x28,0x82,0x38,0xA5,0x05,0x00,0x00,0x3D }
		                };

float temperatures[2];

Dann geht sowas:

sensors.setResolution(sensorList[0], SENSOR_RESOLUTION);
sensors.setResolution(sensorList[1], SENSOR_RESOLUTION);

Oder:

temperatures[0] = sensors.getTempC(sensorList[0]);
temperatures[1] = sensors.getTempC(sensorList[1]);

Ja, so in der Art habe ich mir das vorgestellt. Aber meine Klarnamen finden darin keinen Platz oder? Ich möchte gern beim Auslesen von z.B. der Temperatur temperatures[0] den Klarnamen z.B. Links dabei haben. Damit die Daten besser zu verstehen sind.
Gruß Gerd

Du hast halt zwei Arrays. Eins für die Adressen und eins für die Strings. Solange die Reihenfolge gleich ist, sind die Indices jeweils gleich und es passt.

OK. Das ist realisierbar. 'Ne elegantere Methode gibt es nicht?
Auf jeden Fall habe ich erstmal eine Lösung. Danke dafür.
Gruß Gerd

Eine andere Option ist ein struct aus einer Adresse und einem String. Und dann ein Array aus structs.

Das klingt interessant. Aber ich keine Ahnung wie das zu realisieren ist. Da braüchte ich 100% Hilfe. Ich werde höchsten eine Lösung nachempfinden können und hoffentlich viel dabei lernen.
Gruß Gerd

Die struct Definition:

typedef struct Sensor
{
  DeviceAddress address;
  char* name;
} Sensor;

Das wie eine globale Variable definieren

Ein Array davon:

Sensor sensorList[] = { { { .... }, "Links" }, { { ... }, "Rechts" } };

Man kann statt einem Pointer auch ein richtiges Array in das struct schreiben (das dann eins größer als der längste String sein muss), aber zumindest in Visual C++ geht es auch mit dem Zeiger.

Das typedef ist drin weil man sonst bei jeder Verwendung das struct keyword bräuchte. Also z.B. struct Sensor sensorList[]...
Dadurch kann man dann für "struct Sensor" nur "Sensor" schreiben.

Dann kann man die Variablen über sensorList[index].address und sensorList[index].name ansprechen

Kompilieren tut es. Ob es wirklich geht, habe ich nicht ausprobiert.

Ne elegantere Methode gibt es nicht?

Wenn du statt einer struct eine class definierst, könntest du auch gleich eine Methode float getTemp ( ) dazudefinieren, die ihrerseits sensors.getTempC() aufruft.
Das hiesse dann einfach sensorlist [ i ] .getTemp();

Aber ausser "Eleganz" und evtl. Lerneffekt bringt es nicht wirklich was :wink:

edit: Mist! eckige Klammern gehören in [ code ] tags

vielen, vielen Dank. Werde mich morgen früh ransetzen. Bin gespannt ob ich das hin bekomme. Bis alles läuft bin ich sicherlich noch mal hier.
Gruß Gerd

In C++ können structs auch Funktionen enthalten. Nur nicht in C (und da kann man Funktionszeiger als Workaround verwenden) :slight_smile:

In C++ ist der einzige Unterschied zwischen einem struct und einer Klasse, dass die Member eines structs standardmäßig public sind und die einer Klasse private.

Die "typedef struct Sensor"-Variant funktioniert einwandfrei. ich bin sehr dankbar für die Hilfe.
Gruß Gerd

Nun stehe ich vor dem nächsten Problem:

//===============================================================================================// Bibliotheken einbinden
//===============================================================================================#include <SD.h>
#include <Time.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
//===============================================================================================// Deklarationen
//===============================================================================================// für SD-Karte ------------------------------------------------------------------------------------
const int CS_Mega = 53;                 // PIN 53 Slave Select für Mega
const int CS_SD   =  4;                 // PIN 4 Slave Select für SD
const int CS_Eth  = 10;                 // PIN 10 Slave Select für Ethernet

File myFile;                            // Objekte vom Typ File erzeugen
String strDateiname;                    // für Funktion NeueDatendateiErzeugen
char arDateiname[13];                   // für Funktion NeueDatendateiErzeugen, 8.3 lang
String strDatumUhrzeit;                 // für Funktion DatUhrzeit
// für One-Wire Temperatursensoren ----------------------------------------------------------------------
byte OneWirePin;                        // variiert bei mehreren Bussen
int AnzahlSensoren;                     // dto. Anzahl Sensoren
#define ONE_WIRE_BUS OneWirePin         // Hier ist der Sensorbus angeschl.
OneWire oneWire(ONE_WIRE_BUS);          // Objekte vom Typ oneWire erzeugen
DallasTemperature sensors(&oneWire);    // Anbindung an die Dallas-Lib
DeviceAddress tempSensorID;             // Adressspeicher

typedef struct Sensor {                 // Definition das Sensor-Arrays
    DeviceAddress address;              // Sensor-ID
    char* name;                         // Klarname
    float sollwert;                     // Solltemperatur
} Sensor;

//===============================================================================================// setup
//===============================================================================================void setup() {
        // start USB/Serielle
    Serial.begin(9600);
// ............        
// SD-KARTE starten
    digitalWrite(CS_SD, LOW);           // SD ein
    Serial.print("Initialisierung der SD Karte ... ");
    if (!SD.begin(CS_SD)) {
        Serial.println("SD geht nicht");
        return;                         // raus aus der Funktion
    } // Ende if SD
    Serial.println("OK\n");        // Funktion geht weiter
        // config.sys auslesen, Auflösung und Messzyklus berechnen
//    configAuswerten();                  // Funktion holt Daten aus config.txt von SD

// Temperatursensoren ======================================================
// DALLAS TEMPERATURE Library starten
    sensors.begin();
// -----------------------------------------------
    OneWirePin = 2;                    // variiert bei mehreren Bussen
    AnzahlSensoren = 3;                 // dto. Anzahl Sensoren
// -------------------------------------------------
    
        // Sensor-Array erzeugen
    Sensor sensorList[] = { // address, name, sollwert (mit Punkt)
        { {0x10, 0x8B, 0xCD, 0x4D, 0x02, 0x08, 0x00, 0x63}, "Links", 25.0 },
        { {0x10, 0x64, 0x1F, 0xAD, 0x02, 0x08, 0x00, 0xFA}, "Mitte", 24.8 },
        { {0x10, 0x6B, 0x48, 0x90, 0x02, 0x08, 0x00, 0xCF}, "Rechts", 24.5 } };

        // Spannungsversorgung am Bus ermitteln
    Serial.print("Parasitaere Versorgung ist ... ");
    if (sensors.isParasitePowerMode()) Serial.println("aktiv");
    else Serial.println("inaktiv");
        // Anzahl der vorhandenen Sensoren suchen und mit AnzahlSensoren vergleichen
    Serial.print("Sensorsuche ... ");
    int temp = sensors.getDeviceCount(); // gibt die wirkliche Anzahl an
    if (temp = AnzahlSensoren) {
        Serial.print("Anzahl Sensoren = ");
        Serial.print(temp);
        Serial.println(", ist OK");
    }
    else if(temp < AnzahlSensoren) {
        Serial.print("Es fehlen ");
        Serial.print(AnzahlSensoren - temp);
        Serial.println(" Sensoren");
    }
    else {
        Serial.print("Es sind ");
        Serial.print(temp - AnzahlSensoren);
        Serial.println(" Sensoren zu viel!");
    }

    Serial.println("");
    NeueDatendateiErzeugen();           // Funktion erzeugt lfd.Namen der Ausgabedatei
    Serial.println("Aktuell: " + strDateiname + "\n");

    for (int i = 0; i < AnzahlSensoren; i++) {
        Serial.print(sensorList[i].name);
        Serial.print(" ");
        Serial.print(" ");
        float tempS = sensorList[i].sollwert;
        Serial.print(tempS);
        Serial.print(" ");
        float tempC = sensors.getTempC(sensorList[i].address);
        Serial.print(tempC);
        int tempR = sensors.getResolution(sensorList[i].address);
        Serial.print(" ");
        Serial.println(tempR);
    }

} // Ende Setup-Funktion

//===============================================================================================// loop
//===============================================================================================void loop() {}// Ende Loop-Funktion

//===============================================================================================// Funktionen
//===============================================================================================String  NeueDatendateiErzeugen () { // Aufruf in Setup
      // das Dateiformat ist 8.3
      // der Dateiname soll folgenden Aufbau haben:
      // Jahr, Monat und Tag je 2-stellig, lfd-Nr 2-stellig
    Serial.print("NeueDatendateiErzeugen beginnt ... ");
    time_t t = now();                             // damit alle folgenden Formeln die gleiche Zeit verwenden
    strDateiname = String(year(t));               // Jahr 4-stellig
    strDateiname = strDateiname.substring(2);     // Jahr 2-stellig
    if ( month(t) < 10 ) strDateiname += '0';     // Monat
    strDateiname += String(month(t));
    if ( day(t) < 10 ) strDateiname += '0';       // Tag
    strDateiname += String(day(t));
    for (byte i = 0; i <= 9; i++){                // lfd Nr erzeugen mit i und j
        String strZwischen_i = strDateiname + i;
        for (byte j = 0; j <= 9; j++){
            String strZwischen_j = strZwischen_i + j + ".dat";
                // prüfen, ob Datei existiert, wenn ja, nächste lfd Nr, wenn nein, Datei erzeugen
                // an SD.exists muss Array übergeben werden
                // deshalb zuerst Dateiname-String in Array umwandeln
            strZwischen_j.toCharArray(arDateiname, sizeof(arDateiname));
            if (!SD.exists(arDateiname)) {        // Datei existiert nicht, also erzeugen
//                Serial.println("Datei " + strZwischen_j + " existiert nicht");
                // neue Datei öffnen Tabellenkopf einfügen und wieder schließen
                myFile = SD.open(arDateiname, FILE_WRITE); // Datei wird erzeugt, wenn nicht vorhanden
// -------------------------------------------------------------------------------------------------
                myFile.print("Sensor-ID;"); // Anfang Zeile 1: Sensor-ID
                Serial.print("Sensor-ID ");
                for (int i = 0; i < AnzahlSensoren; i++) {
                    for (int j = 0; j < 8; j++) {
                        int tempA = Sensor sensorList[i].address[j];
                        myFile.print(tempA, HEX);
                        Serial.print(tempA, HEX);
                    }
                    myFile.print(";");
                    Serial.print(" ");
                }
                myFile.println("");
                Serial.println(""); // Ende Zeile 1: Sensor-ID
    


// ------------ Tabellenkopf einfügen                
// -------------------------------------------------------------------------------------------------
                myFile.close();
                strDateiname = strZwischen_j;
//                Serial.println("Datei " + strDateiname + " erzeugt");
                return strDateiname;
            } // Ende if SD.exists
//            else {                                // Datei existiert, also nächste Nr
//                Serial.println("Datei " + strZwischen_j + " existiert!");
//            } // Ende else SD.exists
        } // Ende for j
    } // Ende for i
} // Ende Funktion NeueDatendateiErzeugen

===============================================================================================

In der Funktion NeueDatendateiErzeugen () wird mir immer angezeigt, dass sensorList nicht bekannt ist.
Wie muss ich sensorList deklarieren, damit es funktioniert?
HILFE!
Gruß Gerd

Bei der Formatierung blickt man nicht durch.

Entweder du machst das Array global. Das ist eigentlich der normale Weg. Oder du übergibst es als Parameter.

void func(Sensor* sensorList)
{
}

Bei so vielen Strings solltest du übrigens das F()-Makro verwenden, damit die im Flash bleiben und nichts ins RAM kopiert werden:

Serial.println(F("String im Flash"));

Habe das Array jetzt Global, und nun funktioniert es. F("") ist auch umgesetzt.
Vielen Dank für die Hilfe.
Gruß Gerd