esp8266 with multiple DS18B20

I am trying to read some DS18B20 devices with an ESP8266, using parasitic power because I want to use only two wires to the sensor(s), not three. I have read elsewhere that the ESP8266 pins don’t provide enough power to drive the sensor correctly, so a power boost is needed from a mosfet. So my circuit is excatly as in the Dallas datasheet (page7, fig 6).

When it comes to requesting temperatures from the devices, there is a library function requestTemperatures() which should ask for all values on the bus. But this does not work, I get 85 degrees for all sensors.
If I use the individual requestTemperaturesByAddress(addr), everything works fine. But this takes three times as long because I have to wait for each conversion separately. I would have thought that, having been given the instruction to convert, each device could work in parallel, ready to provide results when asked otherwise, why have a function which purports to request all at the same time?

So I wonder what I am doing wrong; how can I save around 200ms each time?

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

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
#define MOSFET_HARD_PULLUP 13

// 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 insideTemp, outsideTemp, fridgeTemp;
unsigned long lastTempRequest = 0;
const int resolution = 9;
// conversion delay depends on resolution required
const int delayInMillis = 750 / (1 << (12 - resolution));

// function to print a ds18b20 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);
  }
}
// function to print the temperature for a ds18b20 device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.println(tempC);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Dallas Temperature Control Library - Async Demo");
  Serial.print("Library Version: ");
  Serial.println(DALLASTEMPLIBVERSION);
  Serial.println("\n");
  
  // for switching on MOSFET while converting
  pinMode(MOSFET_HARD_PULLUP, OUTPUT);
  digitalWrite(MOSFET_HARD_PULLUP, HIGH);

  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");

  sensors.getAddress(insideTemp, 0);
  sensors.getAddress(outsideTemp, 1);
  sensors.getAddress(fridgeTemp, 2);
  
  sensors.setResolution(insideTemp, resolution);
  sensors.setResolution(outsideTemp, resolution);
  sensors.setResolution(fridgeTemp, resolution);

// check to see that addresses have been read correctly: communication is taking place.
  Serial.print("inside Address:  ");      printAddress(insideTemp); Serial.println();
  Serial.print("outside Address: ");      printAddress(outsideTemp); Serial.println();
  Serial.print("fridge Address:  ");      printAddress(fridgeTemp); Serial.println();

  // we will be timing our own conversion, so don't wait the default amount
  sensors.setWaitForConversion(false);
}

void convertDelay() {
  int tempReq = millis();
  while (millis() - tempReq < delayInMillis) // waited long enough??
  {
    delay(1);
    //idle++;
  }

}
void getTemps() {
  float t1, t2, t3;

  /*****  this method does not work; all sensors return  85 */
  sensors.requestTemperatures();
  digitalWrite(13, LOW);
  convertDelay();
  digitalWrite(13, HIGH);
  
  /******* this method works but takes 3x as long ********/
  /*
  sensors.requestTemperaturesByAddress(insideTemp);
  digitalWrite(13, LOW);
  convertDelay();
  digitalWrite(13, HIGH);


  sensors.requestTemperaturesByAddress(outsideTemp);
  digitalWrite(13, LOW);
  convertDelay();
  digitalWrite(13, HIGH);

  sensors.requestTemperaturesByAddress(fridgeTemp);
  digitalWrite(13, LOW);
  convertDelay();
  digitalWrite(13, HIGH);
*/
  t1 = sensors.getTempC(insideTemp);
  t2 = sensors.getTempC(outsideTemp);
  t3 = sensors.getTempC(fridgeTemp);
  Serial.print("inside  = ");   Serial.println(t1);
  Serial.print("outside = ");   Serial.println(t2);
  Serial.print("fridge  = ");   Serial.println(t3);

  Serial.println();

}
void loop() {
  getTemps();
  delay(10000);
}

The sensors are powered through the 4.7k resistor. Fig. 6 is useful if you have a lot of sensors all doing temperature conversions at the same time. How many do you have?

Yes, you can request all devices to do a temperature conversion simultaneously. But then you should not request again. Use the “get” functions to get the result of that conversion.

You can even set the waitForConversion flag so that the library does not wait after issuing the requestTemperatures(). Your code can continue working while you wait for the appropriate amount of time.

quilkin:
I am trying to read some DS18B20 devices

So how many is "some"?
With code like this

}
void loop() {
  getTemps();
  delay(10000);
}

You should have no trouble reading about fifty, using the standard no-frills example included in the library

The temperature register of each sensor is automatically set to 85 degrees on power up. The fact that you are getting that value suggests that your parasite power arrangement is not sufficient to do a conversion on all the sensors at the same time. The parasite power doesn't supply them enough power and they all go through their power up sequence which resets the temperature to 85C.

Pete

An ESP8266 pin can comfortably supply 10 mA. This sensor requires 0.5-1 mA when active, much less when idle. No problem there.

