Particle electron with DS18B20 temperature sensor : No readings

I am tying to interface the particle electron with the DS18B20 temperature. I thought that it’d be straightforward as is on the arduino board. But on the electron, I get no readings, I tried to switch from the digital pins to the analog pins, I got nowhere. I’ve been on this the whole morning, and I am flustered as to what I am doing wrong on the electron board.

Here’s my code :

#include <OneWire.h>
 
// DS18S20 Temperature chip i/o
OneWire ds(D1);  // on pin 10 on arduino
 
void setup(void) {
  // initialize inputs/outputs
  // start serial port
  Serial.begin(9600);
}
 
void loop(void) {
 
  //For conversion of raw data to C
  int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
 
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
 
  if ( !ds.search(addr)) {
      Serial.print("No more addresses.\n");
      ds.reset_search();
      return;
  }
 
  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }
 
  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.print("CRC is not valid!\n");
      return;
  }
 
  if ( addr[0] == 0x10) {
      Serial.print("Device is a DS18S20 family device.\n");
  }
  else if ( addr[0] == 0x28) {
      Serial.print("Device is a DS18B20 family device.\n");
  }
  else {
      Serial.print("Device family is not recognized: 0x");
      Serial.println(addr[0],HEX);
      return;
  }
 
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end
 
  delay(1500);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
 
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad
 
  Serial.print("P=");
  Serial.print(present,HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print( OneWire::crc8( data, 8), HEX);
  Serial.println();
 
  //Conversion of raw data to C
  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
 
  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;
 
 
  if (SignBit) // If its negative
  {
     Serial.print("-");
  }
  Serial.print(Whole);
  Serial.print(".");
  if (Fract < 10)
  {
     Serial.print("0");
  }
  Serial.print(Fract);
 
  Serial.print("\n");
  //End conversion to C
}

this code I got from OneWire examples, well superbly on the arduino, digital pin 10. On the electron however, I get nothing. Anyone with any ideas what I’m missing?

There is a particle library I use for this sensor with gen3 devices: DS18B20

I have not tried it with the Electron, however. Perhaps it might get you going. You might take a look at the single drop example to see if it could work for you: ds18b20_SingleDrop.ino

2 Likes

Hi,

how did you connect the sensor? Did you add a pull-up resistor of 4k7 as recommended in the datasheet?
thanks

1 Like

I could be wrong on the sensor version but here’s an image of it :


and on the electron, I ddn’t need to do such, just a simple connection; left to ground, middle to +5v and S to the digital pin 10.

I saw the code, but I’m not sure how the circuit is connected, coz I see vccPin is D2? here’s a snippet of the code. I dont understand line 8 & 10, where pins D2 and D4 are defined, how do you connect your circuit?

#include <DS18B20.h>
#include <math.h>

const int      MAXRETRY          = 4;
const uint32_t msSAMPLE_INTERVAL = 2500;
const uint32_t msMETRIC_PUBLISH  = 10000;

const int16_t dsVCC  = D2;
const int16_t dsData = D3;
const int16_t dsGND  = D4;

// Sets Pin D3 as data pin and the only sensor on bus
DS18B20  ds18b20(dsData, true); 

char     szInfo[64];
double   celsius;
double   fahrenheit;
uint32_t msLastMetric;
uint32_t msLastSample;

void setup() {
  Serial.begin(115200);
  
  pinMode(dsGND, OUTPUT);
  digitalWrite(dsGND, LOW);
  pinMode(dsVCC, OUTPUT);
  digitalWrite(dsVCC, HIGH);

  delay(1000);
}

Would you mind explaining some more?

The sensor is connected to D2, D3 and D4 as their variable names suggest - should be self-explanatory.
This pin order is the default configuration of the sensor itself, where usually thy middle pin is the actual sensing pin.

In setup() these pins are driven LOW (D4 = dsGND) and HIGH (D2 = dsVCC) respectively, in order to power the sensor.
D3 is the data line.

In order to make the code fit your sensor’s pinout, you can just re-assign the pins as you see fit.

1 Like

I’ve tried the code, no errors, just “nan” values. I tried it on my boron as well, same thing. I don’t think it is a hardware fault because the sensor works just fine on the arduino with the oneWire library. I can’t pinpoint the issue here.

The sensor appears to have a resistor soldered on it already, [refer to the image] should I still manually add one perhaps?

this isn’t a 1:1 comparison as most Arduinos work on 5V logic while Particles work on 3.3V
IIRC there are sensors that can be used for both levels, but not all do.

