Dear community,
I have connected 4 DS18B20 in parallel to one pin of a NodeMCU, not in parasite mode.
However, during the runtime setup phase, only max. 3 devices are detected. I have tested all sensors, they are all OK, I can just only use 3 at a time.
The index range of devices is set to 0 to 15 in the code.
I also tried to power the sensors externally by connecting GND and 3.3V to an external source and only the data line pin to the digital pin on the NodeMCU.
Did anybody else experience this behavior before? Any known solutions?
I'm thankful for any hint as I didn't find any related issue before.
Thank you!
The code for the device detection was copied from a blog on the internet, I have added some minor lines to show the measurement duration:
//Setting the temperature sensor
void SetupDS18B20(){
DS18B20.begin();
Serial.print("Parasite power is: ");
if( DS18B20.isParasitePowerMode() ){
Serial.println("ON");
}else{
Serial.println("OFF");
}
numberOfDevices = DS18B20.getDeviceCount();
Serial.print( "Device count: " );
Serial.println( numberOfDevices );
lastTemp = millis();
DS18B20.setWaitForConversion(true); //true: waiting for measurement, false: No waiting for measurement
DS18B20.requestTemperatures();
lastTempDuration = -lastTemp + millis();
Serial.print( "Measurement duration: " );
Serial.println( lastTempDuration );
// Loop through each device, print out address
for(int i=0;i<numberOfDevices; i++){
// Search the wire for address
if( DS18B20.getAddress(devAddr[i], i) ){
//devAddr[i] = tempDeviceAddress;
Serial.print("Found device ");
Serial.print(i, DEC);
Serial.print(" with address: " + GetAddressToString(devAddr[i]));
Serial.println();
}else{
Serial.print("Found ghost device at ");
Serial.print(i, DEC);
Serial.print(" but could not detect address. Check power and cabling");
Serial.println();
}
//Get resolution of DS18b20
Serial.print("Resolution: ");
Serial.print(DS18B20.getResolution( devAddr[i] ));
Serial.println();
//Read temperature from DS18b20 and give needed measurement time in ms
float tempC = DS18B20.getTempC( devAddr[i] );
Serial.print("Temp C: ");
Serial.println(tempC);
}
}
Is there any reason why you are using the specific addresses when you fetch the data? I have had no trouble with multiple sensors when I use sensors.getTempFByIndex(i).
Also - you don't really have to check the resolution more than once. Once you set the resolution for a specific device it won't change until you set it again.
Similarly if you are using the specific addresses you don't have to search for them more than once as long as you save the values somewhere the first time.
Don
Hi Don,
thanks for your answer.
As I said, the code is copied from a blog, I wouldn't be able to come up with that 
However, I don't see why the resolution or device search would be executed more than once, as the code shown above is in the setup section of the Arduino code. It isn't contained in the loop part.
I have played a little with the pull-up resistor from 2200Ohm to 10kOhm though. With different resistances it turns out that a different number of devices are found. However, I was only able to detect 4 devices once, and then even with an unchanged pull-up, again only 3 devices.
Didn't find a sweetspot yet.
I also tried to power the sensors externally by connecting GND and 3.3V to an external source and only the data line pin to the digital pin on the NodeMCU.
You must always connect the grounds.
Please post a wiring diagram (not Fritzing) of the current setup .
janholger:
Did anybody else experience this behavior before?
Running four DS18B20s on one pin is normal, so maybe not. The code you are using is pretty decrepit. You would be a lot better off using the Dallas Temperature library, wherein would be some suitable examples, or this tutorial.
However, I don't see why the resolution or device search would be executed more than once, as the code shown above is in the setup section of the Arduino code. It isn't contained in the loop part.
You didn't tell us that.
This is a good example of why posting code snippets instead of the entire program isn't such a good idea.
Don
You haven't said much about your physical configuration.
Are you using discrete TO-92 devices, perhaps on a breadboard or are you using the 'waterproof' versions with longer connecting leads (or both).
If they have the long leads are they more than 3 meters long? Are they connected in a bus configuration or a star?
I have easily run several of each kind together with the discrete devices next to each other on a breadboard and the waterproof ones in a star configuration with one having a 3 meter long lead, all with a single 4700 ohm resistor, feeding an ESP8266. I use the Dallas Temperature library.
Don
Thanks everyone for dedicating your time to this issue.
My thinking was to only post the code snippet responsible for the DB18S20, so that no-one has to search through the whole code, but I see that that approach has its own shortcomings.
So here's the full example code:
#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
//------------------------------------------
//DS18B20
#define ONE_WIRE_BUS D3 //Pin to which is attached a temperature sensor
#define ONE_WIRE_MAX_DEV 15 //The maximum number of devices
// OLED Pins interface definition
#define OLED_RESET 4 //Define Display reset button?
Adafruit_SSD1306 display(OLED_RESET);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
int numberOfDevices; //Number of temperature devices found
DeviceAddress devAddr[ONE_WIRE_MAX_DEV]; //An array device temperature sensors
float tempDev[ONE_WIRE_MAX_DEV]; //Saving the last measurement of temperature
float tempDevLast[ONE_WIRE_MAX_DEV]; //Previous temperature measurement
long lastTemp; //The last measurement
const int durationTemp = 5000; //The frequency of temperature measurement
long lastTempDuration; //The duration of the last temperature sampling in ms
long lastTempDur[ONE_WIRE_MAX_DEV]; //Saving measurement duration for each device
//------------------------------------------
//WIFI
const char* ssid = "Honeymoon";
const char* password = "140315Basketball";
//------------------------------------------
//HTTP
ESP8266WebServer server(80);
//------------------------------------------
//Convert device id to String
String GetAddressToString(DeviceAddress deviceAddress){
String str = "";
for (uint8_t i = 0; i < 8; i++){
if( deviceAddress[i] < 16 ) str += String(0, HEX);
str += String(deviceAddress[i], HEX);
}
return str;
}
//Setting the temperature sensor
void SetupDS18B20(){
DS18B20.begin();
Serial.print("Parasite power is: ");
if( DS18B20.isParasitePowerMode() ){
Serial.println("ON");
}else{
Serial.println("OFF");
}
numberOfDevices = DS18B20.getDeviceCount();
Serial.print( "Device count: " );
Serial.println( numberOfDevices );
lastTemp = millis();
DS18B20.setWaitForConversion(true); //true: waiting for measurement, false: No waiting for measurement
DS18B20.requestTemperatures();
lastTempDuration = -lastTemp + millis();
Serial.print( "Measurement duration: " );
Serial.println( lastTempDuration );
// Loop through each device, print out address
for(int i=0;i<numberOfDevices; i++){
// Search the wire for address
if( DS18B20.getAddress(devAddr[i], i) ){
//devAddr[i] = tempDeviceAddress;
Serial.print("Found device ");
Serial.print(i, DEC);
Serial.print(" with address: " + GetAddressToString(devAddr[i]));
Serial.println();
}else{
Serial.print("Found ghost device at ");
Serial.print(i, DEC);
Serial.print(" but could not detect address. Check power and cabling");
Serial.println();
}
//Get resolution of DS18b20
Serial.print("Resolution: ");
Serial.print(DS18B20.getResolution( devAddr[i] ));
Serial.println();
//Read temperature from DS18b20 and give needed measurement time in ms
float tempC = DS18B20.getTempC( devAddr[i] );
Serial.print("Temp C: ");
Serial.println(tempC);
}
}
//Loop measuring the temperature
void TempLoop(long now){
if( now - lastTemp > durationTemp ){ //Take a measurement at a fixed time (durationTemp = 5000ms, 5s)
for(int i=0; i<numberOfDevices; i++){
lastTempDur[i] = millis();
float tempC = DS18B20.getTempC( devAddr[i] ); //Measuring temperature in Celsius
lastTempDur[i] = millis()-lastTempDur[i];
tempDev[i] = tempC; //Save the measured value to the array
}
lastTempDur[ONE_WIRE_MAX_DEV] = millis();
DS18B20.setWaitForConversion(true); //true: waiting for measurement, false: No waiting for measurement
DS18B20.requestTemperatures(); //Initiate the temperature measurement
lastTempDur[ONE_WIRE_MAX_DEV] = millis()-lastTempDur[ONE_WIRE_MAX_DEV];
lastTemp = millis(); //Remember the last time measurement
}
}
//------------------------------------------
void HandleRoot(){
String message = "Number of devices: ";
message += numberOfDevices;
message += "\r\n
";
char temperatureString[6];
message += "<table border='1'>\r\n";
message += "<tr><td>Device id</td><td>Temperature</td><td>Duration</td></tr>\r\n";
for(int i=0;i<numberOfDevices;i++){
dtostrf(tempDev[i], 2, 2, temperatureString);
Serial.print( "Sending temperature: " );
Serial.println( temperatureString );
message += "<tr><td>";
message += GetAddressToString( devAddr[i] );
message += "</td>\r\n";
message += "<td>";
message += temperatureString;
message += " C";
message += "</td>\r\n";
message += "<td>";
message += lastTempDur[i];
message += " ms";
message += "</td></tr>\r\n";
message += "\r\n";
}
message += "</table>\r\n";
message += "\r\n
";
message += "Time for request for Temperatures: ";
message += lastTempDur[ONE_WIRE_MAX_DEV];
message += "\r\n
";
server.send(200, "text/html", message );
}
void HandleNotFound(){
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/html", message);
}
//------------------------------------------
void setup() {
//Setup Serial port speed
Serial.begin(115200);
//Setup WIFI
WiFi.begin(ssid, password);
Serial.println("");
//Wait for WIFI connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.on("/", HandleRoot);
server.onNotFound( HandleNotFound );
server.begin();
Serial.println("HTTP server started at ip " + WiFi.localIP().toString() );
//Setup DS18b20 temperature sensor
SetupDS18B20();
//Setup OLED Display
display.begin(SSD1306_SWITCHCAPVCC, 0x78>>1);
display.display();
delay(2000);
display.clearDisplay();
}
void loop() {
long t = millis();
server.handleClient();
TempLoop( t );
}
I also attach the wiring schematics, in my physical bread board setup I'm using 4 sensors instead of the 3 in the schematics. The pics of the physical setup shows the sensors being connected to the 3V and GND of the NodeMCU, I also tried external powering with an additional supply, 3.3V and 5V. The resistors shown are 5.1kO and 100kO in parallel resulting in 4.75kO measured (probably due to tolerances).
The sensors are the water tight ones with a 5m cable length.
The code and schematics are from this site:
jremington:
You must always connect the grounds.
Please post a wiring diagram (not Fritzing) of the current setup .
For sure, all GND and 3V are connected in parallel to the respective pin on the NodeMCU. Problably wasn't so clear in the description, so I posted the wiring above to clarify.
5k1 and 100k in parallel sounds silly. That 100k is not going to make a significant difference. Recommended value is indeed 4k7 (interesting you don't have that very common value, but the less common 5k1) but it's not that critical. 10k is a bit much, but for a single sensor should still work. The data sheet talks about 5k for the resistor, then uses 4k7 in the reference circuits.
Just to make it clear: You have four sensors, but only three get detected. Then if you remove one, any one, the other three get detected regardless of which one is removed, right?
Nothing obviously wrong with your code.
I'm thinking that stray capacitance in your breadboard is a problem, in combination with stray capacitance of the sensor wires themselves. The first is the main suspect, breadboards are notorious for those parasitics. That, plus the fact you're working with 3.3V rather than 5V, you may consider lowering the resistor value a bit more: try a 3k3 resistor, or even 2k2.
Note: I can not find a minimum (or maximum) value specified for this pull-up resistor in the data sheet or elsewhere with a quick Google search. The data sheet mentions the device can sink at least 4 mA, but oddly doesn't give a maximum.
5k1 and 100k in parallel sounds silly
I have a package of different resistors from Taobao (living in China), maybe that's why the values are off the normal ones. The 100k in parallel brings the resistance down to 4.85k in theory, 4.75k in reality. Depending on the sensitivity of the sensors+wiring to this value, it might make a difference, so I used the available 2 resistor combo that got me closed to the 4.7k
But you are right, in the configuration of 3 sensors that actually work together, it doesn't have an impact.
I'm thinking that stray capacitance in your breadboard is a problem, in combination with stray capacitance of the sensor wires themselves. The first is the main suspect, breadboards are notorious for those parasitics.
No way of knowing for me I guess. We'll see when I transfer the design to a PCB.
That, plus the fact you're working with 3.3V rather than 5V, you may consider lowering the resistor value a bit more: try a 3k3 resistor, or even 2k2.
Did that, no change that I noticed.
Just to make it clear: You have four sensors, but only three get detected. Then if you remove one, any one, the other three get detected regardless of which one is removed, right?
They all work if I connect them as single devices or in pairs of two.
However, there is only one configuration that works with 3 in parallel, so I guess the one device left out of that configuration might be the problem. This is my working hypothesis going forward anyways.
Thanks for all your help, very much appreciated!!
That, plus the fact you're working with 3.3V rather than 5V
I went back to try the 5V and after some changes to the wiring, it actually worked! I don't yet know exactly what the issue was, but I best guess is that there probably was some GND potential difference between the sensors and the NodeMCU in my old 5V setup for some reason.
Thanks everyone, guys!
Special thanks to @wvmarle for pushing me in the 5V direction again!
As long as you have the grounds connected (as you anyway should have) there will be no problem for the ground potential.
But if you run them at 5V and pull up the data lines up to 5V you do risk damaging the NodeMCU. The inputs should have clamping diodes to help protecting them, still it's not a good thing to do.
The DS18B20 should work fine on 3.3V, minimum is 3.0V.
This link gives more information than you probably want about 1-wire networks. Here's one paragraph:
Precautions with Star Topologies
Testing has shown that unswitched star-type network topologies (i.e., those with several branches diverging at the master) are the most difficult to make reliable. The junction of various branches presents highly mismatched impedances; reflections from the end of one branch can travel distances equal to nearly the weight of the network (rather than the radius) and cause data errors. For this reason, the unswitched star topology is not recommended, and no guarantees can be made about its performance.
Don
Does that really matter for temperature sensors on short wires?
Nothing to indicate OP has attached long wires (5-10m or so) to those sensors.
wvmarle:
Does that really matter for temperature sensors on short wires?
No, but he is using long wires.
Nothing to indicate OP has attached long wires (5-10m or so) to those sensors.
Except for his statement in post #7.
Don
OK, I have now looked at the pictures. I would not doubt the sensors, or the cable, or their length, or using a 4k7 pullup, but those terminals look the same as I use, and I would have strong doubts about using them on a breadboard. OP needs to confirm that he/she has switched things around and shaken things up in that area.
The real story might be that the one terminal that doesn't work shouldn't, and he just got lucky with three that do.
It can't be hard to disprove the point using standard jumpers
those terminals look the same as I use, and I would have strong doubts about using them on a breadboard. OP needs to confirm that he/she has switched things around and shaken things up in that area
Definitly did that, switched sensors on different terminals, used the terminals in different places on the breadboard. Makes no difference.
Thanks for the link, Don, I will read up on that.
But if you run them at 5V and pull up the data lines up to 5V you do risk damaging the NodeMCU. The inputs should have clamping diodes to help protecting them, still it's not a good thing to do.
I thought about that too and had a look into the ESP8266 datasheet, I attached the relevant table to this post. It's not really clear as it says that 3.3V is the max input voltage and I understand that this is what should be applied. However, under the table it states that each GPIO has an ESD/overvoltage protection that triggers at 6V with a 5.8V holding voltage. So I concluded that while 5V input is not advisable longterm, it would probably work for testing purposes.
Anyways, I might have some level shifter lying around somewhere and will just use that going forward.
Please provide link to the complete document. This image is incomplete, the last sentence is cut off.
It's something I've been searching for a few times - I've seen conflicting information on whether or not GPIO pins are or are not 5V tolerant. It'd be awesome if they are, but so far I haven't been willing to try and risk sacrificing a NodeMCU on this test, and even if it would survive I still can't be sure whether it is because it is in spec or just by luck...
Atmel is quite clear about that: clamping diodes are in place, and you may rely on them to read high voltages with an appropriate current limiting resistor. Espressif is far less forthcoming with such technical details about their processor.
Maybe this discussion is also useful, I found it later: ESP8266 is 5V-tolerant after all? | .Stack | Hackaday.io