Multiple DS18B20 with Photon


#13

Published the library today under the name "DS18X20"
Github: https://github.com/MORA99/particle-ds18x20

Its a bit messy since its old C code, not a proper cpp class, if someone is up for the task of converting it that would be nice :slight_smile:


DS18b20 Working Example?
#14

Thanks @MORA your implementation worked for me finally sigh.
I had tried all the other solutions for working with onewire and dallas temperature with my photon but i always run into some compilation error. This just worked. I have only one (DS18B20) so i’ve just tested it with one sensor. Thanks again.


#15

That sounds similar to PoE way.


#16

Mora,
I’m new to Particle Photon. I’ve successfully build several tests with X-Band motion detector, etc. so I’ve become relative comfortable with the Photon and most of the tools, like the IDE. But I’m now trying to implement your library for the DS18B20. (I’ve tried a couple of other implementations, but yours seemed the most current, used the Photon and I see from this thread that others have used them AND THEY WORKED!)

I’m having a problem with every library I’ve tried. I’m not seeing the DS18B20.
I got two DS18B20’s from Adafruit. I’ve tried both of them. I’ve connected the data lead from the DS18B20 through the 4K7 resistor that came with the sensor to D0 of my Photon. I’ powering my breadboard, Photon and DS18B20 with 4.72v.

My code is your onewire.cpp, unmodified.

Any help would be appreciated.
Ray


#17

Your data line should be pulled high, so the resistor should go from data line on DS18B20 to either VIN or VCC on the photon.
And the datapin before the resistor should be connected to a photon digital pin.
GND to GND.

I generally dont use the parasitic power feature of the sensors, I always connect all 3 pins.


#18

I’ve got a small example explained over here. It’s only one sensor, but pictures are always nice to see how to hook one up :smile:


#19

That got me running. I didn’t understand the hookup.

I appreciate to good work you’ve done, and the quick response.

Thanks!


#20

Thanks! That got me up and running.


#21

For a multi-house HVAC project, I need to use many (About 30) water temperature sensors…

My original choice of water temperature sensor was one with PWM output, needing one digital I/O pin per sensor.
In this thread: Calculating a median value we ( @Ric, @BulldogLowell, @ScruffR, @peekay123, @Moors7 and others ) worked on a a sketch to read the temperatures of 16 of these sensors with one Particle. That works fine!

However, for several reasons, I would like to use the DS18B20 sensors. The main reason is that I can monitor even more sensors with less pins (= Only one!).
Today I started to try out the DS18B20 one-wire sensor, and I managed to read out one without problems.

But when I look at all the discussions in this forum about using Multiple DS18B20 with Photon, I am confused by the various methods and libraries used by many of you.

Below, I post a basic “under construction” sketch, to display the temperatures of 8 of these sensors on the serial monitor. Of course, at this moment it measures only one sensor, but it does that 8 times in a row in the loop():

Can anyone show me a simple way to make it read 8 different sensors on the bus?

Once I will be able to do that, I can adapt it to my purposes.

    /******************************************************************************************************
    DS18B20_temperature_monitor.ino
    
    Connections:  Sensor    Particle
                  ------    --------
                  Red       +5V (Vin)
                  Black     Gnd
                  Yellow    Any I/O (D2) => Attention: 4k7 pull-up resistor between yellow wire and +5V (May be reduced to 1k)
    *******************************************************************************************************/
    
    // Libraries for off-line use in the "Particle DEV" program:
     #include "Particle-OneWire.h"
     #include "DS18B20.h"
     DS18B20 ds18b20 = DS18B20(D2); // Sets Pin D2 for Temp Sensor
    
     float T1, T2, T3, T4, T5, T6, T7, T8;// Floating variables for calculations
    
    
    void setup()
    {
     pinMode(D2, INPUT);
     Serial.begin(9600);
    }
    
    
    void loop()
    {
     T1 = getTemp();
     delay(500);
     T2 = getTemp();
     delay(500);
     T3 = getTemp();
     delay(500);
     T4 = getTemp();
     delay(500);
     T5 = getTemp();
     delay(500);
     T6 = getTemp();
     delay(500);
     T7 = getTemp();
     delay(500);
     T8 = getTemp();
     delay(500);
    
     Serial.print(T1,1); Serial.print("-");
     Serial.print(T2,1); Serial.print("-");
     Serial.print(T3,1); Serial.print("-");
     Serial.print(T4,1); Serial.print("-");
     Serial.print(T5,1); Serial.print("-");
     Serial.print(T6,1); Serial.print("-");
     Serial.print(T7,1); Serial.print("-");
     Serial.println(T8,1);
    
     delay(500);
    }
    
    
    
    float getTemp()
    {
      float Reading;
      if(!ds18b20.search())
      {
        ds18b20.resetsearch();
        Reading = ds18b20.getTemperature();
        if (Reading >0 && Reading <120) // Don't use "impossible" values!
        {    
         return Reading;
        }
      }
    }

BTW: Actually, I made this sketch for displaying the 8 temperatures on a mini OLED display, but I removed that part for simplification:

Thanks a lot for your time!
:hand: :older_man:


#22

Here’s the way I’m doing it with 3 sensors. I’m only using the OneWire library. I used one of the demo programs in the library to get the addresses of the devices first, and hard coded those into the sketch.

#include "OneWire/OneWire.h"  

OneWire ds = OneWire(D4);  // 1-wire signal on pin D4
byte addrs[3][8] = {{0x28, 0x1B, 0x1C, 0xE3, 0x03, 0x0, 0x0, 0xC5}, {0x28, 0x8, 0x56, 0xE3, 0x3, 0x0, 0x0, 0x93}, {0x28, 0xD, 0xD3, 0xE2, 0x3, 0x0, 0x0, 0xEE}};
float temps[3];
float celsius, fahrenheit;

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


void loop() {
  
  ds.reset();            
  ds.skip();          // Make all devices start the temperature conversion
  ds.write(0x44, 1);     // tell it to start a conversion, with parasite power on at the end
  //ds.write(0x44, 0);        // or start conversion in powered mode (bus finishes low)

  delay(1000);     //  wait 1 sec for conversion

  ds.reset();
  
  for (int i=0; i<3; i++) {
      ds.select(addrs[i]);
      ds.write(0xBE,0);         // Read Scratchpad
    
       byte data0 = ds.read();
       byte data1 = ds.read();
       ds.reset();
      
      int16_t raw = (data1 << 8) | data0;
    
      celsius = (float)raw * 0.0625;
      fahrenheit = celsius * 1.8 + 32.0;
      temps[i] = fahrenheit;
  }
  
  Serial.printlnf("Temp 1: %.1f   Temp 2: %.1f  Temp 3: %.1f", temps[0], temps[1], temps[2]);
  delay(10000);
}

My devices are the DS18B20-PAR which can only use parasitic power (only 2 wires), so I pass 1 as the second parameter to ds.write(0x44, 1). If you’re using powered devices, then you would pass 0 there. You probably couldn’t power 30 devices at once in parasitic mode from a Photon pin. Which method are you planning on using?


#23

If you are looking at 30 or so sensors, you may want to consider reviewing some of the topographical hardware issues you may face.

I had this bookmarked from when I did an attic space monitor with 12 sensors. It was Arduino ethernet based, very reliable now, but it took me a while to balance the impedance of the circuit.

Sensors seem very accurate, by the way, not that a hot attic is a test of that.

PS: Use Your Arrays!!!

:slight_smile:


#24

Thanks @Ric!

I am using the waterproof type of sensors and do not plan to use the “parasitic” method as it limits the number of sensors too much.

Probably it’s fine indeed to use that hardcoded method if you have only a few sensors on the same bus.
I will try it out asap with a few sensors.

It would be nice though to be able to use a method that discovers the sensors on the bus and identifies the sensors by index… Maybe the library @MORA introduced above can do this?
:grinning:


#25

Thanks for this tip @BulldogLowell!
Your LINK is interesting reading indeed if you plan to use many one-wire devices!
My intention is to keep the weight and length between sensors and Photons as low as possible.
Arrays rock indeed!
:stuck_out_tongue_winking_eye:


#26

Yes, my library can scan a (or several) busses for sensors and list their factory id.
You can loop trough several busses and start temperature conversion, and then return a second later to read them.

If you want to cut down on IO pins you can even do it trough an analog multiplexor, as long as each output line as a pullup, very cheap solution to multiple busses :slight_smile:


#27

Do you have an example for many sensors?
:older_man:

With the example in the library below I don’t see how to do that.
Sorry but my experience is not big…

    #include "ds18x20/ds18x20.h"
    #include "ds18x20/onewire.h"
    
    uint8_t sensors[80];
    
    void log(char* msg)
    {
        Spark.publish("log", msg);
        delay(500);
    }
    
    void setup()
    {
        ow_setPin(D0);
    }
    
    void loop()
    {
        uint8_t subzero, cel, cel_frac_bits;
        char msg[100];
        log("Starting measurement");    
        
        DS18X20_start_meas( DS18X20_POWER_PARASITE, NULL ); //Asks all DS18x20 devices to start temperature measurement, takes up to 750ms at max resolution
        delay(1000); //If your code has other tasks, you can store the timestamp instead and return when a second has passed.
    
        uint8_t numsensors = ow_search_sensors(10, sensors);
        sprintf(msg, "Found %i sensors", numsensors);
        log(msg);
    
        
        for (uint8_t i=0; i<numsensors; i++)
        {
            if (sensors[i*OW_ROMCODE_SIZE+0] == 0x10 || sensors[i*OW_ROMCODE_SIZE+0] == 0x28) //0x10=DS18S20, 0x28=DS18B20
            {
                //log("Found a DS18B20");
    			if ( DS18X20_read_meas( &sensors[i*OW_ROMCODE_SIZE], &subzero, &cel, &cel_frac_bits) == DS18X20_OK ) {
    				char sign = (subzero) ? '-' : '+';
    				int frac = cel_frac_bits*DS18X20_FRACCONV;
    				sprintf(msg, "Sensor# %d (%02X%02X%02X%02X%02X%02X%02X%02X) =  : %c%d.%04d\r\n",i+1,
    				sensors[(i*OW_ROMCODE_SIZE)+0],
    				sensors[(i*OW_ROMCODE_SIZE)+1],
    				sensors[(i*OW_ROMCODE_SIZE)+2],
    				sensors[(i*OW_ROMCODE_SIZE)+3],
    				sensors[(i*OW_ROMCODE_SIZE)+4],
    				sensors[(i*OW_ROMCODE_SIZE)+5],
    				sensors[(i*OW_ROMCODE_SIZE)+6],
    				sensors[(i*OW_ROMCODE_SIZE)+7],
    				sign,
    				cel,
    				frac
    				);
    				log(msg);
    			}
    			else
    			{
    			    Spark.publish("log", "CRC Error (lost connection?)");
    			}
            }
        }
        delay(10000);
    }

#28

This line returns the amount of sensors found.
First argument is the limit to how many sensors you want, second argument is a pointer to an array where the sensors will be stored.

Then you loop over them with

for (uint8_t i=0; i<numsensors; i++)

Where each sensor takes up OW_ROMCODE_SIZE spots in the array, I believe its currently 11.


#29

OK, thanks @MORA!
The sketch indeed publishes every step as an event. Great!

This is the output I got in “Dashboard”: (! Sorted alphabetically, not in timestamp sequence!)

{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:38:53.031Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:01.581Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:05.587Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:09.601Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:13.609Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:17.621Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:21.634Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:25.643Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:29.653Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:33.663Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:37.675Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:41.688Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:45.698Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:49.706Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:53.719Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:39:57.734Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:40:06.276Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:40:10.294Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:40:14.298Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:40:18.308Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 0 sensors","ttl":"60","published_at":"2016-03-15T15:40:22.324Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 1 sensors","ttl":"60","published_at":"2016-03-15T15:38:48.502Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 1 sensors","ttl":"60","published_at":"2016-03-15T15:38:57.051Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Found 1 sensors","ttl":"60","published_at":"2016-03-15T15:40:01.751Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Sensor# 1 (28FF219F611503F9) = : +23.7500\r\n","ttl":"60","published_at":"2016-03-15T15:38:49.019Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Sensor# 1 (28FF219F611503F9) = : +23.7500\r\n","ttl":"60","published_at":"2016-03-15T15:38:57.566Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Sensor# 1 (28FF219F611503F9) = : +23.8125\r\n","ttl":"60","published_at":"2016-03-15T15:40:02.270Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:38:51.519Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:38:55.537Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:00.078Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:04.075Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:08.088Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:12.098Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:16.109Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:20.124Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:24.130Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:28.143Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:32.160Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:36.172Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:40.178Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:44.192Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:48.197Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:52.209Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:39:56.225Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:40:00.238Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:40:04.769Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:40:08.783Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:40:12.788Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:40:16.800Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}
{"data":"Starting measurement","ttl":"60","published_at":"2016-03-15T15:40:20.810Z","coreid":"xxxxxx-coreID-xxxxxxxxxxxxx","name":"log"}

As you can see, I have only one sensor on the bus for this test, and most of the times, the search fails…
The reason is certainly not bad connections or the pull-up resistor, because when I upload my other sketch for one sesor, it works perfectly every time!

Any idea?


#30

The search function in the OneWire library worked fine for me; that’s how I got the addresses of my 3 sensors. The code for that is in the Address_Scanner.ino file that is included with that library.


#31

I’m still trying to see why I get so many failed measurements with your library…
But this could be something:

Does this apply to sensors using parasitic power only?


#32

Nope it works with powered too, I noticed theres a fork of my lib on github where ATOMIC_BLOCK is added, so maybe others had issues with it, I will get that change merged back soon, but if you are up for it, you could fork it and import it privately.

I just tested 3 sensors, and while it works, I am not logging how many failed runs I get, just submits good runs to my server.