I am using default examples in the code. I’ve tried the Dallas library, the one above, the OneWire example, the DS18b20 library in the web IDE, none work. So I really believe it is a wiring issue. My circuit ain’t 100. But I cannot pinpoint the issue. The datasheet says the sensor can work with 3.3v-5v meaning both the boron and electron should work. This tutorial interfaces with the particle photon :

Even though the sensor I am using already has the resistor soldered to it, that seemed like a similar approach I’d use, still nothing. But the sensor continues to work on the arduino, showing that the sensor is functional.
So, 1. the boron/electron can handle the sensor, 2. The sensor is functional on another board, 3. I am using default examples, so no coding mistake from me there, 4. my wiring seems simple enough, 3.3v to power pin, GND to GND pin, sensor to D0 like in the oneWire example.

In any case I’m missing something. I’ll keep looking and trying.

sorry for the delay getting back to you…

I used a 3.3 kΩ for 3.3V Boron device.
The resistor pictured, I believe, is 4.7 kΩ

As @ScruffR said, you can pinout the way you wish. In my case, D6 turned out to be my data pin. Per library example:

D2 dsVCC 3.3V
D4 dsGND GROUND
D3 dsDATA 3.3 kΩ pull-up between DATA and 3.3V VCC allowing max 1mA current flow

I came across this posting a couple of years ago and it helped me out:

https://community.particle.io/t/power-ds18b20-with-3-3v/48140/3

This is the product from Adafruit I hooked up. It comes with a 4.7 kΩ resistor. I reduced errors (NAN) significantly by reducing the resistor value.
https://www.adafruit.com/product/381

2 Likes

So you mean you added another 3.3Kohm resistor on top of the already existing one that came with the sensor? I tried that, for my sensor already has 4.7Kohm resistor on it, and I added 3.2Kohm resistor between data and 3.3V, still getting a “nan” reading

Okay… So after another day of toiling about. I finally got it to work. For anyone else in the future who may meet challenges interfacing the DS18B20 with the particle boron or electron, here’s how I got it to work. I did some research on the parasitic powering, and came up with this circuit (pardon my paint drawing) :


I added a 3.2kOhm (not 3.2 ohm as in the drawing!)

The code I used is as below :

// Include the libraries we need
#include <OneWire.h>
#include <spark-dallas-temperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS D3
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
// arrays to hold device address
DeviceAddress insideThermometer;
/*
 * Setup function. Here we do the basics
 */
void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");
  // locate devices on the bus
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");
  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  
  // Assign address manually. The addresses below will beed to be changed
  // to valid device addresses on your bus. Device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  // Note that you will need to use your specific address here
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
  // Method 1:
  // Search for devices on the bus and assign based on an index. Ideally,
  // you would do this to initially discover addresses on the bus and then 
  // use those addresses and manually assign them (see above) once you know 
  // the devices on your bus (and assuming they don't change).
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  
  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been
  // returned. A zero might mean that the bus is shorted, there are no devices, 
  // or you have already retrieved all of them. It might be a good idea to 
  // check the CRC to make sure you didn't get garbage. The order is 
  // deterministic. You will always get the same devices in the same order
  //
  // Must be called before search()
  //oneWire.reset_search();
  // assigns the first address found to insideThermometer
  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();
  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 9);
 
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();
}
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  // method 1 - slower
  //Serial.print("Temp C: ");
  //Serial.print(sensors.getTempC(deviceAddress));
  //Serial.print(" Temp F: ");
  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit
  // method 2 - faster
  float tempC = sensors.getTempC(deviceAddress);
  Serial.println(sensors.getTempC(deviceAddress));
  if(tempC == DEVICE_DISCONNECTED_C) 
  {
    Serial.println("Error: Could not read temperature data");
    return;
  }
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
/*
 * Main function. It will request the tempC from the sensors and display on Serial.
 */
void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  delay(500);
  
  // It responds almost immediately. Let's print out the data
  printTemperature(insideThermometer); // Use a simple function to print out the data
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

thanks to everyone that gave me ideas on how to tackle the problem.

1 Like

Glad you got it working.

To clarify, I did not use the 4.7 kΩ resistor provided with the kit. Instead, I installed the following:

External Pull-Up of 3 - 10K resistors in parallel to provide 3.3 kΩ or 10k || 10k || 10k → 3.33 kΩ

My goal (and others) was to limit the current flow to the pin to approximately 1 mA.
For a 3.3V device:
4.7 kΩ would be under this limit by roughly .3 mA while
4.7k || 3.3k → 1.93 kΩ would be over by about .7 mA.

1 Like