Verschiedene Datentypen im Zuge eines Sketch verwenden

Einen schönen Vormittag allerseits!

Ich habe ein Problem mit meinem Sketch, ich habe eine Funktion welche 1x als unsigned long deklariert werden muss/soll (Kommunikation Nextion Display mit Arduino) und 1x als double (PID Bibliothek verlangt hier einen double).
In meinem (jugendlichen) Leichtsinn habe ich ursprünglich diese Variable global als double deklariert.
Nun habe ich aber Probleme mit dem Einlesen der Daten von meinem Nextion Slider an den Arduino.
(Es werden zum Teil bei der Verstellung Werte verschluckt und manchmal wird ohne Veränderung 0 ausgegeben obwohl zb. der letzte Wert 23 war)

Nun ist meine Vermutung, dass dies das Problem sein könnte, darum hier unter anderem die Frage wie ich es in diesem Fall am besten bewerkstellige.

Vielen Dank für die Unterstützung
lg

PS: Mit dem angehängten Sketch bekomme ich eine Compilerfehlermeldung:
‘varVomNextion’ was not declared in this scope

#include <Arduino.h>
#include <OneWire.h> // Sensor
#include <DallasTemperature.h> // Sensor
#include <Wire.h> // Sensor
#include <PID_v1.h> //PID

//////////////////////////////////////////////////
// Functions forward declaration(s)
bool readNex(Stream &s);
//////////////////////////////////////////////////
// Definitionen
//PinOut: Gelbes Kabel RX an TX2 Pin16 vom Arduino Mega / Blaues Kabel TX an RX2 Pin17 vom Arduino
#define ONE_WIRE_BUS 24 //DS18b20 Sensoren parallel an Pin24
#define RelayPin 34 //Lüfterrelais an Pin26

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Adresse_Schokotemp2 = {0x28, 0xB3, 0xB0, 0xDC, 0x35, 0x19, 0x01, 0xF7}; //Sensoradresse, zuvor mit anderem Sketch ermittelt
DeviceAddress Adresse_Wassertemp1 = {0x28, 0x47, 0x77, 0xDE, 0x35, 0x19, 0x01, 0x2D};

double Setpoint, Input, Output; // PID Deklarationen, ##Setpoint## war Inhalt in der globalen Deklaration
double wert_Schokotemp2; // Float Variable für Sensor in Schoko setzen
double wert_Schokotemp3; // Float Variable für Sensor in Schoko setzen
double wert_Wassertemp1;
const long interval = 2000;  //intervall
unsigned long vorherMillis = 0; //Deklaration Zeitsteuerung um die Isttemperatur für das Senden an den Nextion nur 1x pro Sekunde zu übermitteln
unsigned long currentMillis = millis();
const byte bufferSize = 15; //Deklaration & Festlegung der Buffergröße für das Empfangen der Settemp vom Nextion Slider
uint8_t buffer[bufferSize]; //Deklaration & Festlegung der Buffergröße für das Empfangen der Settemp vom Nextion Slider

//##########Links und Setting Parameter für die PID Regelung###########
PID myPID(&Input, &Output, &Setpoint, 2, 5, 0, P_ON_M, REVERSE); //P_ON_M specifies that Proportional on Measurement be used

void setup() {

  Serial.begin(9600); //Serielle Schnittstelle öffnen für seriellen Monitor
  Serial2.begin(9600); //Serielle Schnittstelle öffnen (Nextion)
  pinMode(RelayPin, OUTPUT);
  sensors.begin(); //DS18b20 Sensorkommunikation starten
  sensors.setResolution(Adresse_Schokotemp2, 10); // Auflösung DS18b20 setzen 10 Bit optimal bez. Wertspringen
  sensors.setResolution(Adresse_Wassertemp1, 10); // Auflösung DS18b20 setzen 10 Bit optimal bez. Wertspringen
  myPID.SetMode(AUTOMATIC); //PID Regler einschalten

}
bool readNex(Stream &s) {
  static uint8_t bIndex = 0;
  bool allesDa = false;
  if (s.available()) {
    uint8_t inChar = s.read();
    buffer[bIndex++] = inChar;
    // 0x71 bei diesen Paketen können drei 0xFF Bestandteil des Pakets sein,
    // also ergibt es nur Sinn auf die Delimiter hinter dem Wert zu testen
    if (inChar == 0xFF && (bIndex >= (*buffer == 0x71 ? 8 : 3)) &&
        buffer[bIndex - 2] == 0xFF && buffer[bIndex - 3] == 0xFF) {
      allesDa = true;
    } else {
      allesDa = (bIndex == bufferSize);
    }
  }
  if (allesDa) bIndex = 0; // Index zurücksetzen
  return allesDa;
}

void loop()
{

  Isttemp_erfassen(); //DS18b20 Temperatursensor initialisieren und Messung vornehmen
  Send_Isttemp_to_Nextion(); //Gemessene Schokotemp im Nextion darstellen
  Set_Temp_Eingang(); //Senden der Solltemperatur Nextion=>Arduino für Setzen der Settemp für den PID Regler

  Input = (wert_Schokotemp2 + wert_Wassertemp1) / 2.00; //Input Variable vom DS18b20 Sensor
  Setpoint = varVomNextion; //Solltemperatur für den PID vom Slider im Nextion
  //Setpoint = 10; //Fixer Setpoint zum Testen, danach Ersatz durch Sliderwert aus Funktion
  Luefterrelais(); //Lüfterrelaissteuerung
  myPID.Compute();
  analogWrite(3, Output);

  Serial.print("Schokotemperatur: "); Serial.print(wert_Schokotemp2); Serial.println(" °C");
  Serial.print("Wassertemperatur: "); Serial.print(wert_Wassertemp1); Serial.println(" °C");
  Serial.print("Input: "); Serial.print(Input); Serial.println(" °C");
  Serial.print("kp: "); Serial.print(myPID.GetKp()); Serial.print(" ");
  Serial.print("ki: "); Serial.print(myPID.GetKi()); Serial.print(" ");
  Serial.print("kd: "); Serial.print(myPID.GetKd()); Serial.println();
  Serial.print("                                    PID Output: "); Serial.println(Output);
  Serial.print("                                    PWM OUT: ");  Serial.println(analogRead(Output));
  Serial.print("Setpoint: "); Serial.println(Setpoint); //Werte vom Slider im seriellen Monitor einlesen

}
/////////////######Ausgelagerte Funktionen######//////////////////////
void Isttemp_erfassen() { //DS18b20 Temperatursensor initialisieren und Messung vornehmen´
  wert_Schokotemp3 = sensors.getTempC(Adresse_Schokotemp2);
  if (millis() - vorherMillis >= interval) {
    vorherMillis = millis();
    sensors.requestTemperatures();
    wert_Schokotemp2 = sensors.getTempC(Adresse_Schokotemp2); //Temperaturen abholen
    wert_Wassertemp1 = sensors.getTempC(Adresse_Wassertemp1); //Temperaturen abholen
  }
}

void Send_Isttemp_to_Nextion() { // Gemessene Schokotemp im Nextion darstellen

  if (wert_Schokotemp2 != wert_Schokotemp3) {
    char prBuffer[23]  = "";
    char result[6];                 //Buffer für 5 digits, zB 25,60 °C
    dtostrf(wert_Schokotemp2, 2, 0, result);
    sprintf(prBuffer, "IstTempNr0.txt=\"%s\"", result);
    Serial2.print(prBuffer); //Resultausgabe aus dtostrf für den seriellen Monitor auf seriellem Port 2 für das Display
    Serial2.write(0xff);
    Serial2.write(0xff);
    Serial2.write(0xff);
  }

}

