DS18B20 Switching pins during execution

As I said in another post, I have a code working in an arduino and I want to port to photon. In my code, I have 5 positions where a DS18B20 sensor can be placed. During execution, the user can plug it out from Pos1 and plugin the sensor to Pos2, and after a while, put it back to Pos1, remove the sensor completely or whatever.

Of course, the user has to tell the photon that the pin has change.

I tried with the current libraries in Particle cloud but it seems that I have to declare the pin at starting and I cannot change it after that. I tried declaring this line inside the getTemp function: DS18B20 ds18b20 = DS18B20(D2); but it doesn’t work at all.

Then I tested my arduino function (which doesn’t use temp library at all, just OneWire) but I always get 0.00 as a result. Can you tell me what is wrong with it?

float getTemperature(uint8_t pinTemp) {
  //returns the temperature from one DS18S20 in DEG Celsius
  byte data[12];
  byte addr[8];
  OneWire ds(pinTemp);
  if ( !ds.search(addr)) {
    //no more sensors on chain, reset search
    Serial.println("A1");
    ds.reset_search();
    return 0;
  }
  if ( crc8( addr, 7) != addr[7]) {
    //Serial.println("CRC is not valid!");
    Serial.println("A2");
    return 0;
  }
  if ( addr[0] != 0x10 && addr[0] != 0x28) {
    //Serial.print("Device is not recognized");
    Serial.println("A3");
    return 0;
  }
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1); // start conversion, with parasite power on at the end
  //byte present = ds.reset();
  ds.reset();
  ds.select(addr);
  ds.write(0xBE); // Read Scratchpad
  for (uint8_t i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
    Serial.println(data[i]);
  }
  ds.reset_search();
  byte MSB = data[1];
  byte LSB = data[0];
  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  Serial.println(tempRead);
  float TemperatureSum = tempRead / 16;
  return TemperatureSum;
}

This function always go inside A1 Serial print conditional.

What does "doesn't work at all" mean?

  • Does it not build?
  • Can you not access the object?
  • Can you not replace the object once constructed with one pin?
  • ...

About your Arduino code, can you add some more serial print statements to provide a better error description than "I always get 0.0"?

Here you have the DS18B20 sketch, modified to create DS18B20 object inside getTemp function:

[code]// This #include statement was automatically added by the Particle IDE.
#include “Particle-OneWire.h”

// This #include statement was automatically added by the Particle IDE.
#include “DS18B20.h”

DS18B20 ds18b20 = DS18B20(D2); //Sets Pin D2 for Water Temp Sensor
int led = D7;
char szInfo[64];
float pubTemp;
double celsius;

unsigned int Metric_Publish_Rate = 30000;
unsigned int MetricnextPublishTime;
int DS18B20nextSampleTime;
int DS18B20_SAMPLE_INTERVAL = 2500;
int dsAttempts = 0;

void setup() {
pinMode(D2, INPUT);
Serial.begin(38400);
Serial.println(“START”);
}

void loop() {

Serial.println("-------D2------");
getTemp(D2);
Serial.println("-------------");
delay(2000);
/*
Serial.println("-------D3------");
getTemp(D3);
Serial.println("-------------");
delay(1000);
Serial.println("------D4-------");
getTemp(D4);
Serial.println("-------------");
delay(1000);
*/
}

void getTemp(uint8_t pinTemp){
Serial.println(“getTemp”);
DS18B20 ds18b20 = DS18B20(D2);
if(!ds18b20.search()){
Serial.println(“resetSearch”);
ds18b20.resetsearch();
celsius = ds18b20.getTemperature();
while (!ds18b20.crcCheck() && dsAttempts < 4){
Serial.println(“Caught bad value.”);
dsAttempts++;
Serial.print("Attempts to Read: ");
Serial.println(dsAttempts);
if (dsAttempts == 3){
delay(1000);
}
ds18b20.resetsearch();
celsius = ds18b20.getTemperature();
continue;
}
dsAttempts = 0;
DS18B20nextSampleTime = millis() + DS18B20_SAMPLE_INTERVAL;
Serial.println(celsius);
}
}
[/code]

This is the output from console:

START
-------D2------
getTemp
-------------
-------D2------
getTemp
-------------
-------D2------
getTemp
resetSearch
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 1
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 2
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 3
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 4
C9
FF
CRC Failed
-0.50
-------------
-------D2------
getTemp
-------------
-------D2------
getTemp
resetSearch
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 1
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 2
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 3
C9
FF
CRC Failed
Caught bad value.
Attempts to Read: 4
C9
FF
CRC Failed
-0.50
-------------

All time I get this. Where do you want me to put serial prints?

This is a complete example with my function from arduino and the new OneWire library from Photon:

[code]#include “DS18B20/Particle-OneWire.h”

float getTemperature(uint8_t pinTemp);

void setup() {
Serial.begin(38400);
Serial.println(“START”);
}

void loop() {
Serial.print(“D2: “);
Serial.println(getTemperature(D2));
/*
Serial.print(”-----------------”);
delay(1000);
Serial.print(“D3: “);
Serial.println(getTemp(D3));
Serial.print(”-----------------”);
delay(1000);
Serial.print(“D4: “);
Serial.println(getTemp(D4));
Serial.print(”-----------------”);
*/
delay(1000);
}

float getTemperature(uint8_t pinTemp) {
//returns the temperature from one DS18S20 in DEG Celsius
byte data[12];
byte addr[8];
OneWire ds(pinTemp);
if ( !ds.search(addr)) {
//no more sensors on chain, reset search
Serial.println(“A1”);
ds.reset_search();
return 0;
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
//Serial.println(“CRC is not valid!”);
Serial.println(“A2”);
return 0;
}
if ( addr[0] != 0x10 && addr[0] != 0x28) {
//Serial.print(“Device is not recognized”);
Serial.println(“A3”);
return 0;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
//byte present = ds.reset();
ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (uint8_t i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.println(data[i]);
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); //using two’s compliment
Serial.println(tempRead);
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
[/code]

I always get 0.00. Nothing else.

Same wiring. I just replace code with online IDE.

Check an example, but I think you are supposed to have a one-second delay after this line.

ds.write(0x44, 0);

I just tried with a delay after my line and after yours (I have ds.write(0x44,1); and you wrote 0, I don’t know the difference so I tried both).

In both cases I don’t get crc errors, I just get 0.00 all the time. I will try a bit more, if I don’t get something working I will try to implement again all the function to read from this sensor following the datasheet.

Apologies, I copied the line from my own working example code. I meant:

ds.write(0x44, 1);

I don’t use parasitic mode so that might be the difference between your and my implementations.

I think I don’t use it neither I always power the sensor and I just use the data line to read it. It doesn’t get the power and gives data from the same line.

I get good readings with this

bool getTemp(int pin)
{
  DS18B20 ds18b20(pin);
  delay(1000); 
  if(!ds18b20.search())
  {
    int dsAttempts = 0;
    double _tempWater;
    ds18b20.resetsearch();
    _tempWater = ds18b20.getTemperature();
    while (!ds18b20.crcCheck() && dsAttempts < 4)
    {
      Serial.printf("Bad value (%d)", dsAttempts++);
      if (dsAttempts == 3)
        delay(1000);
      ds18b20.resetsearch();
      _tempWater = ds18b20.getTemperature();
    }
    Serial.println(_tempWater);
    tempWater = _tempWater;
    return (dsAttempts < 4);
  }
  return false;
}

Not for me. As soon as I include de line ds18b20(pin) inside the function, I just get CRC errors and problems like that. If I set it at setup, everything goes fine with your code. I don't know what is happening. The only thing the constructor does is setting the pin as input and assigning to a internal variable in OneWire, DS18B20 just create the OneWire object.

What system version and what version of the DS18B20 lib are you using?

I guess it is the latest version of DS18B20 since I got it from the online IDE (0.1.0.3) and the system version is 0.5.2 I found another post which explains how to get it.

What post would that be - got a link?

This is the post: Determining the version of system firmware on a Photon/P1

I see, the “modern” way to get that informoation is either

particle serial inspect

or just v via an serial terminal programm

(Both in Listening Mode)

I’ve just given that another shot and saw some problems with the library when used as you intend to.
The main problem will be potential memory leak since the lib uses ds = new OneWire(pin); but doesn’t delete(ds) anywhere.
The next is that the sensor will need some reads to settle in.
So I adapt the library a bit (added a destructor for DS18B20) and am running this adapted sample code which only reinstatiates the sensor object once a minute

#include "Particle-OneWire.h"
#include "DS18B20.h"

int led = D7;
char szInfo[64];
float pubTemp;
double celsius;
double fahrenheit;
unsigned int Metric_Publish_Rate = 30000;
unsigned int MetricnextPublishTime;
int DS18B20nextSampleTime;
int DS18B20_SAMPLE_INTERVAL = 2500;
int maxAttempts = 3;
int dsAttempts = 0;
DS18B20* ds18b20 = new DS18B20(D1); 


void setup() 
{
    Time.zone(+2);
    pinMode(D7, OUTPUT);
    pinMode(D0, OUTPUT);
    pinMode(D2, OUTPUT);
    digitalWrite(D2, LOW);
    digitalWrite(D0, HIGH);
    pinMode(D1, INPUT);
    Particle.variable("tempHotWater", &fahrenheit, DOUBLE);
    Serial.begin(115200);
}

void loop() 
{
  static uint32_t ms;
  static uint32_t msNew;
  
  if (millis() - ms > 1000)
  {
    getTemp();
    ms = millis();
  }
  
  if (millis() - msNew > 60000)
  {
      digitalWrite(D7, !digitalRead(D7));
      Serial.println("New instance");
      delete(ds18b20);
      msNew = millis();
      ds18b20 = new DS18B20(D1);
  }
}


void getTemp() 
{
    if(!ds18b20->search())
    {
      ds18b20->resetsearch();
      celsius = ds18b20->getTemperature();
      Serial.println(celsius);
      while (!ds18b20->crcCheck() && dsAttempts < maxAttempts)
      {
        Serial.println("Caught bad value.");
        dsAttempts++;
        Serial.print("Attempts to Read: ");
        Serial.println(dsAttempts);
        delay(dsAttempts * 200);
        ds18b20->resetsearch();
        celsius = ds18b20->getTemperature();
      }
      dsAttempts = 0;
    }
}

minimal destructor

DS18B20::~DS18B20() {
    delete(ds);
}

@ScruffR opened an issue on GitHub for the lib. I am getting the recommended changes implemented now and will update the lib in build as soon as I get it done. Any volunteers for testing?

1 Like

@LukeUSMC, I will. this afternoon I will reprogram my photon with the new code (from github?) and I will give a shot during a few hours. I will tell you what I find.

Thank you both, in advance, for your time.

Sorry for this up to an old post. But I am still having some issues with this topic. I did a test program to read 2 DS18B20 and modify 2 relays depending on the temperature read.

I simplified a bit the code because I had Adafruit PWM servo driver library to control some relays in a batch. Now it just measures 2 DS18B20 in D2 and D4 and switch on/off 2 relays in D3 and D6.

[code]// This #include statement was automatically added by the Particle IDE.
#include “DS18B20.h”

// This #include statement was automatically added by the Particle IDE.
#include “Particle-OneWire.h”

//#include “DS18B20/Particle-OneWire.h”
//#include “DS18B20/DS18B20.h”

#define TEMP_MAX_DAY 28
#define TEMP_MIN_DAY 27

#define PIN1 0
#define PIN2 1
#define PINTEMP D3

int led = D7;
char szInfo[64];
float pubTemp;
float celsius;
double fahrenheit;

DS18B20 ds18b20(D2);

unsigned int Metric_Publish_Rate = 5000;
unsigned int MetricnextPublishTime2;
unsigned int MetricnextPublishTime5;
int DS18B20nextSampleTime;
int DS18B20_SAMPLE_INTERVAL = 2500;
int dsAttempts = 0;
//DS18B20 ds18b20 = DS18B20(D2); //Sets Pin D2 for Water Temp Sensor

float tempe;
double max_val;
double min_val;

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

void setup() {
pinMode(PINTEMP, OUTPUT);
pinMode(6, OUTPUT);
Time.zone(+2);
Particle.syncTime();
//pinMode(D2, INPUT);
//Particle.variable(“temp”, &tempe, DOUBLE);
Serial.begin(9600);

Particle.publish("start", "INIT", PRIVATE);
max_val = TEMP_MAX_DAY;
min_val = TEMP_MIN_DAY;

}

void loop() {
runManagement(2, 3);
delay(100);
runManagement(4, 6);
delay(1000);
}

void publishData(uint8_t position){
if(!ds18b20.crcCheck()){
return;
}
sprintf(szInfo, “POS: %d --> %2.2f”, position, celsius);
Particle.publish(“dsTmp”, szInfo, PRIVATE);
if(position == 2) {
MetricnextPublishTime2 = millis() + Metric_Publish_Rate;
} else if(position == 4) {
MetricnextPublishTime5 = millis() + Metric_Publish_Rate;
}
}

bool getTemperature(uint16_t pinSensor, float *value) {
int dsAttempts = 0;
float _tempWater;
ds18b20.setPin(pinSensor);
delay(200);
if(!ds18b20.search()) {
ds18b20.resetsearch();
_tempWater = ds18b20.getTemperature();
while (!ds18b20.crcCheck() && dsAttempts < 4) {
//Serial.printf(“Bad value (%d)”, dsAttempts++);
if (dsAttempts == 3)
delay(200);
ds18b20.resetsearch();
_tempWater = ds18b20.getTemperature();
}
*value = _tempWater;
return (dsAttempts < 4);
}
*value = -1.0;
return false;
}

void runManagement(uint16_t pinSensor, uint8_t pinRelay) {

//tempe = celsius;
bool checker = false;
do {
    checker = getTemperature(pinSensor, &tempe);
    delay(1000);
    celsius = tempe;
} while(checker == FALSE);

if(tempe > max_val) {
    digitalWrite(pinRelay, LOW);
} else if(tempe <= min_val) {
    digitalWrite(pinRelay, HIGH);
}

if(pinSensor == 2 && millis() > MetricnextPublishTime2){
Time.zone(+2);
Particle.syncTime();
Serial.println(“Publishing now.”);
publishData(pinSensor);
}
if(pinSensor == 4 && millis() > MetricnextPublishTime5){
Time.zone(+2);
Particle.syncTime();
Serial.println(“Publishing now.”);
publishData(pinSensor);
}
}[/code]

I modified DS18B20 library. I added this function:

void DS18B20::setPin(uint16_t pin){
    ds->setPin(pin);
}

And then, in OneWire library:

void OneWire::setPin(uint16_t pin){ pinMode(pin, INPUT); _pin = pin; }

In both libraries, this function is defined in .h file.

It works fine for a while. Sometimes 4 loops, sometimes 10… But after some time, I don’t get any more publishing on particle console. While, I get them from other devices. So console is working.

I tested with destructor and without it in DS18B20 library. Same result. What could be happening? Memory leak? How can I get the memory use? I would want to print it by uart.

I am very surprised because the arduino version of this code has been working for one and a half year without any single problem (A couple of restaring due to power outrage it the office).

Until now I have tested it for a couple of minutes and yes, it worked but if I leave it about 10 minutes, it get stuck. No response from uart, no response from console… The only thing which seems to work is cyan led.

Usually you’d not switch pins on an already instantiated sensor object but have one object per sensor with it’s own pin assigned once and for all.
Switching pins that way would only make (some) sense if the one sensor actually got moved from one pin to another in hardware.

  DS18B20 sensorOnPin1(D1);
  DS18B20 sensorOnPin2(D2);

what would happen if at any moment I decide to use one of those pins for other purpose (lets say, dht22) and some time later go back to ds18b20 sensor? During execution without restarting. Ds18b20 instance would reconfigure pins as needed?

I will try that in a couple of hours and will tell what I find. That would solve my issue