MorganS:
How many do you have?

Sorry, I should have said; it's only 3 (although my code shows this)

MorganS:
But then you should not request again. Use the "get" functions to get the result of that conversion.

I'm only making one call to 'requestTemperatures()'. The subsequent calls to 'requestTemperaturesByAddress' are an alternative, not in addition to, the call to request all of them at once.

wvmarle:
An ESP8266 pin can comfortably supply 10 mA. This sensor requires 0.5-1 mA when active, much less when idle. No problem there.

I tried at first with just one sensor, a 4k7 pllup and no mosfet. All responses were -127 degrees. Someone suggested using a 1k instead of 4k7 but that did not help. After a bit of research I found that the esp8266 doesn't supply enough current through the pin (when set up as a oneWire bus) which is why I added the mosfet.

el_supremo:
The fact that you are getting that value suggests that your parasite power arrangement is not sufficient to do a conversion on all the sensors at the same time.

Yes, that would explain it, but the mosfet should be able to supply plenty of power. So maybe I'm driving it incorrectly, or in the wrong sequence. I'll keep on trying different timings.

Wonder why that would be, not enough power supplied. The actual absolute limit is 20 mA or so.

The data sheet says you always have to add a MOSFET for strong pull-up, and enable that while temperature conversion is in progress.

This makes me wonder: why isn't it enough to set the pin to OUTPUT, HIGH at this time? I assume at least that's what the library does for you.

One thing I do notice in your code is that you set the MOSFET pin to HIGH. It's a high side switch, so you need a p-channel MOSFET (or PNP transistor), and that in turn requires the gate to be low to switch on. Setting the pin HIGH switches it off.

Post your circuit diagram, then we can see what's going on.

wvmarle:
One thing I do notice in your code is that you set the MOSFET pin to HIGH. It’s a high side switch, so you need a p-channel MOSFET (or PNP transistor), and that in turn requires the gate to be low to switch on. Setting the pin HIGH switches it off.

Post your circuit diagram, then we can see what’s going on.

It is a p-channel mosfet (I think - I’m not an expert on these parts ! - it’s a ZVP3306A). The circuit is as per the Dallas datasheet (I have copied the relevant bit in the attachment); the mosfet is driven from pin 13 and the onewire bus is on pin 2. If it is relevant, the ESP module is the ‘Feather Huzzah’.

I’ve got some old PNP transistors in stock so I may try one of those later.

dallas.PNG

wvmarle:
This makes me wonder: why isn't it enough to set the pin to OUTPUT, HIGH at this time? I assume at least that's what the library does for you.

Forgot to comment on this bit. AFAICS (I've looked at the source) the library doesn't do anything to the pin settings during the wait time. Earlier I was going to ask in this forum if there was a tested way of modifying the code to change the pins to/from OneWire settings, but the mosfet solution seemed safer.

That’s a P-channel MOSFET alright.
Not really logic level, at VGS = -5V it’s not fully open yet. Not sure if it’s good enough for your application. The RDS, ON is also quite high for this MOSFET, that combined with it being not completely open means it won’t produce that much more current than an ESP pin would do.
The main thing is that you have to set your pin to OUTPUT, LOW during conversion to switch it on, and OUPUT, HIGH for the rest of the time to switch it off. It’s also good practice to add a pull-up resistor to the MOSFET gate to keep it switched off while the ESP starts up and the pins are still in INPUT mode.
You can also try to make changes to the library, it seems it has a parasitic power option already. The pin the output of the DS18B20 is connected to should be set to OUPUT, HIGH during conversion, then back to INPUT for normal communication.

Many thanks. You’re correct on both counts.

wvmarle:
Not sure if it’s good enough for your application. The RDS, ON is also quite high for this MOSFET, that combined with it being not completely open means it won’t produce that much more current than an ESP pin would do.

That would explain a lot. Removed the mosfet and tried your other suggestion…

You can also try to make changes to the library, it seems it has a parasitic power option already. The pin the output of the DS18B20 is connected to should be set to OUPUT, HIGH during conversion, then back to INPUT for normal communication.

…which works fine, using just the single request for all 3 sensors. I should have tried that before, but not wanting to learn the ins and outs of the oneWire system I didn’t feel up to messing with it.
The odd thing is that although the library has a variable for parasite mode, it doesn’t do a lot with it - certainly doesn’t use it to switch the pin mode. I’ll add a comment/issue to the github page.

For anyone else having a similar issue in future, here’s my working code:

        sensors.requestTemperatures();
	pinMode(ONE_WIRE_BUS, OUTPUT);
	digitalWrite(ONE_WIRE_BUS, HIGH);
	int tempReq = millis();
	while (millis() - tempReq < delayInMillis) 
	{
		delay(1);
		// could do other stuff here if needed
	}
	pinMode(ONE_WIRE_BUS, INPUT);
//now read temperatures....