void Set_Temp_Eingang() {//Senden der Solltemperatur Nextion=>Arduino für Setzen der Settemp für den PID Regler
  unsigned long varVomNextion = 0;
  bool fertig = readNex(Serial2);
  if (fertig && buffer[0] == 0x71) { // numerische Daten
    varVomNextion = buffer[1] + buffer[2] * 256 + buffer[3] * 65536 + buffer[4] * 16777216;

  }

}
void Luefterrelais() { //Luefterrelaissteuerung
  if (Input >= Setpoint) {
    digitalWrite(RelayPin, HIGH);
  }
  else {
    digitalWrite(RelayPin, LOW);
  }
}

Vermeide überflüssige globale Variablen, wo es nur geht.

Funktionen haben im Idealfall Parameter und einen Rückgabewert, aber keine Seiteneffekte.

'varVomNextion' was not declared in this scope

Da wird der Kompiler wohl recht haben.

Da gebe ich dir recht, ich weiss aber nicht wie ich dies in dem Fall bewerkstelligen soll.

ich habe eine Funktion welche 1x als unsigned long deklariert werden

Funktionen kann man überladen. Es ist also beides möglich. void funktion(unsigned long value); void funktion(double value);

Das sind zwei verschiedene Funktionen, der Kompiler sucht sich anhand des Parameters die am besten passende raus.

ein global definierter Datentyp wird aber nicht durch den in der Funktion definierten überschrieben oder? (für diese Funktion)

ich habe nämlich das Problem, das ich Setpoint für die PID Bibliothek global deklarieren "muss" da die Setup Parameter des PID vor dem SETUP Teil drin sind. (Zumindest ist die Vorlage so)

ich habe nämlich das Problem, das ich Setpoint für die PID Bibliothek global deklarieren "muss" da die Setup Parameter des PID vor dem SETUP Teil drin sind. (Zumindest ist die Vorlage so)

Ja, ist wohl so. Aber warum das ein Problem ist, sehe ich nicht.

ein global definierter Datentyp wird aber nicht durch den in der Funktion definierten überschrieben oder? (für diese Funktion)

Doch, natürlich! Lokale Variablen überdecken globale Variablen.

int test = 42;

void funktion()
{
  int test = 4711; // überdeckt globale Variable
  Serial.println(test); // zeigt lokale Variable
  Serial.println(::test); // zeigt globale Variable
}

Hallo,

kann ja sein das ich Dein Problem nicht ganz verstanden habe. Willst Du nicht nur eine long Variable in eine double Variable convertieren.

Heinz

combie:
Ja, ist wohl so.
Aber warum das ein Problem ist, sehe ich nicht.

Doch, natürlich!
Lokale Variablen überdecken globale Variablen.

int test = 42;

void funktion()
{
 int test = 4711; // überdeckt globale Variable
 Serial.println(test); // zeigt lokale Variable
 Serial.println(::test); // zeigt globale Variable
}

Ahh jetzt verstehe ich, dann kann ich ja die Variable Global definieren und in der Funktion dann spezifisch nochmal…

Rentner: Hallo,

kann ja sein das ich Dein Problem nicht ganz verstanden habe. Willst Du nicht nur eine long Variable in eine double Variable convertieren.

Heinz

ich brauche setpoint global als double und in einer Funktion als unsigned long

ich brauche setpoint global als double und in einer Funktion als unsigned long

Und was hältst du von convertieren bzw. wandeln.

wie mach ich das?

night0222:
wie mach ich das?

Sorry…K.A…
Ich würde danach googeln. :wink:

ich brauche setpoint global als double und in einer Funktion als unsigned long

Wer zwingt dich denn dazu, dass die beiden Variablen den gleichen Namen tragen müssen?

Ansonsten: Ich rate dir zu einem schönen, dicken und modernen C++ Buch. Da drin ist das ganze SprachZeugs beschrieben/erklärt.

Hallo,

Na ich dachte du bist schon angekommen. Ich hab mal was auf die Schnelle gemacht. Auf einem UNO hat allerdings auch double nur 16 32 bit damit kann es wie float 6 Stellen darstellen.

Es gibt die Möglichkeit mit zwei Variablen zu arbeiten oder die einfach an eine Funktion zu übergeben.

Heinz

long set_l =123456789; // Anzahl der Stellen zu hoch
double set_d;   // auch double hat nur 16 bit beim UNO

double set=1234.56; // 

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

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

  set_d = set_l; // Lösung mit zwei Variablen 
  Serial.println(set_l);
  Serial.println(set_d);
  function(set);
  delay(500);
}

void function(unsigned long set) { // Übergabe als parameter
  // set ist hier lokal 
 Serial.print ("in der Function " );Serial.println(set);
}

An Rentner, Danke für die Info, ich lerne ja so langsam dazu…
Als Newbie stell ich halt blöde Fragen, tut mir leid.
Ich hab übrigens ein C Buch :wink: nur muss man alles halt mal verstehen (Everything linking together :wink:

Ich habs jetzt so gemacht:

#include <Arduino.h>
#include <OneWire.h> // Sensor
#include <DallasTemperature.h> // Sensor
#include <Wire.h> // Sensor
#include <PID_v1.h> //PID

//////////////////////////////////////////////////
// Functions forward declaration(s)
bool readNex(Stream &s);
//////////////////////////////////////////////////
// Definitionen
//PinOut: Gelbes Kabel RX an TX2 Pin16 vom Arduino Mega / Blaues Kabel TX an RX2 Pin17 vom Arduino
#define ONE_WIRE_BUS 24 //DS18b20 Sensoren parallel an Pin24
#define RelayPin 34 //Lüfterrelais an Pin26

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Adresse_Schokotemp2 = {0x28, 0xB3, 0xB0, 0xDC, 0x35, 0x19, 0x01, 0xF7}; //Sensoradresse, zuvor mit anderem Sketch ermittelt
DeviceAddress Adresse_Wassertemp1 = {0x28, 0x47, 0x77, 0xDE, 0x35, 0x19, 0x01, 0x2D};

double Setpoint, Input, Output; // PID Deklarationen, ##Setpoint## war Inhalt in der globalen Deklaration
double wert_Schokotemp2; // Float Variable für Sensor in Schoko setzen
double wert_Schokotemp3; // Float Variable für Sensor in Schoko setzen
double wert_Wassertemp1;
const long interval = 2000;  //intervall
unsigned long vorherMillis = 0; //Deklaration Zeitsteuerung um die Isttemperatur für das Senden an den Nextion nur 1x pro Sekunde zu übermitteln
unsigned long currentMillis = millis();
unsigned long varVomNextion;
const byte bufferSize = 15; //Deklaration & Festlegung der Buffergröße für das Empfangen der Settemp vom Nextion Slider
uint8_t buffer[bufferSize]; //Deklaration & Festlegung der Buffergröße für das Empfangen der Settemp vom Nextion Slider

//##########Links und Setting Parameter für die PID Regelung###########
PID myPID(&Input, &Output, &Setpoint, 2, 5, 0, P_ON_M, REVERSE); //P_ON_M specifies that Proportional on Measurement be used

void setup() {

  Serial.begin(9600); //Serielle Schnittstelle öffnen für seriellen Monitor
  Serial2.begin(9600); //Serielle Schnittstelle öffnen (Nextion)
  pinMode(RelayPin, OUTPUT);
  sensors.begin(); //DS18b20 Sensorkommunikation starten
  sensors.setResolution(Adresse_Schokotemp2, 10); // Auflösung DS18b20 setzen 10 Bit optimal bez. Wertspringen
  sensors.setResolution(Adresse_Wassertemp1, 10); // Auflösung DS18b20 setzen 10 Bit optimal bez. Wertspringen
  myPID.SetMode(AUTOMATIC); //PID Regler einschalten

}
bool readNex(Stream &s) {
  static uint8_t bIndex = 0;
  bool allesDa = false;
  if (s.available()) {
    uint8_t inChar = s.read();
    buffer[bIndex++] = inChar;
    // 0x71 bei diesen Paketen können drei 0xFF Bestandteil des Pakets sein,
    // also ergibt es nur Sinn auf die Delimiter hinter dem Wert zu testen
    if (inChar == 0xFF && (bIndex >= (*buffer == 0x71 ? 8 : 3)) &&
        buffer[bIndex - 2] == 0xFF && buffer[bIndex - 3] == 0xFF) {
      allesDa = true;
    } else {
      allesDa = (bIndex == bufferSize);
    }
  }
  if (allesDa) bIndex = 0; // Index zurücksetzen
  return allesDa;
}

void loop()
{

  Isttemp_erfassen(); //DS18b20 Temperatursensor initialisieren und Messung vornehmen
  Send_Isttemp_to_Nextion(); //Gemessene Schokotemp im Nextion darstellen
  Set_Temp_Eingang(); //Senden der Solltemperatur Nextion=>Arduino für Setzen der Settemp für den PID Regler
  PID_PART();//PID Berechnung und Ausgabe an das SSR
  Luefterrelais(); //Lüfterrelaissteuerung


  Serial.print("Schokotemperatur: "); Serial.print(wert_Schokotemp2); Serial.println(" °C");
  Serial.print("Wassertemperatur: "); Serial.print(wert_Wassertemp1); Serial.println(" °C");
  Serial.print("Input: "); Serial.print(Input); Serial.println(" °C");
  Serial.print("kp: "); Serial.print(myPID.GetKp()); Serial.print(" ");
  Serial.print("ki: "); Serial.print(myPID.GetKi()); Serial.print(" ");
  Serial.print("kd: "); Serial.print(myPID.GetKd()); Serial.println();
  Serial.print("                                    PID Output: "); Serial.println(Output);
  Serial.print("                                    PWM OUT: ");  Serial.println(analogRead(Output));


}
/////////////######Ausgelagerte Funktionen######//////////////////////

void Isttemp_erfassen() { //DS18b20 Temperatursensor initialisieren und Messung vornehmen´
  wert_Schokotemp3 = sensors.getTempC(Adresse_Schokotemp2);
  if (millis() - vorherMillis >= interval) {
    vorherMillis = millis();
    sensors.requestTemperatures();
    wert_Schokotemp2 = sensors.getTempC(Adresse_Schokotemp2); //Temperaturen abholen
    wert_Wassertemp1 = sensors.getTempC(Adresse_Wassertemp1); //Temperaturen abholen
  }
}

void Send_Isttemp_to_Nextion() { // Gemessene Schokotemp im Nextion darstellen

  if (wert_Schokotemp2 != wert_Schokotemp3) {
    char prBuffer[23]  = "";
    char result[6];                 //Buffer für 5 digits, zB 25,60 °C
    dtostrf(wert_Schokotemp2, 2, 0, result);
    sprintf(prBuffer, "IstTempNr0.txt=\"%s\"", result);
    Serial2.print(prBuffer); //Resultausgabe aus dtostrf für den seriellen Monitor auf seriellem Port 2 für das Display
    Serial2.write(0xff);
    Serial2.write(0xff);
    Serial2.write(0xff);
  }

}

void Set_Temp_Eingang() {//Senden der Solltemperatur Nextion=>Arduino für Setzen der Settemp für den PID Regler
  unsigned long varVomNextion = 0;
  bool fertig = readNex(Serial2);
  if (fertig && buffer[0] == 0x71) { // numerische Daten
    varVomNextion = buffer[1] + buffer[2] * 256 + buffer[3] * 65536 + buffer[4] * 16777216;

  }

}

void PID_PART() {//PID Berechnung und Ausgabe an das SSR
  Input = (wert_Schokotemp2 + wert_Wassertemp1) / 2.00; //Input Variable vom DS18b20 Sensor
  Setpoint = varVomNextion; //Solltemperatur für den PID vom Slider im Nextion
  myPID.Compute();
  analogWrite(3, Output);
  Serial.print("Setpoint: "); Serial.println(Setpoint); //Werte vom Slider im seriellen Monitor einlesen
}
void Luefterrelais() { //Luefterrelaissteuerung
  if (Input >= Setpoint) {
    digitalWrite(RelayPin, HIGH);
  }
  else {
    digitalWrite(RelayPin, LOW);
  }
}

Rentner: Auf einem UNO hat allerdings auch double nur 16 bit damit kann es wie float 6 Stellen darstellen.

Nö, es sind 32 Bit.

void Set_Temp_Eingang() {//Senden der Solltemperatur Nextion=>Arduino für Setzen der Settemp für den PID Regler
  unsigned long varVomNextion = 0;
  bool fertig = readNex(Serial2);
  if (fertig && buffer[0] == 0x71) { // numerische Daten
    varVomNextion = buffer[1] + buffer[2] * 256 + buffer[3] * 65536 + buffer[4] * 16777216;

  }

}

Das wird doch alles verworfen...

Statt

bool fertig = readNex(Serial2); reicht auch readNex(Serial2); Da fertig nie verwendet wird. OK, im if. Aber das if ist eben auch überflüssig

varVomNextion = buffer[1] + buffer[2] * 256 + buffer[3] * 65536 + buffer[4] * 16777216; Die Zuweisung ist überflüssig, weil varVomNextion am Ende der Funktion verfällt.

Merksatz: Lokale Variablen verfallen, wenn der Geltungsbereich verlassen wird. Es sei denn sie sind static, aber das bringt wieder andere Probleme mit sich.

Ich hab übrigens ein C Buch ;-)

