MAX31865 - Problem beim Werte auslesen in einer Schleife

Hallo,

Ich habe mich hier angemeldet um hoffentlich Hilfe zu bekommen.
Komme selbst nicht mehr weiter....

Zum Vorhaben:
Ich würde mir gerne ein kleines Messsystem für unterschiedliche Sensoren basteln.
der Anfang soll erst mal nur ein PT100 machen, den ich mit 10Hz (100ms) abtasten möchte.

Dazu habe ich mir ein bisschen was Programmiert und aus anderen Beispielen zusammengebaut was bisher für die Abtastung und Bedienung gut funktioniert.
Arduino Mega 2560 starten - und wartet dann auf die Eingabe von Befehlen -> mit "s" wird die Messung gestartet - solange bis wieder ein "s" geschickt wird, danach wird die Messung gestoppt. Das klappt soweit.

Jetzt würde ich gerne den PT100 integrieren.
Angefangen habe ich mit dem Beispiel aus der MAX31865 Library von Adafruit - da bekomme ich auch schön die Werte angezeigt, die mein Sensor gerade liefert.

Wenn ich allerdings die Werte nun in meinem Programm abrufe, habe ich anfangs nur -242°C zurück bekommen.
Wenn ich beim "void setup()" einmalig den Wert abfrage, bekomme ich die korrekte Temperatur ausgelesen.
Allerdings bleibt dann dieser Wert dauerhaft erhalten, meine Schleife die für während Messdauer läuft, schickt mir also immer den selben alten Wert zurück, obwohl ich jedes mal einen neuen Wert anfordere.

Und mittlerweile habe ich keine Idee mehr woran es liegen könnte.

Leider darf ich mein Programm nicht komplett hochladen, da ich ein neuer User bin...
Daher hier mein Code am Ende dieser Nachricht.

Grüße
Patrick

Mein Code:

#include <Adafruit_MAX31865.h>
bool stop_meas;
int t_xdel = 0;

//------ MAX31865 bzw.  PT100 Initialization : -----------------------------
Adafruit_MAX31865 RTD = Adafruit_MAX31865(10); // use hardware SPI, just pass in the CS pin
#define RREF      430.0 // The value of the Rref resistor. Use 430.0 for PT100 and 4300.0 for PT1000
#define RNOMINAL  100.0 // 100.0 for PT100, 1000.0 for PT1000
//--------------------------------------------------------------------------


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // ---- PT100 Initialization: ------------------------------------------
  RTD.begin(MAX31865_4WIRE);  // set to 2WIRE or 4WIRE as necessary
  //Debug - Test ob Werte sich ändern:
  delay(200);
  Serial.println(RTD.temperature(RNOMINAL, RREF), 6);
  delay(200);
  Serial.println(RTD.temperature(RNOMINAL, RREF), 6);
  delay(200);
  Serial.println(RTD.temperature(RNOMINAL, RREF), 6);
  RTD.clearFault(); //Sicherheitshalber Fehler löschen
  
  // ----------------------------------------------------------------------
 
  Init_Internal_Timer();
 
  Serial.print("Commands:\n");
  Serial.print("s = Start & Stop Measurement\n");
  Serial.print("? = show commands\n");
  Serial.print("Initialization completed - Wait for Input\n");
 
}

void loop() {
  // put your main code here, to run repeatedly:

  while (Serial.available() > 0) {
    char command  = Serial.read();
    doCommand(command);
  }

}


//----------- Methode -> Serielle Abfrage der Eingabe:
void doCommand(char command)
{
  switch (command) {
    case '?':
      Serial.print("Commands:\n");
      Serial.print("s = Start & Stop Measurement\n");
      Serial.print("? = show commands\n");

      break;

    case 's':
      stop_meas = false; //Stop Variable initialisieren
      
      Serial.println("---- Start of Measurement ----");
      Serial.println("Time ; PT100 [C] ; MW2 ; MW ; ...");
      Run_Measurement(); //Hier werden alle Messwerte aufgenommen und ausgegeben
      Serial.println("---- End of Measurement ----");
      break;

  }
}


//---------- Interner Timer hochzählen lassen :
// Muss Auserhalb der Loop schleife stehen
ISR(TIMER0_COMPA_vect) {   //This is the interrupt request - every 0.001s (1kHz)
  t_xdel++;
}
//-------------------------------------
//Initialization of internal timer
void Init_Internal_Timer() {
  //TCCRx - Timer / Zählersteuerregister. Der Prescaler kann hier konfiguriert werden.
  TCCR0A = (1 << WGM01); //Set the CTC mode

  //OCRx - Ausgabevergleichsregister
  //OCRn=[(clock_speed/Prescaler_value)*Desired time in secounds]-1
  OCR0A = 0xF9; //Value for ORC0A for 1ms / 0.001s / 1kHz

  //TIMSKx - Timer / Zählerunterbrechungsmaskenregister. Zum Aktivieren / Deaktivieren von Timer-Interrupts.
  TIMSK0 |= (1 << OCIE0A); //Set the interrupt request
  sei(); //Enable interrupt

  //TCCRx - Timer / Zählersteuerregister. Der Prescaler kann hier konfiguriert werden.
  //TCCR 0B = Timer/Counter Control Register 0B
  TCCR0B |= (1 << CS01); //Set the prescale 1/64 clock
  TCCR0B |= (1 << CS00);

}
void Run_Measurement() {
 
  //Solange bis Messung abgebrochen wird.
  //String Meas_Values;
  float t = 0;
  int xdel = 100; // 100*0.001s = 100ms - 10Hz
  /* 1 - 1kHz
    10 - 100Hz
    100 - 10Hz
    1000 - 1Hz
  */

  while (stop_meas == false) {
    
    /*---------------- Wenn Abtastevent auftritt: -------------------------*/
    if (t_xdel >= xdel) { // 100*0.001s = 100ms - 10Hz
      t_xdel = 0;
      /*Meas_Values = Meas_Values + String(t, 3) + ";";                                      // Time
        Meas_Values = Meas_Values + String(PT100.temperature(RNOMINAL, RREF), 6)+ ";";      // Messwert 1
        Meas_Values = Meas_Values + "\n";                                                    // Neue Zeile
        ---> Offenbar ist der Speicher nicht groß genug um alle Werte in einer Variablen zu speichern ?
              - ggf. später über Wlan oder Netzwerk Board direkt in eine Datei schreiben
      */

      /*----- Messdaten erst mal direkt ausgeben - geht offenbar noch bei 10Hz: */
      Serial.print(String(t, 3) + ";");
      Serial.print(RTD.temperature(RNOMINAL, RREF), 6); //Erst mal direkt auslesen, später mit Fehler über Funktion
      Serial.print(";");
      //Serial.print(String(Read_PT100(), 6) + ";"); //PT100 Messwert direkt aus Funktion lesen
      Serial.print("\n");
      /*----- Ende Messdatenausgabe */
  
      t = t + (xdel * 0.001); // Timer - je nach Abtastung hochzählen
    }
    /*-----------------------------------------------------------------------*/
    /*---------------- Abfragen ob Messung beendet werden soll --------------*/
    while (Serial.available() > 0) {//Wenn Serial verfügbar // .available fragt nur ab wie lange die Daten sind die ankommen.
      char command  = Serial.read(); //Serielle Daten einlesen in Variable
      switch (command) {
        case 's': //wenn s geschickt - dann Messung beenden
          stop_meas = true;
          //Serial.print(Meas_Values); //Messwerte anzeigen die aufgenommen worden sind
          break;
      }
    }
    /*------------------------------------------------------------------------*/
  }
}
float Read_PT100() {
  //Messwert lesen:
  float Value;
  Value = RTD.temperature(RNOMINAL, RREF);
 
  //----- Falls Fehler vorhanden:
  //Check and print any faults
  uint8_t fault = RTD.readFault();
  if (fault) {
    Serial.print("Fault 0x"); Serial.println(fault, HEX);
    if (fault & MAX31865_FAULT_HIGHTHRESH) {
      Serial.println("PT100 - RTD High Threshold");
    }
    if (fault & MAX31865_FAULT_LOWTHRESH) {
      Serial.println("PT100 - RTD Low Threshold");
    }
    if (fault & MAX31865_FAULT_REFINLOW) {
      Serial.println("PT100 - REFIN- > 0.85 x Bias");
    }
    if (fault & MAX31865_FAULT_REFINHIGH) {
      Serial.println("PT100 - REFIN- < 0.85 x Bias - FORCE- open");
    }
    if (fault & MAX31865_FAULT_RTDINLOW) {
      Serial.println("PT100 - RTDIN- < 0.85 x Bias - FORCE- open");
    }
    if (fault & MAX31865_FAULT_OVUV) {
      Serial.println("PT100 - Under/Over voltage");
    }
    RTD.clearFault();
    
  }
  
  return Value;
}

Arduino verwendet Timer0 für millis() Timeouts usw.

Wenn du Timer0 unabhängig verwenden möchtest, solltest du auch auf den Rest des Arduino Frameworks verzichten.
Klarer:
setup und loop weglassen und stattdessen eine eigene main() einführen.

Alternativ:
Natürlich kannst du auch

mit dem Framework verwenden, verlierst dann aber einen PWM Kanal, oder fängst dir Jitter ein.
Liegst dann bei ca 980Hz.

Hi, danke schonmal für die Antwort.

Ich tue mir ein wenig schwer es wirklich zu verstehen.
Was ich verstanden habe:
Wenn ich den Timer0 verwende, kommt es zu Problemen, weil dieser schon an einer anderen Stelle durch die Standard Arduino Befehle genutzt werden.

Damit bleibt mir nur die Möglichkeit alles was Arduino von Haus aus liefert - zu verwerfen, und mir irgendwie selbst die Ansteuerung zu Programmieren.
Dafür finde ich aber nicht wirklich was über Google - wie ich die Setup und Loop Funktion umgehe.

Oder:
Ich verwende statt Timer0 die millis() Funktion, um mir eine feste Abtastung meiner Messwerte zu erstellen. - Ich weiß zwar noch nicht wie, aber da fällt mir evtl. noch was ein.

Soweit richtig ?

Nein, die Probleme stellen sich nur ein, wenn du ihn gänzlich umprogrammierst, was du ja tust. Oder zusätzlich den betreffenden PWM Kanal nutzt.

Das habe ich dir doch schon erklärt!
Aber gerne nochmal:
loop() und setup() weglassen!
stattdessen eine main() einführen.

Warum willst du dann überhaupt die Arduino IDE verwenden ?

Oder umgekehrt, warum vermurkst du den Timer ? Es gibt eine Funktion, die mit 1 kHz (jede ms) einen Zähler um eins erhöht! --> millis() , aber das hast du ja schon selber gefunden.

float t;
t = t + (xdel * 0.001);

ist natürlich Unsinn auf einem Controller ohne Gleitkomma-Hardware. Denke in Millisekunden und wandle diese (höchstens) bei der Ausgabe, wenn du sonst keine Probleme mehr hast :)...

Danke nochmal für die Antworten.
(Vielleicht noch als Ergänzung zum Ursprünglichen Post, das ist so ziemlich das erste Projekt was ich mit dem Arduino machen möchte, daher ist eigentlich noch fast alles neu für mich.)

das mit dem Setup() und loop() habe ich glaube ich hinbekommen:

allerdings hilft mir das noch nicht wirklich weiter... identischer Fehler wie vorher.

@ michael_x
das mit dem millis() probiere ich als nächstes aus.

Hallo nochmal,

Mit dem millis() habe ich es zumindest hinbekommen das sich nun die Werte entsprechend ändern.

Allerdings schaffe ich nun gerade so noch die 10Hz - wenn ich auf 100Hz Abtastung gehen will, kommt der Arduino schon nicht mehr nach, was mit dem Timer0 noch ganz gut geklappt hatte.

Vieleicht kann @combie ja nochmal drüber schauen, oder mir evtl. nochmal genauer erklären wie ich es ändern muss.
Wie gesagt, bin noch ganz am Anfang, und es ist quasi alles noch ziemlich neu, daher tue ich mir auch etwas schwer die Tipps direkt umzusetzen.

#include <Adafruit_MAX31865.h>
bool stop_meas;

//------ MAX31865 bzw.  PT100 Initialization : -----------------------------
Adafruit_MAX31865 RTD = Adafruit_MAX31865(10); // use hardware SPI, just pass in the CS pin
#define RREF      430.0 // The value of the Rref resistor. Use 430.0 for PT100 and 4300.0 for PT1000
#define RNOMINAL  100.0 // 100.0 for PT100, 1000.0 for PT1000
//--------------------------------------------------------------------------


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // ---- PT100 Initialization: ------------------------------------------
  RTD.begin(MAX31865_4WIRE);  // set to 2WIRE or 4WIRE as necessary
  RTD.clearFault(); //Sicherheitshalber Fehler löschen
   // ----------------------------------------------------------------------
 
  
  Serial.print("Commands:\n");
  Serial.print("s = Start & Stop Measurement\n");
  Serial.print("? = show commands\n");
  Serial.print("Initialization completed - Wait for Input\n");
 
}


void loop() {
  // put your main code here, to run repeatedly:

  while (Serial.available() > 0) {
    char command  = Serial.read();
    doCommand(command);
  }

}


//----------- Methode -> Serielle Abfrage der Eingabe:
void doCommand(char command)
{
  switch (command) {
    case '?':
      Serial.print("Commands:\n");
      Serial.print("s = Start & Stop Measurement\n");
      Serial.print("? = show commands\n");

      break;

    case 's':
      stop_meas = false; //Stop Variable initialisieren
      
      Serial.println("---- Start of Measurement ----");
      Serial.println("Time ; PT100 [C] ; MW2 ; MW ; ...");
      Run_Measurement(); //Hier werden alle Messwerte aufgenommen und ausgegeben
      Serial.println("---- End of Measurement ----");
      break;

  }
}
float Read_PT100() {
  //Messwert lesen:
  float Value;
  Value = RTD.temperature(RNOMINAL, RREF);
 
  //----- Falls Fehler vorhanden:
  //Check and print any faults
  uint8_t fault = RTD.readFault();
  if (fault) {
    Serial.print("Fault 0x"); Serial.println(fault, HEX);
    if (fault & MAX31865_FAULT_HIGHTHRESH) {
      Serial.println("PT100 - RTD High Threshold");
    }
    if (fault & MAX31865_FAULT_LOWTHRESH) {
      Serial.println("PT100 - RTD Low Threshold");
    }
    if (fault & MAX31865_FAULT_REFINLOW) {
      Serial.println("PT100 - REFIN- > 0.85 x Bias");
    }
    if (fault & MAX31865_FAULT_REFINHIGH) {
      Serial.println("PT100 - REFIN- < 0.85 x Bias - FORCE- open");
    }
    if (fault & MAX31865_FAULT_RTDINLOW) {
      Serial.println("PT100 - RTDIN- < 0.85 x Bias - FORCE- open");
    }
    if (fault & MAX31865_FAULT_OVUV) {
      Serial.println("PT100 - Under/Over voltage");
    }
    RTD.clearFault();
    
  }
  
  return Value;
}
void Run_Measurement() {

  unsigned long t0 = 0;
  unsigned long tx = 0;
  int xdel = 100;
  int Trel = 0;


  //Solange bis Messung abgebrochen wird.
  while (stop_meas == false) {

    t0 = millis();
    /*--------------------------Wenn Abtastevent auftritt: -----------------------------------*/
    if (t0 - tx >= xdel) {
      tx = t0; // letzten Zeitpunkt in Startbedingung schreiben - damit neuer Zyklus wieder 100ms lang ist.
      Trel=Trel+xdel; //Relative Messdauer hochzählen
      Serial.print(float(Trel)/1000, 3);
      Serial.print(";");
      Serial.print(String(Read_PT100(), 6) + ";"); //PT100 Messwert direkt aus Funktion lesen
      Serial.print("\n");
    }

    /*-----------------------------------------------------------------------*/
    /*---------------- Abfragen ob Messung beendet werden soll --------------*/
    while (Serial.available() > 0) {//Wenn Serial verfügbar // .available fragt nur ab wie lange die Daten sind die ankommen.
      char command  = Serial.read(); //Serielle Daten einlesen in Variable
      switch (command) {
        case 's': //wenn s geschickt - dann Messung beenden
          stop_meas = true;
          //Serial.print(Meas_Values); //Messwerte anzeigen die aufgenommen worden sind
          break;
      }
    }
    /*------------------------------------------------------------------------*/
  }
}

Warum sehe ich drei Codefenster?
Kannst Du das nicht in einen Code packen?

Hier macht es Dir kaputt...

Folgender Code:

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
}

void loop()
{
  Serial.println("Das ist ein Text, der ausgegeben wird.");
}

gibt u.a. aus:

19:59:37.036 -> Das ist ein Text, der ausgegeben wird.
19:59:37.036 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.136 -> Das ist ein Text, der ausgegeben wird.
19:59:37.136 -> Das ist ein Text, der ausgegeben wird.

Zu beachten sind die Lücken:

19:59:37.036 -> Das ist ein Text, der ausgegeben wird.
19:59:37.103 -> Das ist ein Text, der ausgegeben wird.
//
19:59:37.105 -> Das ist ein Text, der ausgegeben wird.
19:59:37.136 -> Das ist ein Text, der ausgegeben wird.

Vielleicht hilfts.

Das sind PC Lücken.
Also hier null Komma null von Belang.

Danke für die Tipps,
ich hab mein Programm jetzt erst mal so geändert, das ich auf Timer 4 statt Timer 0 gehe, damit läuft es.

Das mit dem Seriellen Monitor ist mir auch schon aufgefallen, denke da muss ich noch einiges lernen bis ich an höhere Frequenzen dran komme. Unnötige Befehle weglassen, oder alternativen nutzen.

Vielen Dank nochmal an alle für die schnelle Hilfe :slight_smile: