BOSCH PST F1 - Map-Funktion?

Ich möchte mein Projekt "Öltemperatur und -druck" mit dem Arduino Nano gern weiter führen und die bisher einzelnen Sensoren durch den BOSCH PST F1 ersetzen.
Dieser hat einen Drucksensor mit linearem 0-5V Signal und einer Funktion für die Temperatur über dem Widerstand.
Widerstand mit dem Arduino und "Bias Widerstand" messen ist kein Problem, das Umrechnen von Widerstand zu Temperatur geht mit einer Polynom-Funktion 6. Grades - das ist mit aber zu aufregend :wink: Das mache ich bislang so mit selbst gemessenen Widerständen an dem NTC den ich bisher nutze. Code in meinem anderen Thread.

int analogPin7 = A7; // Analog-Input Pin7 => Öltemperatur als  Widerstand
float R1 = 5.14; //Wert des bekannten Widerstands in kOhm
float R; //Widerstand des Temperaturfühlers
float SpannungR2; //Spannung über dem zu messenden Widerstand
float oiltemp; // Öltemperatur

  //Berechung Widerstand Temperaturfühler
  SpannungR2 = 5 / 1023.0 * analogRead(analogPin7);
  R = R1 * (SpannungR2 / (5 - SpannungR2));

  //Umrechnung Widerstand in Temperatur
  if (R > 45) {
    oiltemp = 0.00479709*pow(R, 2) - 1.00497778*R + 61.07424494;
  }
  else {
    oiltemp = 0.0000001326*pow(R, 6) - 0.0000236053*pow(R, 5) + 0.0016840356*pow(R, 4) - 0.0620097366*pow(R, 3) + 1.2759648324*pow(R, 2) - 15.504389816*R + 138.9049501569;
  }

Der Sensor BOSCH PST F1 bringt eine "Map" mit - kann man den Wert anhand dieser ermitteln lassen?

T [°C] R [Ohm]
-40 44864
-30 25524
-20 15067
-10 9195
0 5784
10 3740
20 2480
30 1683
40 1167
50 824
60 594
70 434.9
80 323.4
90 244
100 186.6
110 144.5
120 113.3
130 89.9
140 71.9
150 58.1

Datenblatt

PS: ich habe einen Beitrag gefunden, wo schon mal wer versucht hat den Sensor einzubinden, er hat aber wohl gedacht da kommt auch ein 5V Signal raus. Das Schaltbild da ist auch für die Widerstandsmessung falsch.
Alte Beiträge wieder öffnen und da fortfahren geht nicht, oder?

Meine Schaltung sieht in etwa so aus:

Hierzu und zur Widerstandsermittlung habe ich eine Frage.
Den Bias-Widerstand kann man ja messen und den Wert für die Berechnung nehmen. Dazu brauche ich noch den Wert der Versorgungsspannung, diese wäre ideal bei 5V - kann aber auch abweichen. Mein Versuch Pin "5V" einfach z.B. an A3 zu legen und da zu messen und in die Berechnung zu holen scheitert. Es kommen immer "komische" Spannungswerte raus, aber keine 5V. (analogRead als int und die Spannung als float mit analogread/1023*5)

Das ist der Sensor

Widerstandsmessung unabhängig von Spannungsschwankungen führt man mit Brückenschaltungen durch.

Gruß Tommy

Hallo,
d.h Du willst die 5Vam Pin mit A3 messen ?
dann zeig mal Deinen Testsketch dazu

Du konntest die Map Werte in Excell eingeben und die eine Trendfunktion berechnen lassen. Bei der Gelegenheit kannst Du dann auch gleich die Ausgangsspannung für den Spannungsteiler berechnen und die Funktion nutzten. das klappt eigentlich ganz gut. Oder Du legst ein Array an und interpolierst linear zwischen zwei Werten.

Heinz

Danke für den Tipp. Bei Herr Wheatstone bin ich bereits im Studium ins Straucheln gekommen.
Ich brauch eine Vollbrücke, also 4 Widerstände - 3 bekannte und der 4. ist der NTC, richtig?
Dazu muss ich google quälen wie man so eine Schaltung aufbaut bzw meine ergänzt.

Ja, das war der Plan.
Den Sketch müsste ich zusammen tippen.

Sollte grob dem entsprechen:

int analogPin3 = A3; // Analog-Input Pin3
float Vcc; //Spannung an Pin 3

  //Berechung Vcc
  Vcc = 5 / 1023.0 * analogRead(analogPin3);

und mit Vcc dann oben in den Code um die "5" in der Widerstandsberechnung zu ersetzen.

Bezüglich der Map - die Excel gibt es und daraus die entsprechenden Umrechnungen die die das Polynom 6. Grades ergeben.
Hatte gehofft mit einer Map geht das einfacher :frowning:
Bei anderen heißt das "lutTable" - sowas habe ich für Arduino noch nicht gefunden.


Hallo,

die Spannungsmessung sollte ja ok sein , was kommt denn da so bei raus. ?
Mit einem Nano hast Du bei float Variablen einen Wert mit 6 Stellen, da kannst Du eingeben was u willst. Die Berechnung wird da ziemlich ungenau denke ich. Ich würde da ehr auf das lineare Interpolieren zwischen zwei Werten zurückgreifen. Das ist ein bisschen aufwendiger aber da kann man sich ja eine Functon für schreiben.
Übergabe ist der x Wert Rückgabe y Wert. sowas in der Art.

Heinz

Nachtrag
dh. Du musst die Spannung messen , dann in Verbindung mit dem Spannungsteiler den Widerstand des NTC im Nano berechnen, und damit in die Function gehen um an dieTemperatur zu bekommen.

Ich muss einen Wackler am Board gehabt haben (die Stiftleiste war nur gesteckt, nun ist sie verlötet). Die Spannung schwankte zw. 2,x und 4,7V. Evtl hatte ich auch zuviele Verbraucher am Laptop (externes Display wird via USB gespeist).
Aktuell habe ich VCC (5V) direkt auf A3 gelegt und erhalte im seriellen Monitor glatte 5,00V.

Nach wie vor bin ich aber mit der Berechnung nicht happy. Das Polynom 6. Grades weicht mir zu gravierend ab vom IST-Wert. Hier sind aktuell sicher keine 28°C im Büro.

float R1 = 4.7; //Wert des bekannten Widerstands in kOhm
float R; //Widerstand des Temperaturfühlers
float SpannungR2; //Spannung über dem zu messenden Widerstand
float oilpressure = 0; //(analogRead(A6)/1023.00*5)* 2.50 - 1.25; // Öltemperatur
float oiltemp = 0;
float Vcc = 0;

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input:
  int sensorVcc = analogRead(A3);
  int sensorValuep = analogRead(A6);
  int sensorValueT = analogRead(A7);

  //Berechung Vcc
  Vcc = analogRead(A3)/1023.0*5;

  //Berechung Widerstand Temperaturfühler
  SpannungR2 = 5 / 1023.0 * analogRead(A7);
  R = R1 * (SpannungR2 / (Vcc - SpannungR2)) * 1000;

  //Umrechnung Widerstand in Temperatur

  oiltemp = - 1.87740 * pow(SpannungR2 , 5) + 23.95691 * pow(SpannungR2 , 4) - 114.25183 * pow(SpannungR2 , 3) + 251.39272 * pow(SpannungR2 , 2) - 272.99750 * SpannungR2  + 149.50112; //4,7kOhm

  //Berechnung Öldruck
  if ((analogRead(A6) / 1023.00 * 5) * 2.50 - 1.25 <= 0.05) {
    oilpressure = 0;
  }
  else {
    oilpressure = (analogRead(A6) / 1023.00 * 5) * 2.50 - 1.25;
  }

  // print out the value you read:

  Serial.print("U= ");
  Serial.print(Vcc);
  Serial.println(" V");
  Serial.print("p= ");
  Serial.print(oilpressure);
  Serial.println(" bar");
  Serial.print("T= ");
  Serial.print(oiltemp);
  Serial.println(" °C");
  Serial.println("----------");
  delay(1000);        // delay in between reads
}

Das nutzen der Wertetabelle im Quellcode und Interpolation zwischen den Werten muss doch auch funktionieren?

Lass dir doch mal SpannungR2 und R ausgeben.

Und lass doch die ganzen *5 *1023, /5 /1023 weg und rechne direkt mit den analogread werten.

Warum hast du mehrfach im loop

Auch hier: einmal reicht

R und SpannungR2 habe ich mir testweise ausgegeben.
Aber das hilft mir nicht was die "Map" angeht. Die Werte passen auch zur Excel oben.
Nur die Temperatur halt nicht so wie ich mir das vorstelle.

Und die

 // read the input:
  int sensorVcc = analogRead(A3);
  int sensorValuep = analogRead(A6);
  int sensorValueT = analogRead(A7);

..sind unnötig, hast du Recht.
Aber die analogRead geben mir doch nur 0-1023 Integer aus, die ich in Volt umrechnen muss, oder nicht? Warum soll ich die /1023*5 weglassen?

NEIN, die sind nicht unnötig. Unten die Reads sind unnötig.

Nein musst du nicht. Du kannst auch die Werte direkt verrechnen. So bringst du nur unnötige Rundungsfehler in deine Werte.

Wenn du direkt die integer Werte aus analog read benutzt kannst du eine switch case Anweisung nutzen

switch (sensorValueT) {
  case 0..100:
    map(sensorValueT.....
   break;
  case 101..200:
    map(sensorValueT.....
   break;
}
1 Like

Du meinst ich soll statt vieler einzelner Floats mit denen ich weiter rechne den analogread direkt in den Formeln verrechnen?

  //Berechnung Widerstand in Temperatur
oiltemp = - 1.87740 * pow((analogRead(A7)/1023*5), 5) + 23.95691 * pow((analogRead(A7)/1023*5), 4) - 114.25183 * pow((analogRead(A7)/1023*5), 3) + 251.39272 * pow((analogRead(A7)/1023*5), 2) - 272.99750 * (analogRead(A7)/1023*5)+ 149.50112; //4,7kOhm

Die Formel willst du doch durch verschiedene maps ersetzen.

Hallo,
mal die Frage : entsprechen denn deine mit dem Arduino gemessenen Spannungen denen die Du mit einem Digitalvoltmeter messen kannst. ?
Ich denke nur den Widerstand R1 hast Du ja mit 4,7KOhm angegeben. Entspricht das dem tatsächlichen Wert ?

Du kannst Deinen Sensor sicher auch mal in Eiswasser halten , da solltest Du etwa 0 Grad haben. Bei kochendem Wasser halt ca. 100°C wenn Du nicht gerade auf einem Berg wohnst.
Dann hättest Du zusammen mit einer bekannten Raumtemperatur schon mal 3 Werte im meist genutzten Bereich.

Den Vorschlag von Werner finde ich schon mal super und auch einfach. Du hast ja bereits eine Excel Tabelle die Temperaturen und Analogwerte enthält. Nur hat der swich case nicht unbedingt gerade Werte 0...100, 101....200, sonder eventuell krumme aus Deiner Tabelle z.B
swich case 35....44, 45....53, 54....xxx
in den zugehörigen map() kommen dann diese Grenzen mit den zugehörigen Temeraturwerten. z.B 140, 130,120

Heinz

1 Like

Da ich mich ja auch schon mal mit nicht liniearen Sensoren betätigt habe und hier bereits excel als Hilfstellung zur Sprache kam....

Hier ist eine Lösung zu einem Problem, welches bei richtiger Betrachtungsweise keines ist.

Ich glaube jetzt habe ich Dich verstanden.. halb zumindest.

Wäre dann also so?

  int sensorValueT = analogRead(A7);

  switch (sensorValueT) {
  case (sensorValueT >= 15 || sensorValueT < 20):
    oiltemp = map(sensorValueT, 15, 19, 140 ,130)
   break;
  case (sensorValueT >= 20 || sensorValueT < 25):
    oiltemp = map(sensorValueT, 20, 24, 130 ,120)
   break;
     case (sensorValueT >= 25 || sensorValueT < 30):
    oiltemp = map(sensorValueT, 25, 30, 120 ,110)
   break;

Hier kommt allerdings bereits der Fehler:

exit status 1

the value of 'sensorValueT' is not usable in a constant expression


Stellt sich mir nur die Frage: ich kann da ja nur mit Integern rechnen, also fang ich oben mir 15-19 an, die 140-130°C entsprechen. Was aber eigentlich 15,4-19,2 wäre.
Verliere ich da nicht auch "Auflösung" mit dem "case", wenn ich nur ganzzahlig ran gehe und auch der Wert stimmt ja dann nicht. Würde das nicht mit SpannungR2 mehr Sinn machen, hier kommt ich auf Steps von 0,005V und wäre da näher dran?

Schau Dir mal an, wie switch/case wirklich funktioniert oder mit range.

Gruß Tommy

Wenn dir analogRead nur 15-19 liefert, kannst du da nicht mehr rausholen. Wenn es genauer sein muss, musst du auf einen 12bit AD Wandler gehen (extern oder anderer µC).

int sensorValueT = analogRead(A7);

  switch (sensorValueT) {
  case 15 ... 19:
    oiltemp = map(sensorValueT, 15, 19, 140 ,130)
    break;
  case 20 ... 24:
    oiltemp = map(sensorValueT, 20, 24, 130 ,120)
    break;
     case 25 ... 30:
     oiltemp = map(sensorValueT, 25, 30, 120 ,110)
   break;
}

Das ist nur vorgegaukelte Genauigkeit.

magische Zahlen.
fehlende Lookuptable.

Das kannst Du besser.

Ich versuche Dir wirklich zu folgen, aber manchmal enthält Deine Antwort zu knappe Infos um einem ambitionierten und willigem Noob weiter zu helfen :frowning:

Ich versuche es mal: Ich bekomme mit dem analogRead nur int im Bereich 0-1023 was 0-5V entspricht - mehr kann der Nano nicht und soll für meine Zwecke auch ausreichen. Die Öltemperatur höher als auf 0,5°C auflösen wäre unnütz.
Wenn ich in meiner Excel nun die errechnete Spannung umrechne in int, dann bekomme ich bei 140°C "15,4 int" her raus, was auf 15 gerundet wird aber dann eben nicht mehr der 140°C entspricht - oder?
Meine Idee war dann den switch mit der SpannungR2 zu nutzen - aber die kann keinen float auswerten.

Ich habe es daher mal händisch mit einer if - else if - else Funktion probiert und da die jeweile Interpolation über zwei Werte auf Basis der Excel aus Spannung und Temperatur eingesetzt. Beim kompilieren meckert schon mal nichts.
Leider bin ich auf Dienstreise und habe das Nano nicht mit. Test steht aus.

float R1 = 4.7; //Wert des bekannten Widerstands in kOhm
float R; //Widerstand des Temperaturfühlers
float SpannungR2; //Spannung über dem zu messenden Widerstand
float oilpressure = 0; //(analogRead(A6)/1023.00*5)* 2.50 - 1.25; // Öltemperatur
float oiltemp = 0;
float Vcc = 0;
//unsigned long last_oil_send = 0;
//unsigned long last_oled_send = 0;
//int sendTime = 2000;

//#include <U8g2lib.h>
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED

// the setup routine runs once when you press reset:
void setup() {
  //u8g2.begin();
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input:
  int sensorVcc = analogRead(A3);
  int sensorValuep = analogRead(A6);
  int sensorValueT = analogRead(A7);

  //Berechung Vcc
  Vcc = sensorVcc/1023.0*5;

  //Berechung Widerstand Temperaturfühler
  SpannungR2 = sensorValueT / 1023 * 5;
  R = R1 * (SpannungR2 / (Vcc - SpannungR2)) * 1000;

  //Mapping SpannungR2 => Temp
if (SpannungR2 >= 0.075 || SpannungR2 < 0.094) { oiltemp = map(SpannungR2, 0.075, 0.094, 140 ,130); }
else if (SpannungR2 >= 0.094 || SpannungR2 < 0.118) { oiltemp = map(SpannungR2, 0.094, 0.118, 130 ,120); }
else if (SpannungR2 >= 0.118 || SpannungR2 < 0.149) { oiltemp = map(SpannungR2, 0.118, 0.149, 120 ,110); }
else if (SpannungR2 >= 0.149 || SpannungR2 < 0.191) { oiltemp = map(SpannungR2, 0.149, 0.191, 110 ,100); }
else if (SpannungR2 >= 0.191 || SpannungR2 < 0.247) { oiltemp = map(SpannungR2, 0.191, 0.247, 100 ,90); }
else if (SpannungR2 >= 0.247 || SpannungR2 < 0.322) { oiltemp = map(SpannungR2, 0.247, 0.322, 90 ,80); }
else if (SpannungR2 >= 0.322 || SpannungR2 < 0.424) { oiltemp = map(SpannungR2, 0.322, 0.424, 80 ,70); }
else if (SpannungR2 >= 0.424 || SpannungR2 < 0.561) { oiltemp = map(SpannungR2, 0.424, 0.561, 70 ,60); }
else if (SpannungR2 >= 0.561 || SpannungR2 < 0.746) { oiltemp = map(SpannungR2, 0.561, 0.746, 60 ,50); }
else if (SpannungR2 >= 0.746 || SpannungR2 < 0.995) { oiltemp = map(SpannungR2, 0.746, 0.995, 50 ,40); }
else if (SpannungR2 >= 0.995 || SpannungR2 < 1.318) { oiltemp = map(SpannungR2, 0.995, 1.318, 40 ,30); }
else if (SpannungR2 >= 1.318 || SpannungR2 < 1.727) { oiltemp = map(SpannungR2, 1.318, 1.727, 30 ,20); }
else if (SpannungR2 >= 1.727 || SpannungR2 < 2.216) { oiltemp = map(SpannungR2, 1.727, 2.216, 20 ,10); }
else if (SpannungR2 >= 2.216 || SpannungR2 < 2.759) { oiltemp = map(SpannungR2, 2.216, 2.759, 10 ,0); }
else if (SpannungR2 >= 2.759 || SpannungR2 < 3.309) { oiltemp = map(SpannungR2, 2.759, 3.309, 0 ,-10); }
else if (SpannungR2 >= 3.309 || SpannungR2 < 3.811) { oiltemp = map(SpannungR2, 3.309, 3.811, -10 ,-20); }
else if (SpannungR2 >= 3.811 || SpannungR2 < 4.223) { oiltemp = map(SpannungR2, 3.811, 4.223, -20 ,-30); }
else if (SpannungR2 >= 4.223 || SpannungR2 < 4.526) { oiltemp = map(SpannungR2, 4.223, 4.526, -30 ,-40); }
else {oiltemp = 0;
}

  //Berechnung Öldruck
  if ((analogRead(A6) / 1023.00 * 5) * 2.50 - 1.25 <= 0.05) {
    oilpressure = 0;
  }
  else {
    oilpressure = (analogRead(A6) / 1023.00 * 5) * 2.50 - 1.25;
  }


  // an I2C-Display senden alle 200 ms
  /*int sendTimeOLED = 200;
  if (millis() - last_oled_send > sendTimeOLED) {
    last_oled_send = millis();
    u8g2.clearBuffer();
    //u8g2.setFont(u8g2_font_8x13B_tf);
    //u8g2.setFont(u8g2_font_10x20_tf); //16px hoch
    u8g2.setFont(u8g2_font_fur20_tf); //20px hoch
    u8g2.setFontRefHeightExtendedText();
    u8g2.setDrawColor(1);
    u8g2.setFontPosTop();
    u8g2.setFontDirection(0);
    //u8g2.setCursor(0, 1);
    //u8g2.print(pmittel, 2);
    //u8g2.setCursor(72, 1);
    //if (Tmittel<100) {u8g2.print(Tmittel, 1);
    //}
    // else
    //{u8g2.print(Tmittel, 0);
    //}
    // u8g2.setFont(u8g2_font_5x7_tf);
    u8g2.drawUTF8(0, 25, "Öldruck bar");
    //u8g2.drawUTF8(72, 25, "Öltemp. C");
    u8g2.sendBuffer();
  }*/

  // print out the value you read:

  Serial.print("U= ");
  Serial.print(Vcc);
  Serial.println(" V");
  Serial.print("p= ");
  Serial.print(oilpressure);
  Serial.println(" bar");
  //Serial.print("T_int= ");
  //Serial.print(sensorValueT);
  //Serial.print(" int/ U= ");
  Serial.print("U_R2= ");
  Serial.print(SpannungR2);
  //Serial.print(" V/ R= ");
  Serial.println(" V");
  //Serial.print(R);
  //Serial.print(" Ohm/ T= ");*/
  Serial.print("T= ");
  Serial.print(oiltemp);
  //Serial.print(" °C / T(R)=");
  //Serial.print(oiltempR);
  Serial.println(" °C");
  Serial.println("----------");
  delay(1000);        // delay in between reads
}

Mach Dir das doch nicht so schwer.
Gib die ganzzahligen Stützwerte an, und die dazugehörigen Temperaturen.
Also analogRead() zu Temperatur
15 -> 140°C
19 -> 130°C
usw.
Mache Dir eine lookuptable und baue Dir das Konstrukt in 20 Codezeilen zur Auswertung.
Den Ansatz hab ich Dir doch schon auf dem Silbertablett geliefert.