Das hilft nicht viel weiter. Denn die Sprache welche du verwendest ist C++ und nicht C

Whandall: Nö, es sind 32 Bit.

Hallo,

danke für den Hinweis, ist geändert.

Heinz

combie: Das wird doch alles verworfen...

Statt

bool fertig = readNex(Serial2); reicht auch readNex(Serial2); Da fertig nie verwendet wird. OK, im if. Aber das if ist eben auch überflüssig

varVomNextion = buffer[1] + buffer[2] * 256 + buffer[3] * 65536 + buffer[4] * 16777216; Die Zuweisung ist überflüssig, weil varVomNextion am Ende der Funktion verfällt.

Kannst du mir da eindringlicher helfen? der Einzelsketch war genau so und der hat funktioniert...

//***********************Bereich für Empfangen von Soll Temperaturwerten des Nextion Nummernfelds setTempNr0 auf page0 (Solltemp)
// Die Hex ID 0x71 wird vom Nextion bei Betätigung des Buttons gesendet (Im Debugger im Nextion Editor ersichtlich)
const byte bufferSize = 15;
uint8_t buffer[bufferSize];

void setup() {   Serial.begin(9600);   Serial2.begin(9600); }

bool readNex(Stream &s) {   static uint8_t bIndex = 0;   bool allesDa = false;   if (s.available()) {     uint8_t inChar = s.read();     buffer[bIndex++] = inChar;     // 0x71 bei diesen Paketen können drei 0xFF Bestandteil des Pakets sein,     // also ergibt es nur Sinn auf die Delimiter hinter dem Wert zu testen     if (inChar == 0xFF && (bIndex >= (*buffer == 0x71 ? 8 : 3)) &&         buffer[bIndex - 2] == 0xFF && buffer[bIndex - 3] == 0xFF) {       allesDa = true;     } else {       allesDa = (bIndex == bufferSize);     }   }   if (allesDa) bIndex = 0; // Index zurücksetzen   return allesDa; }

void loop() {

  double varVomNextion = 0;   bool fertig = readNex(Serial2);   if (fertig && buffer[0] == 0x71) { // numerische Daten     varVomNextion = buffer[1] + buffer[2] * 256 + buffer[3] * 65536 + buffer[4] * 16777216;     Serial.println(varVomNextion);   }

  }

Kannst du mir da eindringlicher helfen? der Einzelsketch war genau so und der hat funktioniert...

Ja,, da gibts immerhin eine Ausgabe. Die funktioniert. Aber in deinem Programm gibts nicht mal die, also kann der Rest auch weg. ODer? Warum soll man etwas berechnen, was man sowieso nicht ausgibt?

Tipp: Funktionen sollten immer nur eine Sache machen! Und das möglichst gut.