It works but is it being done correctly: multiple DS18B20s 1-Wire Bus

I have a question about retreiving data from a multiple sensor 1-Wire bus using an Arduino UNO.

Is this the correct way to request the data involving two DS18B20 sensors on a one wire bus:

float flue_pipe_temp;
float blr_sup_wtr_temp;

sensors.requestTemperatures();  
   
flue_pipe_temp = sensors.getTempFByIndex(0);   // sensor 1

blr_sup_wtr_temp = sensors.getTempFByIndex(1);  // sensor 2

The above code works and I can create an independent temp change with each of the two sensors.
Is my understanding correct that the 'getTempFByIndex' function requires an increment for each additional sensor?

Also if I want to use another digital input pin for a second 1-Wire bus do I simply need to add an additional line of #define? And the sensors.requestTemperatures(); function will then scan both buses?

 #define ONE_WIRE_BUS 4    // define first bus input pin
 #define ONE_WIRE_BUS 6    // define 2nd bus input pin
 
  OneWire oneWire(ONE_WIRE_BUS);  // Setup a oneWire instance to communicate with OneWire devices

  DallasTemperature sensors(&oneWire);

That's usually how indexing something works. I'd take your working example as enough proof that this is what's happening here.

This, however

 #define ONE_WIRE_BUS 4    // define first bus input pin
 #define ONE_WIRE_BUS 6    // define 2nd bus input pin

immediately doesn't make sense. One symbol ONE_WIRE_BUS cannot simultaneously have two values.

So you need two symbols, at least, viz:

 # define ONE_WIRE_BUS_1     4    // define first bus input pin
 # define ONE_WIRE_BUS_2     6    // define 2nd bus input pin

And here's where we say any time you find yourself replicating something by appending an increasing digit, or with A, B, C as suffixes, you should start thinking about array variables, a shorthand for referring to many things that are the same.

Using array variables lead to… the ability to index your way through them, typically with a for loop.

And the power of that is cannot be overstated.

Array variables also go well with functions.

a7

2 Likes

sensors.requestTemperatures();

Suggestion:
You should disable waiting for a sensor’s response in your sketches otherwise you have code blocking.

This is what I was suspicious about. Having never did this type of thing I was unsure. So the bus_1 bus_2 is the way forward. :+1:

thanks for clarifying that....

I need to learn how to utilize arrays. I know they are super efficient. I am an "old dog" who needs to learn these new tricks...lol.

Can you expound on this concern? Is it wise to make the function call
with a provisional "if" or "!=" of some sort? Are you saying if the sensors.request gets locked up for some reason and never executes fully the code will be blocked?

No. If you use two buses, you'll need to duplicate everything, and scan each bus separately.

OneWire oneWire(ONE_WIRE_BUS);  // Setup a oneWire instance to communicate with OneWire devices

  DallasTemperature sensors(&oneWire);

So you'd need two OneWire objects, like oneWire_1 and oneWire_2 and so forth.

Which brings us to the question why two buses? The hole point of a bus, any bus in the context of microprocessor communication methods, is that everyone rides the (one) bus. There may be several buses i use at once, usually these would be if fundamentally different kinds, like one I2C handling what uses that standard, and one SPI for a few others and so forth. You will run into all of them sooner or later.

If you do have a legit reason to use two one wire buses, you should really be using (wait for it) array variables to manage all the bits that need to exist in support of those multiple identical things.

Arrays are not that complicated, at least your first uses of them need not be at all.

Curl up in front of a roaring fire, or under the umbrella at the beach, and read like you already know all about them. Ask questions here if you find a block that makes you stumble:

a7

  //start a new conversion request
  sensors.setWaitForConversion(false);    //  <-------<<<<<<< turn OFF Wait
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);     //  <-------<<<<<<< turn ON Wait

Example:

//Say this is your DS18B20 addresses 
//
//Freezer = 0x1035B58A0208009B  <-----<<<<   change to the appropriate address
uint8_t freezerAddress[8] = {0x10, 0x35, 0xB5, 0x8A, 0x02, 0x08, 0x00, 0x9B};

//Outside = 0x109CC18A02080023  <-----<<<<   change to the appropriate address
uint8_t outsideAddress[8] = {0x10, 0x9C, 0xC1, 0x8A, 0x02, 0x08, 0x00, 0x23};



// I n   l o o p ( )

//************************************************              T I M E R  read temperatures
//is it time to read the temperature sensors ?
if (millis() - readTempTime >= 2000)            //every 2 seconds
{
  //restart this TIMER
  readTempTime = millis();

  //**********************************
  temperatureFreezerC = sensors.getTempC(freezerAddress);

  temperatureOutsideC = sensors.getTempC(outsideAddress);

  //start a new conversion request
  sensors.setWaitForConversion(false);    //  <-------<<<<<<< turn OFF Wait
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);     //  <-------<<<<<<< turn ON Wait

}  //END of   readTemp TIMER

Both sensors will be on the same bus.

The 'getTempFByIndex()' and 'getTempCByIndex()' functions do indeed "work". However, they are horribly slow and inefficient. They scan the OneWire bus on EVERY call to determine the device's address based on the suppled index. Then they start a conversion and then wait (allowing the processor to do absolutely nothing else) for up to 750ms. Then they read the result. This pattern repeats itself on every call!!!

There's absolutely not need to keep calling setWaitForConversion() with arguments 'false' then 'true' like this.

See the 'WaitForConversion2' example in the DallasTemperature library. Despite its name, it actually doesn't wait for the conversion to happen! It illustrates how to use the library in the mode that allows useful work to be done while the conversion process is happening.

Calming music …

The user has the the option of doing as they wish.

This was a simple example demonstrating the use of the two 2 functions. :slight_smile:

1 Like

Understood. Is it any more efficient doing the:

deviceA = sensors.getTempC(deviceA Address);

I realize there are many ways to tackle coding situations and some are much more efficient than others and this is what makes for good programming habits versus bad programming habits. As user alto777 suggested I need to commit to learning arrays. My bucket list continues into old age. Lol...

It is if you handle the devices per the example I cited.

"See the 'WaitForConversion2' example in the DallasTemperature library."

Completely forgot about looking at the Dallas library... :+1:

image

1 Like

Funny guy.......us old farts are a little slower than these younger whippersnappers....
at least I am.... lol

Example:

//Freezer = 0x1035B58A0208009B  <-----<<<<   change to the appropriate address
uint8_t freezerAddress[8] = {0x10, 0x35, 0xB5, 0x8A, 0x02, 0x08, 0x00, 0x9B};  //address array <———<<<

There is a sketch, in the library, that will scan for temperature sensors and print their addresses.

Do this one at a time, write the address on a very small label :wink: and attach it to that sensor for later reference.

Take these addresses and place them into an array similar to that above.

Then address you sensors by their address.

You will be able to connect all your DS18B20s on the same bus and you can access them as needed.

1 Like

You get suggestion of the day! I am knee deep in playing with 'waitforconversion' right now.
The array approach seems a wise one.
thanks....

https://docs.arduino.cc/learn/communication/one-wire

Holy Crap!!! Now I get it about the wait for conversion issue, especially if dealing
with high resoution calls. Live and learn... its never too late. ...lol..

When you get time …

Set a non blocking TIMER to get the readings at a reasonably slow rate ex: 2 seconds.


//************************************************              T I M E R  read temperatures
//is it time to read the temperature sensors ?
if (millis() - readTempTime >= 2000)            //every 2 seconds
{
  //restart this TIMER
  readTempTime = millis();

  //**********************************
  temperatureFreezerC = sensors.getTempC(freezerAddress);
  Serial.print( “Freezer temperature is = “); 
  Serial.println( temperatureFreezerC );


  //start a new conversion request 
  sensors.setWaitForConversion(false);    //  <-------<<<<<<< turn OFF Wait, can be done in setup( )
  sensors.requestTemperatures();


}  //END of   readTemp TIMER

Here's a sample code I wrote for this thead. It uses an array and non-blocking techniques. In this case, the sensor addresses are hard-coded. But they can also be determined dynamically at run time.

#include <OneWire.h>
#include <DallasTemperature.h>

uint32_t waitTime;
uint32_t timer;
const uint8_t busPin = 2;

OneWire oneWire(busPin);
DallasTemperature sensors(&oneWire);

const DeviceAddress TempSensors[] = {
  { 0x28, 0x41, 0x6B, 0x07, 0xD6, 0x01, 0x3C, 0xAA },   // S01_ColdIntoPWT
  { 0x28, 0x4F, 0xEA, 0x07, 0xD6, 0x01, 0x3C, 0xBF },   // S02_ColdFromPWT
  { 0x28, 0xCF, 0xC2, 0x07, 0xD6, 0x01, 0x3C, 0x93 },   // S03_HotFromCompr
  { 0x28, 0xD4, 0x45, 0x07, 0xD6, 0x01, 0x3C, 0xAA },   // S04_HotFromPWT
  { 0x28, 0xC9, 0x05, 0x07, 0xD6, 0x01, 0x3C, 0x52 },   // S05_AmbientOfUnit
  { 0x28, 0xAA, 0xD5, 0xAC, 0x1D, 0x13, 0x02, 0xE5 },   // S06_InsideFluid
  { 0x28, 0xD4, 0xD1, 0xEA, 0x32, 0x14, 0x01, 0xDF },   // S07_CoolBoxS01
  { 0x28, 0xAA, 0xC3, 0xDB, 0x1D, 0x13, 0x02, 0x2B }    // S08_CoolBoxS02
};

void setup() {
  Serial.begin(115200);
  sensors.setWaitForConversion(false);
  sensors.begin();
  waitTime = sensors.millisToWaitForConversion(sensors.getResolution());
  sensors.requestTemperatures();
  timer = millis();
}

void loop() {
  uint32_t currentTime = millis();
  if (currentTime - timer >= waitTime ) {
    for (auto &addr : TempSensors) {
      float sensorTemp = sensors.getTempC(addr);
      Serial.println(sensorTemp);
    }
    sensors.requestTemperatures();
    timer = currentTime;
  }

  // Do useful stuff here while waiting for sensors to take readings

}
1 Like

I appreciate your sharing that code as an array example.
One question I have is after setting up that array and retreiving the sensor data in the void loop() instead of just observing the data on a serial monitor can you also pull out the sensor value of a specific address to use in a logic statement. Or is it more straightforward to just directly request data from a specific sensor? If the array knows T1 is the first sensor address and so on then perhaps there is a way to get that one value and/or other values. I am asking with little current knowledge on arrays structures.