DS18B20 waarde mappen

Hallo allemaal,

Ik ben Rik, 38 jaar en bezig met een dashboard project. Daarbij wil ik een DS18B20 gebruiken als probe om de koelwater temperatuur uit te lezen en weer te geven op een SPI OLED op het dashboard.

Het initiele plan was om de "onboard" sensor van de auto te gebruiken, echter ben ik van dit plan afgeweken. De onboard sensor is er een waarbij de weerstand op-/afloopt al naar gelang de temperatuur. Hierop is ook mijn (deels geleende) sketch afgestemd. Nu ik de DS18B20 wil gebruiken, gaat volgens mij de map functie niet meer op, waardoor ik de juiste waarde niet weer kan geven op de dial op de OLED.

Onderstaand de sketch:

/////////////////////////////////////////////////////////////////
  //      Arduino OLED VW Jetta Digidash V.1            //
 //       Design and coding: R. Spijkers             //
//   19-1-2021    //
/////////////////////////////////////////////////////////////////

#include "U8glib.h"
// pins on the Arduino 
  #define OLED_SCK  13   
  #define OLED_MOSI 11
  #define OLED_CS   10    
  #define OLED_DC    7  
  #define OLED_RES   8 
#include <OneWire.h> 
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2 

// U8GLIB constructor OLED display
  U8GLIB_SSD1306_128X64 u8g(OLED_SCK, OLED_MOSI, OLED_CS, OLED_DC, OLED_RES);

int frame = 0;

int xmax=128;                                   // max length x-axis
int ymax=62;                                    // max length y-axis
int xcenter=xmax/2;                             // center of x-axis
int ycenter=ymax/2+10;                          // center of y-axis
int arc=ymax/2;                              
int angle=0;                                    
char* label[] = {"LOAD","COOLANT","INTAKE", "VOLT"};    // some custom gauge labels
int labelXpos[] = {53, 45, 49, 53};                     // predefined x-position of a gauge label
//#define potmeterPin A1                                  // simulate analogue value with potentiometer
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);
int p, w, m;
u8g_uint_t xx=0;

// ------------------------------------------------- void gauge() ------------------------------------------
void gauge(uint8_t angle) {

 // draw border of the gauge
 u8g.drawCircle(xcenter,ycenter,arc+6, U8G_DRAW_UPPER_RIGHT);
 u8g.drawCircle(xcenter,ycenter,arc+4, U8G_DRAW_UPPER_RIGHT);
 u8g.drawCircle(xcenter,ycenter,arc+6, U8G_DRAW_UPPER_LEFT);
 u8g.drawCircle(xcenter,ycenter,arc+4, U8G_DRAW_UPPER_LEFT);

 // draw the needle
 float x1=sin(2*angle*2*3.14/360);              // needle position
 float y1=cos(2*angle*2*3.14/360);  
 u8g.drawLine(xcenter, ycenter, xcenter+arc*x1, ycenter-arc*y1);
 u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_LEFT);
 u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_RIGHT);
 u8g.setFont(u8g_font_chikita);
 
 // show scale labels
 u8g.drawStr( 15, 42, "0C");                    
 //u8g.drawStr( 25, 18, "25");
 u8g.drawStr( 55, 14, "90C");
 //u8g.drawStr( 95, 18, "75");
 u8g.drawStr( 105, 42, "120C");
 
 // show gauge label
 u8g.setPrintPos(labelXpos[1],32);             
 u8g.print(label[1]);

}
 }
//}

// ------------------------------------------------- void setup() ------------------------------------------
void setup(void) {
u8g.firstPage(); 
 do {  
 pinMode(potmeterPin, INPUT);
 u8g.setFont(u8g_font_chikita);
 u8g.setColorIndex(1);                         // Instructs the display to draw with a pixel on. 

 // assign default color value
 if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255);                     // white
 }
 else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3);                       // max intensity
 }
 else if ( u8g.getMode() == U8G_MODE_BW ) {
u8g.setColorIndex(1);                       // pixel on
 }
 else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255,255,255);
 }
}

// ------------------------------------------------- void loop() ------------------------------------------

void loop(void) {

 p = sensors.getTempCByIndex(0);
 //p = analogRead(potmeterPin);                  // get value from potmeter
 w = map(p,0,1023,0,100);                      // map it between 0 and 100
 m = map(p,0,1023,0,90);                       // map needle movement

 // show needle and dial
 xx = m;                                      // 135 = zero position, 180 = just before middle, 0 = middle, 45 = max
 if (xx<45){                                   // position correction
xx=xx+135;
 }
 else {
xx=xx-45;
 }
 
 // picture loop
 {
u8g.firstPage();  
do {              
 gauge(xx); 
} 
while( u8g.nextPage() ); 
 }
}

Hij zal vast een stuk netter kunnen, maar ben nog redelijk vers omtrend dit gebeuren. Alle suggesties zijn meer dan welkom! (tevens zijn de bitmaps eruit gehaald om hier ruimte te besparen..)
Dank zover!

Excuus Erik, done :slight_smile:

Ha, leesbare code! :wink: Zie ook hier waarom dat zo belangrijk is.

De map()-functie blijft zo te zien gewoon werken hoor, die doet het nl. ook voor negatieve getallen. Maar: alleen voor long, integer en byte. Als je er een float in stopt gaat het mis. Gebruik dan deze:

float floatMap(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Verder wil ik je adviseren om betere namen te bedenken voor je variabelen: namen als, p, w, m en xx betekenen niets voor iemand anders dan jijzelf, maar als je deze code later weer eens moet lezen of bewerken zul je er zelf ook moeite mee hebben. Eigenlijk moet je aan de naam al kunnen zien waar die voor dient.

Edit: ik zie dat de DS18B20 temperaturen tot +125°C kan meten, is dat wel genoeg?

Ha Erik,

Vervangt jouw code het onderstaande?

p = sensors.getTempCByIndex(0);[color=#222222][/color]
 //p = analogRead(potmeterPin);                  // get value from potmeter[color=#222222][/color]
 w = map(p,0,1023,0,100);                      // map it between 0 and 100[color=#222222][/color]
 m = map(p,0,1023,0,90);                       // map needle movement

De DS pakt inderdaad tot 125 graden. Dat is genoeg, als ie dat bereikt, sta ik al aan de kant met de auto :slight_smile:

rsk749:
Vervangt jouw code het onderstaande?

Nee, het is een vervanging voor/aanvulling op de ingebouwde map-functie. In je sketch moet je dan

w = map(p,0,1023,0,100);

vervangen door

w = floatMap(p,0,1023,0,100);

en natuurlijk de functie zelf toevoegen. Maar voor de duidelijkheid: ik kan nu nog niet inschatten of dat nodig zal zijn.

rsk749:
als ie 125 graden bereikt, sta ik al aan de kant met de auto :slight_smile:

En moet je dus alsnog de Wegenwacht bellen. Waarom zou je dan nog al die moeite doen met een Arduino en een display ? :wink:

En ik zie net "VW Jetta" staan. Welk bouwjaar?

Thanks..

Ik heb het vermoeden dat het hele gebeuren in mijn sketch niet lekker omgaat met de waarden uit de DS18B20.
De waarde op het scherm (digitale VU meter type) blijft op 75% staan. Ook als ik de signaalkant van de DS18B20 lostrek..

Als ik de oude (analoge) sensor er tussen gooi en weer lees vanaf A0, krijg ik prima waardes door..

Welke waardes geeft sensors.getTempCByIndex(0); (*) en welke temperaturen horen daar bij?

*: Print de waardes evt. in de Serial Monitor.

16:11:31.840 -> Temperature is: 25.00 Requesting temperatures...DONE
16:11:33.339 -> Temperature is: 33.50 Requesting temperatures...DONE
16:11:34.841 -> Temperature is: 33.31 Requesting temperatures...DONE
16:11:36.388 -> Temperature is: 33.13 Requesting temperatures...DONE
16:11:37.888 -> Temperature is: 32.94 Requesting temperatures...DONE
16:11:39.387 -> Temperature is: 32.63 Requesting temperatures...DONE
16:11:40.886 -> Temperature is: 32.31 Requesting temperatures...DONE
16:11:42.392 -> Temperature is: 31.94 Requesting temperatures...DONE
16:11:43.891 -> Temperature is: 31.62 Requesting temperatures...DONE
16:11:45.395 -> Temperature is: 31.44 Requesting temperatures...DONE
16:11:46.883 -> Temperature is: 31.25 Requesting temperatures...DONE

Erik_Baas:
En ik zie net "VW Jetta" staan. Welk bouwjaar?

1983 :slight_smile:
Het originele cluster is defect en de 2 vervangende die ik had gescoord zijn ook ruk.. Dus zelf maar aan het bouwen geslagen. Ontwerp in CAD gemaakt, laten lasersnijden en 2 VDO meters erin. Originele km stand laten programmeren en de overige meters (koelwater en tank) wil ik op OLED...
De purist vermoord me, ik hou wel van dingen eigen maken.

Hoi Rik, welkom.

In antwoord 3 geeft Erik aan dat je met map geen float kunt gebruiken (en dat neem ik meteen van hem aan).
Float (klik!) is een afkorting voor "floating point", en het is een indicatie dat er een cijfernotatie word gebruikt met een komma (punt in Amerikaanse notatie) er in.
Erik biedt daar ook een mogelijke oplossing voor aan, namelijk een aparte functie (of library) die dit wel toelaat.

Ik vraag me af of je überhaupt wel getallen achter de komma nodig hebt als je een analoge wijzer emuleert die procentsgewijs aanwijst.
Want dan kun je de float eerst ombouwen naar een integer; in de link naar de Arduino documentatie hierboven staat helemaal onderaan hoe je dat zou kunnen doen.
Daarna zouden de resultaten weer als vanouds gebruikt moeten kunnen worden.

rsk749:
16:11:31.840 -> Temperature is: 25.00 Requesting temperatures...DONE
...
16:11:46.883 -> Temperature is: 31.25 Requesting temperatures...DONE

Tja, die getallen zeggen mij niet zo veel... Ik zou graag een vergelijking willen zien tussen de temp die de sensor aangeeft en de (geschatte?) werkelijke temp.

MAS3:
dat je met map geen float kunt gebruiken

Het kan wel, maar de resultaten zullen fout zijn: in die functie worden namelijk van alle parameters de decimalen afgekapt. Maar nogmaals, laten we even afwachten of dat wel nodig is.

rsk749:
1983 :slight_smile:

Nice! '84-er Golfje hier. Met een Jetta front, dat dan weer wel. :wink:

rsk749:
De purist vermoord me, ik hou wel van dingen eigen maken.

De eeuwige discussie.. :wink: Maar je zult soms wel moeten improviseren om de wagen op de weg te houden, zó simpel is het.

Beste rsk749,

Ik zit zo nu en dan met SSD1306 OLEDS te knutselen. Mijn aandacht werd getrokken door de opbouw van je sketch. Dat moet een fraaie gauge opleveren! Dus: sketch gedownload, DS18B20 aan een Nano geprikt, OLED erbij en testen maar.

Ik heb er dit van gemaakt. De schaal is nu tussen nul en 100. Om een beetje beweging in de naald te houden heb ik een int p toegevoegd en daarna p = 3*temperature toegevogd. Ik kan dan lichaamstemperatuur gebruiken om de gauge te testen.
Wat ik eigenlijk nog zou willen is het door de naaldpunt beschreven boogsegment in de edge van de gauge kleur geven als de naald (arc = 5). Alleen weet ik [nog] niet met welke u8g instructie ik willekeurige boogsegmenten kan laten tekenen. Wie? (of zoeken in de u8g documentatie voorbeelden)

succes, Photoncatcher - hier is de aangepaste sketch:

Succes, en hier volgt de aangepaste sketch:

/////////////////////////////////////////////////////////////////////////////
//                     Arduino OLED VW Jetta Digidash V.1                  //
//                                                                         //
//                   original design and coding: R. Spijkers               //
//                                19-1-2021                                //
/////////////////////////////////////////////////////////////////////////////
//
// adapted for DS18B20 sensor
// gauge scans 0 to 100 degrees
// Floris Wouterlood
// feb 15, 2021
// public domain

  #include "U8glib.h"
  U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);


   #include <OneWire.h>
   #include <DallasTemperature.h>
   #define onewirePin 2

   int frame =   0;
   int xmax  = 128;                                                          // max length x-axis
   int ymax  =  62;                                                          // max length y-axis
   int xcenter = xmax/2;                                                     // center of x-axis
   int ycenter = ymax/2+10;                                                  // center of y-axis
   int arc=ymax/2;                             
   int angle=0;                                   
   char* label[] = {"LOAD","","INTAKE", "VOLT"};                             // some custom gauge labels
   int labelXpos[] = {53, 45, 49, 53};                                       // predefined x-position of a gauge label

   float temperature;
   float displayed_temp;
   int p, w, m;
   u8g_uint_t xx=0;

   String mystring ;
   OneWire oneWire(onewirePin);
   DallasTemperature sensors(&oneWire);
   DeviceAddress Probe = { 0x28, 0xFF, 0xD7, 0x91, 0x92, 0x16, 0x04, 0x69 }; // find address with DS18B20 address finder


void setup(void) {
  
   Serial.begin (9600); 
   Serial.print ("Initializing Temperature Control Library Version ");
   Serial.println (DALLASTEMPLIBVERSION);
   sensors.begin ();              
   sensors.setResolution (Probe, 10);
   delay (500);
   Serial.println();
   Serial.print ("Number of Devices found on bus = ");  
   Serial.println (sensors.getDeviceCount());   
   Serial.print ("Getting temperatures... ");  
   Serial.println ();  

   
   u8g.firstPage();
   do { 
      u8g.setFont(u8g_font_chikita);
      u8g.setColorIndex(1);                                                  // instructs the display to draw with a pixel on.
      }
      while (u8g.nextPage()); 
} 


void loop(void) {

   sensors.requestTemperatures();                                            // command all devices on bus to read temperature 
   float tempC = sensors.getTempC(Probe);
   temperature = tempC;

   if (tempC == -127.00) 
   {
   Serial.print ("Error getting temperature  ");
   } 
   else

   Serial.println();
   delay(1000);
   Serial.print ("temperature --------- ");
   Serial.print (temperature,1);
   Serial.println (" *C"); 
  
   p = temperature*3;  // convert float to integer

   Serial.print ("p = temperature *3 -- ");
   Serial.print (p);
   Serial.println ("   *C - for testing purposes"); 
 
   w = map (p,0,10,0,100);                                                   // map it between 0 and 100 - was 1023
   m = map (p,0,100,0,90);                                                   // map needle movement

   // show needle and dial   
   xx = m;                                                                   // 135 = zero position, 180 = just before middle, 0 = middle, 45 = max
   if (xx<45)
      {                                                                      // position correction
      xx=xx+135;
      }
   else 
      {
      xx=xx-45;
      }

 
  // picture loop
  {
  u8g.firstPage(); 
  do {             
      gauge(xx);
     }
  while( u8g.nextPage() );
     }
}


void gauge (uint8_t angle) {

   u8g.drawCircle (xcenter,ycenter,arc+6, U8G_DRAW_UPPER_RIGHT);             // draw gauge edge
   u8g.drawCircle (xcenter,ycenter,arc+4, U8G_DRAW_UPPER_RIGHT);
   u8g.drawCircle (xcenter,ycenter,arc+6, U8G_DRAW_UPPER_LEFT);
   u8g.drawCircle (xcenter,ycenter,arc+4, U8G_DRAW_UPPER_LEFT);

   float x1=sin (2*angle*2*3.14/360);                                        // needle position
   float y1=cos (2*angle*2*3.14/360); 
   u8g.drawLine (xcenter, ycenter, xcenter+arc*x1, ycenter-arc*y1);
   u8g.drawDisc (xcenter, ycenter, 5, U8G_DRAW_UPPER_LEFT);
   u8g.drawDisc (xcenter, ycenter, 5, U8G_DRAW_UPPER_RIGHT);
   u8g.setFont (u8g_font_chikita);
 
   u8g.drawStr( 15, 42, "0");                                                // scale labels               
   u8g.drawStr( 55, 14, "50");
   u8g.drawStr( 105, 42, "100");
 
   u8g.setPrintPos (labelXpos[1],32);                                        // gauge label     
   u8g.print (label[1]);
}

Beste rsk749

over het bevriezen van sensor readings in u8g:

Zaak in u8g is dat het opvragen van de temperatuur van de probe in void loop - picture loop moet gebeuren. Je mag het opvragen niet in een aparte functie ('subroutine') zetten want dan wordt de waarde niet doorgegeven aan de float in void loop. Overigens, met een DS18B20 is werken met meer dan 1 decimaal eigenlijk onzin omdat 0,1 graad de nauwkeurigheid is van deze sensor.

succes, Photoncatcher

Ik weet niet of ik een OLED zou inbouwen. Die dingen geven amper licht, en branden in waar je bij staat. Als je veel uurtjes met je JETTA maakt dan kun je 2x per jaar nieuw schermpje inbouwen. Ik zou voor een SPI IPS schermpje gaan, kun je meteen in kleur werken.

Hoi blnkjns,

OLEDjes zijn bijzonder aardige dingen. Ik heb slechte ervaring met een OLED die ik had ingebouwd in een IOT weerstation en die altijd aan bleef. Die OLED was na een jaar compleet ingebrand.
Maar toch, je kunt er leuk mee spelen, zie plaatje, de sketch van Spijkers nog wat opgefleurd ! Met een goed voorbeeld kom je een heel eind weg. :slight_smile:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.