Multi Drop DS18B20 NAN trouble

Hello all, I changed over to the DS18B20 library and it seems to work accept I get a NAN reading after a good reading. I was thinking it has to do with moving code from loop area to timer area? I stared at the code stupidly long enough. I’m not a programmer by any means. Any hints would be appreciated.

I would like to keep the multi drop code for future use.

#include <DS18B20.h>
#include <blynk.h>
#include <PowerShield.h>
#include <HX711ADC.h>
#include <SparkFunMAX17043.h>
#include <SparkCorePolledTimer.h>

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

unsigned long firstAvailable = 0;
int counter;
retained int retainedCounter = 0;

SparkCorePolledTimer updateTimer(5000);     //Create a timer object and set it's timeout in milliseconds        //TIMER
void OnTimer(void);                         //Prototype for timer callback method                               //TIMER

char auth[] = "************************";                   //blynk

double hiveweight = 0.0;                                    //scale 

double cellVoltage = 0.0;                                   //powershield
double stateOfCharge = 0.0;                                 //powershield

#define DOUT  3                                             //scale
#define CLK  2                                              //scale
HX711ADC scale(DOUT, CLK);                                  //scale

PowerShield batteryMonitor;                                 //powershield

const int MAXRETRY = 3;                                     //temp DS18B20 library
const int pinOneWire = D5;                                  //temp DS18B20 library
const int pinLED = D7;                                      //temp DS18B20 library
const uint32_t msSampleTime = 2500;                         //temp DS18B20 library
const uint32_t msPublishTime = 30000;                       //temp DS18B20 library
const int nSENSORS = 2;                                     //temp DS18B20 library

DS18B20 ds18b20(pinOneWire);                                //temp DS18B20 library

retained uint8_t sensorAddresses[nSENSORS][8];              //temp DS18B20 library

float celsius[nSENSORS] = { NAN, NAN };                     //temp DS18B20 library
double _temp;

void setup() {
  updateTimer.SetCallback(OnTimer);                                        //TIMER

  Blynk.begin(auth);  // Here your Arduino connects to the Blynk Cloud.    //blynk

  batteryMonitor.begin(); // This sets up the fuel gauge                  //powershield
  batteryMonitor.quickStart();                                            //powershield

  pinMode(pinLED, OUTPUT);                                                              //temp DS18B20 library
  ds18b20.resetsearch();                    // initialise for sensor search             //temp DS18B20 library
  for (int i = 0; i < nSENSORS; i++) {      // try to read the sensor addresses         //temp DS18B20 library
    ds18b20.search(sensorAddresses[i]);     // and if available store                   //temp DS18B20 library
  }                                                                                     //temp DS18B20 library

  scale.power_up();                          // SCALE-
  Serial.begin(9600); 
  delay(1000);                               // delay for everything to settle down
                      
// zero factor from SparkFun_HX711_Calibration by sarahalmutlaq
// long zero_factor = scale.read_average();                   //Get a baseline reading (for zero factor)
// Serial.print("Zero factor: ");                             //This can be used to remove the need to tare the scale. Useful in permanent scale projects.
// Serial.println(zero_factor);                               //note the zero factor to set the offset

  scale.set_scale(6538.f);         //6538 TAL214 load cell,6218wii load cell  // SCALE-this value is obtained by calibrating the scale with known weightssee the README for details, buttoncell5430,wiicell758;

                                 // long zero_factor = 8483395;         //set the zero_factor with number determined from "scale.read_average(20)"
                                 // scale.set_offset(zero_factor);      //Zero out the scale using a previously known zero_factor for a permanent weight on the scale
  scale.tare();				           // SCALE-reset the scale to 0, if your not setting the offset with "zero_factor
}

void loop() {
  Serial.begin(9600);
  bool wifiReady = WiFi.ready();
  bool cloudReady = Particle.connected();
  Serial.printlnf("wifi=%s cloud=%s counter=%d retainedCounter=%d", (wifiReady ? "on" : "off"), (cloudReady ? "on" : "off"),
    counter++, retainedCounter++);

  if (wifiReady) {
    updateTimer.Update();                                //TIMER, code executed at "void OnTimer(void) then continues here??
    Blynk.run(); // All the Blynk Magic happens here...  //blynk

// if (firstAvailable == 0) {
//                     firstAvailable = millis();
//                       }
// if (millis() - firstAvailable > 15000) {
// 			// After we've been up for 15 seconds, go to sleep. The delay is so the serial output gets written out before
// 			// sleeping.
// 			Serial.println("calling System.sleep(SLEEP_MODE_DEEP, 15 seconds)");
// 			delay(2);

// 			System.sleep(SLEEP_MODE_DEEP, 360); // deep sleep in seconds, 360sec=6min

// 			// The rest of the code here is not reached. SLEEP_MODE_DEEP causes the code execution to stop,
// 			// and when wake up occurs, it's like a reset where you start again with setup(), all variables are
// 			// cleared, etc.
// 			Serial.println("returned from sleep, should not occur");
// 	    	}
  }
  else {
    firstAvailable = 0;
  }
  delay(1000);
}

void OnTimer(void) {  //Handler for the timer, will be called automatically
  Serial.begin(9600);

  hiveweight = (scale.get_units(10));                  // SCALE-
  hiveweight = round(hiveweight * 10) / 10;              // SCALE, round to first decimal place 
  Serial.println("HIVE WEIGHT LBS");
  Serial.println(hiveweight);                         // SCALE-
                                                      //temp DS18B20 library
  static uint32_t msSample = 0;
  static uint32_t msPublish = 0;

  if (millis() - msSample >= msSampleTime) {                                               //temp DS18B20 library
    msSample = millis();
    for (int i = 0; i < nSENSORS; i++) {
      float temp = getTemp(sensorAddresses[i]);
      if (!isnan(temp)) celsius[i] = temp;
    }
  }                                               //temp DS18B20 library

  if (millis() - msPublish >= msPublishTime) {
    msPublish = millis();
    Serial.println("Publishing now.");
    publishData();
  }
}

double getTemp(uint8_t addr[8]) {                                                           //temp DS18B20 library
  double _temp;
  int   i = 0;

  do {
    _temp = ds18b20.getTemperature(addr);
  } while (!ds18b20.crcCheck() && MAXRETRY > i++);

  if (i < MAXRETRY) {
    _temp = ds18b20.convertToFahrenheit(_temp);
    Serial.println(_temp);
  }
  else {
    _temp = NAN;
    Serial.println("Invalid reading");                              //temp DS18B20 library
  }
  return _temp;
}

void publishData() {
  char szInfo[64];
  snprintf(szInfo, sizeof(szInfo), "%.1f �C, %.1f �C", celsius[0], celsius[1]);
  //   Particle.publish("dsTmp", szInfo, PRIVATE);

  //temp DS18B20 library      
  cellVoltage = batteryMonitor.getVCell();    // Read the voltage of the LiPo                 //powershield
  stateOfCharge = batteryMonitor.getSoC();    // Read the State of Charge of the LiPo         //powershield
  Serial.println("BATTERY");
  Serial.println(stateOfCharge);
  Serial.println("VOLTAGE");
  Serial.println(cellVoltage);

  Blynk.virtualWrite(V1, _temp);                    //BLYNK, photon BC, in office
  Blynk.virtualWrite(V2, _temp);                    //BLYNK, photon BC
  Blynk.virtualWrite(V5, hiveweight);               //BLYNK, photon BC
  Blynk.virtualWrite(V6, hiveweight);               //BLYNK, photon BC
  Blynk.virtualWrite(V9, cellVoltage);              //BLYNK, photon BC
  Blynk.virtualWrite(V10, cellVoltage);             //BLYNK, photon BC
  Blynk.virtualWrite(V13, stateOfCharge);           //BLYNK, photon BC
  Blynk.virtualWrite(V14, stateOfCharge);           //BLYNK, photon BC
  Blynk.virtualWrite(V17, _temp);                    //BLYNK, photon BC, in office
  Blynk.virtualWrite(V18, _temp);                    //BLYNK, photon BC
  Blynk.virtualWrite(V19, hiveweight);               //BLYNK, photon BC
  Blynk.virtualWrite(V20, hiveweight);               //BLYNK, photon BC
  Blynk.virtualWrite(V21, cellVoltage);              //BLYNK, photon BC
  Blynk.virtualWrite(V22, cellVoltage);             //BLYNK, photon BC
  Blynk.virtualWrite(V23, stateOfCharge);           //BLYNK, photon BC
  Blynk.virtualWrite(V24, stateOfCharge);           //BLYNK, photon BC
  Serial.println("sent it to BLYNK!");
}

This is the Serial output I get-

wifi=on cloud=on counter=1388 retainedCounter=5848
wifi=on cloud=on counter=1389 retainedCounter=5849
wifi=on cloud=on counter=1390 retainedCounter=5850
wifi=on cloud=on counter=1391 retainedCounter=5851
HIVE WEIGHT LBS
0.00
the temp is
70.70
the temp again
the temp is
nan
the temp again

First I’d do away with the SparkCorePolledTimer as there are now better options to do that.

Next, do you get the same issue with the multiDrop demo alone, without the extra libraries?

When you say

Does this mean you only have one sensor currently?
If so, you should change nSENSOR to 1.
Attempting to read a non-present sensor is bound to cause troubles.

What’s the reason for all these redundant Blynk.virtualWrite() calls that just publish the same variables multiple times?

In another thread you asked about temp vs. _temp and there is a perfectly good reason why I have used two different variable names in my library sample and having changed that may well be the reason why you are not getting the correct values anymore.
You may want to have a read about loval vs. global variables
In the original sample temp is global and _temp is local - but in your code things got a bit muddled up.

Finally

Usually having the work done in loop() rather than in a timer callback is the less problematic way to do it.

BTW, if you are using Web IDE, it’s always good to also supply a link to a sharable snapshot of your project alongside your code, for people who’d like to test your code themselves without having to got through the hassle of copy/pasting and importing all the individual libraries manually.
But be aware, these snapshots only live as long your project exists in your Web IDE account. If you remove it from there, all snapshot links will get invalid too.
https://docs.particle.io/guide/getting-started/build/photon/#sharing-your-app


I also took the liberty to reformat your code and removed these superfluous automatically added comments about library includes and excessively deep indentations.
Also adding loads of empty lines of code does only make the code longer, but doesn’t really make it easier to follow - much the contrary, as you can’t easily get the whole picture.

I I’ve done the demo alone with same results. I get proper temp readings but also the nan. I’m guessing its not an actual “not a number” reading because we don’t get a serial print “Invalid reading” with it.

Here is the link of the demo.

https://go.particle.io/shared_apps/5a89f6a53ffc1a20da00101d

I’m working on changing the timer over to the particle timer. It could take me awhile.

Thanks for your help ScruffR.

Could you also answer this part of my post?

yes one sensor connected

There you are then, the second sensor will never provide any other reading so the initial NAN will still prevail.

Hence my suggestion above

2 Likes

Oh, wow. Makes perfect sense.
Thanks again.

1 Like

Yup, did already the first time :wink:

1 Like

Hello All newbie Drew here.
I am using two DS18B20 Sensors with the <DS18B20.h> MultiDrop Example
For the life of me I can’t get it to work on a Photon. Keep getting NAN for the second sensor.
I have nSENSOR to 2.
I have used the scanner and it sees both sensors and reads them just fine.
I have the 4.7K resistor on the data line.
Using singledrop works for switching the wires from one sensor to the other.

All I am trying to do is separate the two sensors into separate values like two double values
Sensor 1 = TempIn
Sensor 2 = TempOut

Why is this so hard?

I think <DS18B20.h> and the MultiDrop example must of been written by Albert Einstein its way over complicated for just reading two temp sensors.

They could of ditched the delay, and the publish, and just give the example as simple and basic as possible, or include a basic, intermediate, and rocket scientist versions, a lot of people getting into Arduino, and Particle, and IOT are NOT programmers, guess lets scare the crap out of them quickly as possible LOL.

I can’t see any way to separate the two sensors into two different variables. TempIn and TempOut.

I can get the two sensors working great on Arduino Nano no problem then jumping over the HIGH brick wall trying to get to the Particle world is the hard part.

Any help would be greatly appreciated. (e.g. link to a basic version example of <DS18B20.h> with two sensors with separated variables that I can easily particle.publish(TempIn) and particle.publish(TempOut).
Thanks.

Unfortunately I’ve no devices to test with me, but sorry if that sample looks overly complicated, but having a look at it, I’m not sure how to make it a lot simpler.

If you can point out which parts are most confusing, we may be able to clarify.

Hello ScruffR Thanks for your reply!

I want to say I am I big fan of your posts and replies, your knowledge in this area is very impressive!
Thanks for all your help!

So I gave up on the “One Wire” option for the DS18B20 and just put the two sensors on their own separate pins, I know I cheated and too the easy way out of a complicated problem but it works and I had an extra pin to spare.

I didn’t end up using <DS18B20.h> or the Multi Drop example it simply would not work for me reading the second sensor value? Not sure what was wrong.

I ended up using DS18.h all though its not available directly by itself, its part of the “ONEWIRE” library.

The One Wire library has an example DS18x20_Temperature.ino which I cut down and simplified to.


// This Library is part of "OneWire" WebIDE will not find it by itself. 
// Search for OneWire open DS18.h copy your code to use this DS18.h Works Easy. 

#include "DS18.h"

DS18 sensor1(D3); //I am cheating and taking the easyway just use two pins....
DS18 sensor2(D4); //Pin sensor two. 

double TempIn;
double TempOut;

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

void loop() 
{

    if (sensor1.read())
        {
        TempIn = ("%.2f F ", sensor1.fahrenheit());
        }
    Serial.print("Temp In ");
    Serial.println(TempIn);
  
    if (sensor2.read())
        {
        TempOut = ("%.2f F ", sensor2.fahrenheit());
        }
    Serial.print("Temp Out ");
    Serial.println(TempOut);
  
}

This worked great for getting two separate variables from two separate DS18B20 sensors, simple basic “NewBie” level.

I hope soon my coding skills will improve and things will make more sense with the advanced level code.

Thanks again ScruffR for all your help!

3 Likes