Ms/cm in gramm umrechen

Hallo,

ich habe hier ein TDS Sensor wo ich den mS/cm von Salzwasser messe. nun wollte ich aber das ganze in g/L umrechnen so das ich weiss wieviel Salz ich im Wasser habe.

Kann dazu eventuell jemand etwas sagen?

über die SPS funktioniert das schon, nur leider ist dort eine etwas andere Vorgehensweise bei der Umrechnung. Da der Arduino diesen Code ja nicht versteht und ich keinen Ansatz dafür habe hoffe ich hier auf Hilfe.
der Arduino Code

void EC()  // ermitteln des ec wertes
{
  static unsigned long timepoint = millis();
  if (millis() - timepoint > 1000U)  //time interval: 1s
  {
    timepoint = millis();
    voltage = analogRead(EC_PIN) / 1024.0 * 5000;  // read the voltage
    //temperature = readTemperature();          // read your temperature sensor to execute temperature compensation
    ecValue = ec.readEC(voltage, temperature);  // convert voltage to EC with temperature compensation

#ifdef DEBUG1                                   // Ausgabe im Serialen Monitor deaktiviert
    Serial.print("temperature:");
    Serial.print(temperature, 1);
    Serial.print("^C  EC:");
    Serial.print(ecValue, 2);
    Serial.println("ms/cm");
#endif
  }
  ec.calibration(voltage, temperature);  // calibration process by Serail CMD
}

und hier noch der Code der in der SPS am laufen ist.

VAR
r_salzgehalt  : REAL:=0;
r_Leitwert    : REAL:=0;

A1   : REAL;
A2   : REAL;
A3   : REAL;
SF	 : REAL := 553;

END_VAR

	salzgehalt   	:= TO_WORD (r_salzgehalt*10.0);
 	r_Leitwert     	:= TO_REAL (Leitwert)/10.0;
  	Leitwert_EC     := TO_WORD (r_Leitwert*10.0);
 	zelle_EN 		:= Z_EN;
 	
 if (BeckenTemp <= 10)then
	 A1:= -0.044532198;
	 A2:= -0.013174538;
	 A3:= 1.085694313;
 else
	 A1:= -0.073894632;
	 A2:= -0.010947644;
	 A3:= 1.09173096;

 end_if;

r_salzgehalt := expt( IN1 := 10,  IN2:= (A1 + BeckenTemp * A2 + A3 * log( in:= ABS( in:= r_Leitwert) ) ));
r_salzgehalt := r_salzgehalt *  SF/1000;

kann man daraus nicht auch für den Arduino etwas machen?

Moin @luzie ,

eine Umsetzung des SPS Codes auf C++ für Arduino könnte in etwa so aussehen:

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  Serial.println(salzGehalt(100.0,20.0));
}

void loop() {
}

float salzGehalt(float r_Leitwert_mS, float BeckenTemp) {
  const float SF	= 553;
  float r_salzgehalt = 0;
  float A1, A2, A3;
  if (BeckenTemp <= 10) {
    A1 = -0.044532198;
    A2 = -0.013174538;
    A3 = 1.085694313;
  } else {
    A1 = -0.073894632;
    A2 = -0.010947644;
    A3 = 1.09173096;
  }
  float r_Leitwert = r_Leitwert_mS/(1000.0);   
  float base = 10;
  float exponent = (A1 + BeckenTemp * A2 + A3 * log10 ( abs(r_Leitwert)));
  r_salzgehalt = pow(base, exponent);
  r_salzgehalt = r_salzgehalt *  SF/1000;
  return r_salzgehalt;
}

Der SPS Code umfasst ein paar Variable und Umsetzungen, die anscheinend für die Berechnung nicht relevant sind; das kann ich nur begrenzt beurteilen.

Die Funktion

  • float salzGehalt(float r_Leitwert_mS, float BeckenTemp)

erwartet den Leitwert in mS (Eingabe 1--> 1 mS), rechnet diese in die Einheit Sievers durch Teilen mit 1000 um. Als zweiter Parameter ist die Beckentemperatur einzugeben. Es gibt zwei unterschiedliche Sätze an Koeffizienten für Temperaturen größer als 10 (vermutlich Grad Celsius) und Werte darunter.

Die Größenordnungen der Eingabe/Ausgabewerte müsstest Du ggf. selbst anpassen, indem Du die Werte mit denen der SPS vergleichst.

Ich hoffe, dass Dir das irgendwie weiterhilft.
ec2021

@ec2021

hallo und danke dir, ja die A1 bis A3 werte hängen mit der Temeratur vom Wasser zusammen.
Ich werde es einmal testen und dann vergleichen, wenn es Funktioniert melde ich mich auf jedenfall noch einmal.
gruß luzie

der code bringt schon einmal keinen Fehler, aber es wird nicht gerechnet, er zeigt immer den selben wert an, auch wenn sich der Leitwert ändert bleibt der wert Salzgehalt immer gleich.
das serial print musste ich einmal in den loop setzen da mir sonst nichts angezeigt wird.

ergebniss vom arduino was aber nicht passt
14:25:48.202 -> 3.48 :g/L
14:25:48.245 -> 1.61 mS/cm

14:27:21.558 -> 8.25 mS/cm
14:27:24.347 -> 3.48 :g/L

ergbniss der sps
​16#0015 ​ ​2.080627 ​
salzgehalt := TO_WORD (r_salzgehalt*10.0);
​6.1 ​ ​16#003D ​
r_Leitwert := TO_REAL (Leitwert)/10.0;

Schreib mal, was Du für EIngangsdaten hast und was da zum Schluss rauskommen soll.
Also alle Variablen, damit man sich das erarbeiten kann, wo es klemmt.

Und: Auf was für einem Controller machst Du das?
Denke dran, dass bei float unter Umständen eine massive Ungenauigkeit zustande kommen kann.

1 Like

Der Code rechnet schon, aber wie @my_xy_projekt bereits geschrieben hat, hängt das Ergebnis stark von den verwendeten Wertebereichen ab.

Daher ist es erforderlich, reale Eingangs- und zugehörige Ergebniswerte zu kennen.

Günstig wäre eine Tabelle:

Leitwert in mS, Temperatur in °C, Salzgehalt in g/l

Dann kann man die Berechnung ggf. so umstellen, dass relevante Änderungen nicht "rechts" hinterm Komma herunterfallen.

Gruß
ec2021

hallo my_mx_projekt

ich habe einnmal nur den Code von dem DFRobot Teil herrausgenommen so das es übersichtlicher ist.

#include <Wire.h>
#include <SPI.h>
#include <EEPROM.h>
#include "DFRobot_EC.h"

void EC();

int EC_PIN {4}; // Analopin Arduino Lepnardo ETH
float voltage, ecValue, temperature = 21;    // fiktiver Wert da kein onewire sensor angeschliossen ist
DFRobot_EC ec;


void setup() {
  Wire.begin();                // enable I2C port.
  Serial.begin(115200);
}

void loop() {
  EC();            // Auslesen TDS Sensor ppm Wert

  Serial.print(salzGehalt(100.0,20.0));
  Serial.println(" :g/L");
  Serial.print(ecValue);
  Serial.println(" mS/cm");
}

void EC()  // ermitteln des ec wertes
{
  static unsigned long timepoint = millis();
  if (millis() - timepoint > 1000U)  //time interval: 1s
  {
    timepoint = millis();
    voltage = analogRead(EC_PIN) / 1024.0 * 5000;  // read the voltage
    //temperature = readTemperature();          // read your temperature sensor to execute temperature compensation
    ecValue = ec.readEC(voltage, temperature);  // convert voltage to EC with temperature compensation

#ifdef DEBUG1                                   // Ausgabe im Serialen Monitor deaktiviert
    Serial.print("temperature:");
    Serial.print(temperature, 1);
    Serial.print("^C  EC:");
    Serial.print(ecValue, 2); // ermittelter wert ms/cm
    Serial.println("ms/cm");
#endif
  }
  ec.calibration(voltage, temperature);  // calibration process by Serail CMD
}

float salzGehalt(float ecValue, float temperature) {
  const float SF	= 553;
  float r_salzgehalt = 0;
  float A1, A2, A3;
  if (temperature <= 10) {
    A1 = -0.044532198;
    A2 = -0.013174538;
    A3 = 1.085694313;
  } else {
    A1 = -0.073894632;
    A2 = -0.010947644;
    A3 = 1.09173096;
  }
  float r_Leitwert = ecValue/(10.0);   
  float base = 10;
  float exponent = (A1 + temperature * A2 + A3 * log10 ( abs(r_Leitwert)));
  r_salzgehalt = pow(base, exponent);
  r_salzgehalt = r_salzgehalt *  SF/1000.0;
  return r_salzgehalt;
}

float readTemperature() {
  //add your code here to get the temperature from your temperature sensor
}

dazu noch die h und cpp datei von DFRobot.
cpp

/*
 * file DFRobot_EC.cpp
 * @ https://github.com/DFRobot/DFRobot_EC
 *
 * Arduino library for Gravity: Analog Electrical Conductivity Sensor / Meter Kit V2 (K=1), SKU: DFR0300
 *
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * version  V1.01
 * date  2018-06
 */


#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "DFRobot_EC.h"
#include <EEPROM.h>

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

#define KVALUEADDR 0x0A    //the start address of the K value stored in the EEPROM
#define RES2 820.0
#define ECREF 200.0

char* DFRobot_EC::strupr(char* str) {
    if (str == NULL) return NULL;
    char *ptr = str;
    while (*ptr != ' ') {
        *ptr = toupper((unsigned char)*ptr);
        ptr++;
    }
    return str;
}

DFRobot_EC::DFRobot_EC()
{
    this->_ecvalue                = 0.0;
    this->_kvalue                 = 1.0;
    this->_kvalueLow              = 1.0;
    this->_kvalueHigh             = 1.0;
    this->_cmdReceivedBufferIndex = 0;
    this->_voltage                = 0.0;
    this->_temperature            = 25.0;
} 

DFRobot_EC::~DFRobot_EC()
{

}

void DFRobot_EC::begin()
{
    EEPROM_read(KVALUEADDR, this->_kvalueLow);        //read the calibrated K value from EEPROM
    if(EEPROM.read(KVALUEADDR)==0xFF && EEPROM.read(KVALUEADDR+1)==0xFF && EEPROM.read(KVALUEADDR+2)==0xFF && EEPROM.read(KVALUEADDR+3)==0xFF){
        this->_kvalueLow = 1.0;                       // For new EEPROM, write default value( K = 1.0) to EEPROM
        EEPROM_write(KVALUEADDR, this->_kvalueLow);
    }
    EEPROM_read(KVALUEADDR+4, this->_kvalueHigh);     //read the calibrated K value from EEPRM
    if(EEPROM.read(KVALUEADDR+4)==0xFF && EEPROM.read(KVALUEADDR+5)==0xFF && EEPROM.read(KVALUEADDR+6)==0xFF && EEPROM.read(KVALUEADDR+7)==0xFF){
        this->_kvalueHigh = 1.0;                      // For new EEPROM, write default value( K = 1.0) to EEPROM
        EEPROM_write(KVALUEADDR+4, this->_kvalueHigh);
    }
    this->_kvalue =  this->_kvalueLow;                // set default K value: K = kvalueLow
}

float DFRobot_EC::readEC(float voltage, float temperature)
{
    float value = 0,valueTemp = 0;
    this->_rawEC = 1000*voltage/RES2/ECREF;
    valueTemp = this->_rawEC * this->_kvalue;
    //automatic shift process
    //First Range:(0,2); Second Range:(2,20)
    if(valueTemp > 2.5){
        this->_kvalue = this->_kvalueHigh;
    }else if(valueTemp < 2.0){
        this->_kvalue = this->_kvalueLow;
    }

    value = this->_rawEC * this->_kvalue;             //calculate the EC value after automatic shift
    value = value / (1.0+0.0185*(temperature-25.0));  //temperature compensation
    this->_ecvalue = value;                           //store the EC value for Serial CMD calibration
    return value;
}

void DFRobot_EC::calibration(float voltage, float temperature,char* cmd)
{   
    this->_voltage = voltage;
    this->_temperature = temperature;
    strupr(cmd);
    ecCalibration(cmdParse(cmd));                     //if received Serial CMD from the serial monitor, enter into the calibration mode
}

void DFRobot_EC::calibration(float voltage, float temperature)
{   
    this->_voltage = voltage;
    this->_temperature = temperature;
    
    if(cmdSerialDataAvailable() > 0)
    {
        ecCalibration(cmdParse());  // if received Serial CMD from the serial monitor, enter into the calibration mode
    }
}

boolean DFRobot_EC::cmdSerialDataAvailable()
{
    char cmdReceivedChar;
    static unsigned long cmdReceivedTimeOut = millis();
    while (Serial.available()>0) 
    {
        if(millis() - cmdReceivedTimeOut > 500U){
            this->_cmdReceivedBufferIndex = 0;
            memset(this->_cmdReceivedBuffer,0,(ReceivedBufferLength));
        }
        cmdReceivedTimeOut = millis();
        cmdReceivedChar = Serial.read();
        if(cmdReceivedChar == '\n' || this->_cmdReceivedBufferIndex==ReceivedBufferLength-1){
            this->_cmdReceivedBufferIndex = 0;
            strupr(this->_cmdReceivedBuffer);
            return true;
        }else{
            this->_cmdReceivedBuffer[this->_cmdReceivedBufferIndex] = cmdReceivedChar;
            this->_cmdReceivedBufferIndex++;
        }
    }
    return false;
}

byte DFRobot_EC::cmdParse(const char* cmd)
{
    byte modeIndex = 0;
    if(strstr(cmd, "ENTEREC")      != NULL){
        modeIndex = 1;
    }else if(strstr(cmd, "EXITEC") != NULL){
        modeIndex = 3;
    }else if(strstr(cmd, "CALEC")  != NULL){
        modeIndex = 2;
    }
    return modeIndex;
}

byte DFRobot_EC::cmdParse()
{
    byte modeIndex = 0;
    if(strstr(this->_cmdReceivedBuffer, "ENTEREC")     != NULL)
        modeIndex = 1;
    else if(strstr(this->_cmdReceivedBuffer, "EXITEC") != NULL)
        modeIndex = 3;
    else if(strstr(this->_cmdReceivedBuffer, "CALEC")  != NULL)
        modeIndex = 2;
    return modeIndex;
}

void DFRobot_EC::ecCalibration(byte mode)
{
    char *receivedBufferPtr;
    static boolean ecCalibrationFinish  = 0;
    static boolean enterCalibrationFlag = 0;
    static float compECsolution;
    float KValueTemp;
    switch(mode){
        case 0:
        if(enterCalibrationFlag){
            Serial.println(F(">>>Command Error<<<"));
        }
        break;
        case 1:
        enterCalibrationFlag = 1;
        ecCalibrationFinish  = 0;
        Serial.println();
        Serial.println(F(">>>Enter EC Calibration Mode<<<"));
        Serial.println(F(">>>Please put the probe into the 1413us/cm or 12.88ms/cm buffer solution<<<"));
        Serial.println();
        break;
        case 2:
        if(enterCalibrationFlag){
            if((this->_rawEC>0.9)&&(this->_rawEC<1.9)){                         //recognize 1.413us/cm buffer solution
                compECsolution = 1.413*(1.0+0.0185*(this->_temperature-25.0));  //temperature compensation
            }else if((this->_rawEC>9)&&(this->_rawEC<16.8)){                    //recognize 12.88ms/cm buffer solution
                compECsolution = 12.88*(1.0+0.0185*(this->_temperature-25.0));  //temperature compensation
            }else{
                Serial.print(F(">>>Buffer Solution Error Try Again<<<   "));
                ecCalibrationFinish = 0;
            }
            KValueTemp = RES2*ECREF*compECsolution/1000.0/this->_voltage;       //calibrate the k value
            if((KValueTemp>0.5) && (KValueTemp<1.5)){
                Serial.println();
                Serial.print(F(">>>Successful,K:"));
                Serial.print(KValueTemp);
                Serial.println(F(", Send EXITEC to Save and Exit<<<"));
                if((this->_rawEC>0.9)&&(this->_rawEC<1.9)){
                    this->_kvalueLow =  KValueTemp;
                }else if((this->_rawEC>9)&&(this->_rawEC<16.8)){
                    this->_kvalueHigh =  KValueTemp;
                }
                ecCalibrationFinish = 1;
          }
            else{
                Serial.println();
                Serial.println(F(">>>Failed,Try Again<<<"));
                Serial.println();
                ecCalibrationFinish = 0;
            }
        }
        break;
        case 3:
        if(enterCalibrationFlag){
                Serial.println();
                if(ecCalibrationFinish){   
                    if((this->_rawEC>0.9)&&(this->_rawEC<1.9)){
                        EEPROM_write(KVALUEADDR, this->_kvalueLow);
                    }else if((this->_rawEC>9)&&(this->_rawEC<16.8)){
                        EEPROM_write(KVALUEADDR+4, this->_kvalueHigh);
                    }
                    Serial.print(F(">>>Calibration Successful"));
                }else{
                    Serial.print(F(">>>Calibration Failed"));
                }
                Serial.println(F(",Exit EC Calibration Mode<<<"));
                Serial.println();
                ecCalibrationFinish  = 0;
                enterCalibrationFlag = 0;
        }
        break;
    }
}

header datei

/*
 * file DFRobot_EC.h * @ https://github.com/DFRobot/DFRobot_EC
 *
 * Arduino library for Gravity: Analog Electrical Conductivity Sensor / Meter Kit V2 (K=1), SKU: DFR0300
 *
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * version  V1.01
 * date  2018-06
 */

#ifndef _DFROBOT_EC_H_
#define _DFROBOT_EC_H_

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#define ReceivedBufferLength 10  //length of the Serial CMD buffer

class DFRobot_EC
{
public:
    DFRobot_EC();
    ~DFRobot_EC();
    void    calibration(float voltage, float temperature,char* cmd);        //calibration by Serial CMD
    void    calibration(float voltage, float temperature);                  //calibration by Serial CMD
    float   readEC(float voltage, float temperature);                       // voltage to EC value, with temperature compensation
    void    begin();                                                        //initialization

private:
    float  _ecvalue;
    float  _kvalue;
    float  _kvalueLow;
    float  _kvalueHigh;
    float  _voltage;
    float  _temperature;
    float  _rawEC;

    char   _cmdReceivedBuffer[ReceivedBufferLength];  //store the Serial CMD
    byte   _cmdReceivedBufferIndex;

private:
    boolean cmdSerialDataAvailable();
    void    ecCalibration(byte mode); // calibration process, wirte key parameters to EEPROM
    byte    cmdParse(const char* cmd);
    byte    cmdParse();
	char* strupr(char* str);
};

#endif

wenn ich das ganze über modbus sende
Mb.MbData[5] = ecValue * 10; // EC Wert
bekomme ich auf der SPS den Rohwert wo er dann weiter bearbeitet wird und als ist Wert an die Visualisirung gesendet wird.

nun noch der gesammte Baustein wie es in der SPS verarbeitet wird.

FUNCTION_BLOCK EC  { altName := "Salzmenge"; vNameAlignment := "top"; width := 400; bgColor := "green"; }
VAR_INPUT
Leitwert	 	: Word 	:= 0; 			//ms/cm Leitwert / cm
BeckenTemp 		: REAL 	:= 0;			// Becken ist Temperatur
Z_EN			: BOOL	:= FALSE;		// Elektrolyse Zelle enable/false
END_VAR

VAR_OUTPUT
salzgehalt 		: WORD := 0;			// Salzgehalt was an den RPI gesendet wird
salz_high		: BOOL:= FALSE;			// Salzgehalt überschritten, Zelle abschalten
salz_low		: BOOL:= FALSE;			// Salzgehalt unterschritten Zelle abschalten
zelle_EN		: BOOL:= FALSE;			// Zelle auschalten
Leitwert_EC		: WORD:= 0;				// Leitwert an den RPI senden
END_VAR

VAR_EXTERNAL
Mout_Elektrolyse  : BOOL;				// externe Variable ob Zelle ein oder ausgeschaltet ist
END_VAR
VAR
r_salzgehalt  : REAL:=0;
r_Leitwert    : REAL:=0;

A1   : REAL;
A2   : REAL;
A3   : REAL;
SF	 : REAL := 553;

END_VAR

	salzgehalt   	:= TO_WORD (r_salzgehalt*10.0);
 	r_Leitwert     	:= TO_REAL (Leitwert)/10.0;
  	Leitwert_EC     := TO_WORD (r_Leitwert*10.0);
 	zelle_EN 		:= Z_EN;                                        // noch nicht berücksichtigt
 	
 if (BeckenTemp <= 10)then                                            // Angabe in °C
	 A1:= -0.044532198;
	 A2:= -0.013174538;
	 A3:= 1.085694313;
 else
	 A1:= -0.073894632;
	 A2:= -0.010947644;
	 A3:= 1.09173096;

 end_if;

r_salzgehalt := expt( IN1 := 10,  IN2:= (A1 + BeckenTemp * A2 + A3 * log( in:= ABS( in:= r_Leitwert) ) ));
r_salzgehalt := r_salzgehalt *  SF/1000;

IF (r_salzgehalt >= 4.9)THEN
		salz_high:= TRUE;
	ELSE	
		salz_high:= FALSE;
END_IF;
IF (r_salzgehalt<=2.1)THEN
		salz_low:=TRUE;
	ELSE
		salz_low:= FALSE;
	END_IF;
END_FUNCTION_BLOCK

ich hoffe du kannst dir damit ein bild machen

wie gesagt ich sende den EC wert was auch bei der SPS ankommt, auch der Arduino zeigt diesen Wert richtig an, nur der Arduino weigert sich den Salzgehalt anzuzeigen.

Das könnte tatsächlich ein Problem der Auflösung sein.

gibt mir mal einen ecValue und den passenden r_salzgehalt der von der SPS ausgegeben wird.
Dann komm ich da schon hin :wink:

@ec2021 Wenn gar nicht anders, wird erst wieder in Ganzzahlen hochgerechnet. Float auf den 8 bittern ist ein 7 Stellen Ding. Da zählen alle Stellen, sowohl vor als auch nach dem Komma....
Ich schau mal auf die Formelgestaltung.

​16#001A                  ​ ​**2.587362**           // Slazgehalt                                                            ​
salzgehalt   	:= TO_WORD (r_salzgehalt*10.0);
​**7.8**                        ​ ​16#004E                                                                     ​
r_Leitwert     	:= TO_REAL (Leitwert)/10.0;   // ec_value

@my_xy_projekt ,

sehe ich auch so. Kannst gerne auch noch mal prüfen, ob meine Umsetzung grundsätzlich i.O. ist.

Danke für die Unterstützung und viel Erfolg!

(von meiner Terrasse gesendet )
:wink:

Gruß
ec2021

1 Like

Ich bin das etwas anders angegangen, muss mir aber nochmal die Formeln anschauen.

uint16_t Leitwert;

float BeckenTemp;// Becken ist Temperatur
bool Z_EN;// Elektrolyse Zelle enable/false

bool salz_high; // Salzgehalt überschritten, Zelle bool abschalten
bool salz_low;// Salzgehalt unterschritten Zelle abschalten
bool zelle_EN;// Zelle auschalten

float a1;
float a2;
float a3;

const uint16_t SF = 553;

uint16_t salzgehalt ()
{
  Serial.print(F("Salzgehalt: "));
  Serial.println(r_salzgehalt() * 10);
  return r_salzgehalt() * 10;
}

float r_Leitwert ()
{
  Serial.print(F("r_Leitwert: "));
  Serial.println(Leitwert / 10.0, 6);
  return Leitwert / 10.0;
}

uint16_t Leitwert_EC ()
{
  Serial.print(F("Leitwert_EC: "));
  Serial.println(r_Leitwert() * 10);
  return r_Leitwert() * 10;
};


float r_salzgehalt()
{
  float returnWert = 0.0;
  const uint8_t IN1 = 10;
  if (BeckenTemp <= 10)
  {
    a1 = -0.044532198;
    a2 = -0.013174538;
    a3 = 1.085694313;
  }
  else
  {
    a1 = -0.073894632;
    a2 = -0.010947644;
    a3 = 1.09173096;
  }
  float IN2 = a1 + BeckenTemp * a2 + a3 * log(abs(r_Leitwert()));
  returnWert = pow(IN1, IN2) *  SF / 1000;
  Serial.print(F("r_salzgehalt"));
  Serial.println(returnWert);
  return returnWert;
}

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  salz(10, 16);  // Temparatur, Leitwert
}

void loop()
{
}

void salz(const float temp, const uint16_t leit)
{
  BeckenTemp = temp;
  Leitwert = leit;
  salz_high = false;
  salz_low = false;
  if (r_salzgehalt() >= 4.9)
  {
    salz_high = true;
  }
  else if (r_salzgehalt() <= 2.1)
  {
    salz_low = true;
  }
}

Irgendwo vermutlich ein c/p Problem oder was falsch interpretiert.

Nachtrag: Die Umrechnerei funktioniert so nicht.
a1 bis a3 sind 10stellig...
Ich denk mal drüber nach.

Ich werd aus den Zahlen nicht schlau.
Was ist da was?

Bzgl. des Leitwerts sieht das wohl so aus

  • Leitwert= Eingangswert als Ganzzahl (WORD)
  • r_leitwert = Leitwert/10 als float (REAL)
  • Leitwert_EC = r_leitwert*10 als Ganzzahl (WORD)

Also wird einmal hin- und zurück gerechnet über einen float-Wert. Im Arduino ist Leitwert_EC unnötig, da könnte man gleich "Leitwert" nehmen, wenn es denn jemals wieder gebraucht wird.

Am besten wäre es, zunächst einmal die Rechnung in einer Tabellenkalkulation nachzuvollziehen und zwar mit von @luzie bestätigten Eingabe/Ausgabe-Werten.

Danach die Umsetzung auf Arduino-Code.

P.S.:

Hier ein gezipptes OpenDatasheet-File:

SalzgehaltBerechnung.zip (15,8 KB)

Sieht so aus:

  • Gelb markiert sind die Eingaben BeckenTemp in °C und Leitwert in mS/cm
  • Grün markiert die Ausgaben r_salzgehalt und salz_gehalt
  • Die verwendeten Parameter-Werte passen sich der gewählten Temperatur an.

Die Werte von r_Leitwert und salz_gehalt ergeben sich (jedoch zur besseren Beurteilbarkeit ohne Wandlung in Ganzzahl) nach

salzgehalt   	:= TO_WORD (r_salzgehalt*10.0);
r_Leitwert     	:= TO_REAL (Leitwert)/10.0;

Jetzt wäre es interessant, hier einmal Werte der SPS mit der Tabelle zu verifizieren.

Gerne mal prüfen, ob ich die Berechnung korrekt umgesetzt habe ...

1 Like

das habe ich auch nur so
UmrechnungLeitfaehigkeitNaCl (1).zip (36.5 KB)

bei den

  • Leitwert= Eingangswert als Ganzzahl (WORD)
  • r_leitwert = Leitwert/10 als float (REAL)
  • Leitwert_EC = r_leitwert*10 als Ganzzahl (WORD)
    ich muss es einmal in Real umrechen damit die SPS es verarbeiten kann, das ergbniss sende ich via Modbus an einen RPI der als Visualisrung arbeitet um es dort anzeigen zu können. Daher das hin und her rechnen.

der arduino Leonardo ETH sendet es via modbus an die SPS wird dort verabeitet und geht dann via Modbus an die Visu.
Ich weiss es ist etwas umständlich, aber leider ist es derzeit nicht anderst möglich da zuviele Geräte dazwischen hängen um es gleich mit den Arduino oder ESP32 zu verarbeiten und direkck an die Visu zu senden.
Da aber nun am Arduino ein Nextion Display angeschlossen ist und die Anzeige direkt dort erfolgt wollte ich das auch gleich noch mit dem arduino erledigen.


anhand der Tabelle passen die werte auf der SPS mit der Umrechnunng

@my_xy_projekt

das mit den Zahlen wird auf Blatt 2 in der Umrechnuungstabelle erklärt, ich hoffe du kannst jetzt etwas mit den Zahlen anfangen.

gruß Luzie

Ich muss mir das erarbeiten - mal sehen, wie ich da nachher Zeit habe.
Wenigstens ist es ein .ods :slight_smile:

Ich sehe aber ernsthaft Probleme mit den vielen Stellen in den Variablen.
Lösung findet sich dafür bestimmt.
Mir eilt ja der Ruf voraus sich gerne festzubeisen :wink:

1 Like

Evtl. kannst Du die BigNumber-Lib von Nick Gammon nutzen.

Gruß Tommy

1 Like

Sieht nett aus :slight_smile: