Go Down

Topic: Trouble with a DS18B20 (Read 1 time) previous topic - next topic

BlueEther

Nov 21, 2016, 07:08 am Last Edit: Nov 21, 2016, 06:12 pm by BlueEther
We had an "over temp" event on a incubator at work so I set out to make an over-ride switch and or monitor. I started with the monitor to work out any kinks in the system with out turning anything off that should still be on and vice versa.

All ran fine for a few days and we had a good log of the .25 deg C swing as the heaters came on and of, then for some reason the esp8266 hung. A reset and all was fine again untill I showed the boss how to do a reset. At this point - with nothing changing in the setup or code the DS18B20 read about 7 deg C hotter. A few resets were performed with the same reading.

I then left it turned off for a few days and then last night I turned it back on - still to read ~6 or more deg too hot. I left it running over night and over the next ~18 hours the temp came down to the 34 C where the incubator is set at.

The DS18B20 is connected to about 500mm of cat5 (just a single pair removed) in parasite mode

Any thoughts on what may cause this?


pylon

I have doubts that the DS18B20 make wrong readings if accessed correctly. My guess is a wrong timing, especially because the sensor is running in parasite mode. Without the code and the wiring it's very hard to help you more.

MarkT

Radiant heat?  These digital sensors have failure modes like reading all zeroes, all ones or being
jammed, not reading wrong temperatures.

If your DS18B20 is in the black epoxy package its well able to sense radiant heat, whereas the
ones that come in metal tubes ignore most radiant heat and just measure the temperature of
the metal case.

It is possible that the analog side of the DS18B20 got affected somehow, but it would be unusual.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

MarkT

Oh, parasite mode?  Don't use it, you have CAT5 cable, use normal powered mode with a 100nF
decoupling capacitor on the supply at the DS18B20.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

BlueEther

#4
Nov 21, 2016, 06:21 pm Last Edit: Nov 21, 2016, 06:26 pm by BlueEther
This is the code more or less:
Code: [Select]

#include <Arduino.h>
#include <TimeLib.h>
#include <WiFiUdp.h>
#include <ESP8266WiFi.h>
#include <OneWire.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include <Array.h>

#define min(X, Y) (((X)<(Y))?(X):(Y))
#define max(X, Y) (((X)>(Y))?(X):(Y))

#define rLoc "HOME"
//#define rLoc "WORK"

/************************* WiFi Access Point *********************************/
#if rLoc == "HOME"
  #define WLAN_SSID       "BlueEther Tech"
  #define WLAN_PASS       "xxxxxxxxxxxxxxx"
#else
  #define WLAN_SSID       "KB-Corp"
  #define WLAN_PASS       "xxxxxxxxxxxxxxx"
#endif
/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "blueether"
#define AIO_KEY         "xxxxxxxxxxxxxxxxxxxxxxxx"

/************ Global State (you don't need to change this!) ******************/
// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;
//UDP for ntps
WiFiUDP Udp;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

/****************************** Feeds ***************************************/
// Setup a feed called 'photocell' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
#if rLoc == "HOME"
  Adafruit_MQTT_Publish tempOW = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempOWTest");
  Adafruit_MQTT_Publish tempHAvg = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempHAvgTest");
  Adafruit_MQTT_Publish tempHMin = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempHMinTest");
  Adafruit_MQTT_Publish tempHMax = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempHMaxTest");
  Adafruit_MQTT_Publish warningS = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/warningStringTest");
  Adafruit_MQTT_Publish warning = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/warningTest");
#else
  Adafruit_MQTT_Publish tempOW = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempOW");
  Adafruit_MQTT_Publish tempHAvg = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempHAvg");
  Adafruit_MQTT_Publish tempHMin = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempHMin");
  Adafruit_MQTT_Publish tempHMax = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/tempHMax");
  Adafruit_MQTT_Publish warningS = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/warningString");
  Adafruit_MQTT_Publish warning = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/warning");
#endif
Adafruit_MQTT_Publish battery = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/battery");

/*************************** Sketch Code ************************************/
// Bug workaround for Arduino 1.6.6, it seems to need a function declaration
// for some reason (only affects ESP8266, likely an arduino-builder bug).
void MQTT_connect();

// NTP Servers:
void sendNTPpacket(IPAddress &address);

static const char ntpServerName[] = "nz.pool.ntp.org";
const int timeZone = 12;     // Central European Time
unsigned int localPort = 8888;  // local port to listen for UDP packets
time_t getNtpTime();

int LEDPin = LED_BUILTIN;

OneWire  ds(D1);  // on pin Digital 1 (a 4.7K resistor is necessary)

bool sendH = false;
float minAvg = 0;
int minC = 0; // count of no. of temps in min Average
int hourC = 0;

const byte arrySize = 60;
float hourAvg[arrySize];
Array<float> hourAvgArray = Array<float>(hourAvg,arrySize);
int nekMin = 99;
float hourMin = 99;
float hourMax = 0;

void setup() {
  pinMode(LEDPin, OUTPUT);
  Serial.begin(115200);
  delay(10);

  Serial.println(F("MQTT Temp"));

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected");
  Serial.println("IP address: "); Serial.println(WiFi.localIP());
 
  Serial.println("Starting UDP");
  Udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(Udp.localPort());
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
  setSyncInterval(3600);
}

void loop() {
  unsigned long mills= millis();
  MQTT_connect();
  digitalWrite(LEDPin, LOW);
  float tmpOW = getOWTemp();
  digitalWrite(LEDPin, HIGH);
  if(tmpOW == 0) return;
  tempOW.publish(tmpOW);
  Serial.print("Digital temp = ");
  Serial.println(tmpOW);
  int thisMin = minute();
  Serial.println(thisMin);
  Serial.println(nekMin);
  if ( thisMin < nekMin ){
    minAvg = minAvg + tmpOW;
    nekMin = thisMin + 1;
    minC ++;
  }else {
    hourAvg[minute()]  = minAvg / minC;
    if(hourAvg[minute()] > 35.5){
      warningS.publish("Running: Over Temp");
      warning.publish(1);
    }else if(hourAvg[minute()] < 32){
      warningS.publish("Running: Door Open");
      warning.publish(-1);
    }else {
      warningS.publish("Running: Normal");
      warning.publish(0);
    }
    minAvg = tmpOW;
    nekMin = thisMin + 1;
    minC = 1;
    hourC ++;
  }
 
  hourMin = min(hourMin, tmpOW);
  hourMax = max(hourMax, tmpOW);
 
  if(hourC >= 60){ //60
    hourC = 0;
    sendH = true;
  }
  if (minute() == 0 && sendH == true){
    tempHAvg.publish(hourAvgArray.getAverage());
    Serial.print("Average over 60 min: ");
    Serial.println(hourAvgArray.getAverage());
    tempHMin.publish(hourMin);
    Serial.print("Min over 60 min: ");
    Serial.println(hourMin);
    tempHMax.publish(hourMax);
    Serial.print("Max over 60 min: ");
    Serial.println(hourMax);
    hourMax = 0;
    hourMin = 99;
    sendH = false;
  } 
  delay(10000 - millis() + mills);
}

float getOWTemp(){
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
 
  if ( !ds.search(addr)) {
//    Serial.println("No more addresses.");
//    Serial.println();
    ds.reset_search();
    delay(250);
    return 0;
  }
 
//  Serial.print("ROM =");
//  for( i = 0; i < 8; i++) {
//    Serial.write(' ');
//    Serial.print(addr[i], HEX);
//  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
//      Serial.println("CRC is not valid!");
      return 0;
  }
//  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
//      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
//      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
//      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
//      Serial.println("Device is not a DS18x20 family device.");
      return 0;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
 
  delay(1000);     // 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("  Data = ");
//  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();

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  return celsius;
}

// ntp functions etc removed



pylon

You don't check the CRC of the transferred scratchpad. Check it a throw away readings where CRC don't match last byte. For debugging print out configuration byte.
If that doesn't help, try setting lower resolution, although I don't think that the problem is there.

BlueEther

OK, thanks.

I was mistaken that the first crc check was for temp but after looking at the code from the example I guess it is a crc on the device ID/address - C (or programming) is not a strong point for me...

So I've added this code:
Code: [Select]
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
// CRC check on temp
  Serial.print(" Read CRC=");
  Serial.print(data[8], HEX);
  Serial.print(" Calc CRC=");
  Serial.println(OneWire::crc8(data, 8), HEX);
  if (OneWire::crc8(data, 8) == data[8]) {
    Serial.println("CRC Match");   
  }else{
    Serial.println("CRC Dont Match"); 
    return 0; 
  } 

I'm not expecting temps below 20 or so (room temp) so a return of 0 singles an error.
I cant test this untill tomorrow on the live system, but seems to work at home.

BlueEther

#7
Nov 25, 2016, 09:15 am Last Edit: Nov 25, 2016, 09:21 am by BlueEther
OK, an update:

Finally got to upload the above change to the esp8266 and it seemed to make little difference (this board has an issue that I often cant  get serial console / com5 to show so debugging is problematic. It always runs [serial] if I use a desktop PSU set at ~5.2v)

Anyway I swapped the PSU to an iPad one as I was having trouble connecting after uploading the new code - low and behold the read temp drops to something more like the real temp and is much more stable. I guess using fully powered and a cap on the power line might solve it on the other PSU.

BlueEther

Update #2:

added a 100nF cap and the extra wire for vcc and now the original charger/psu gives stable temp readings. It will be interesting to see if it is still the case at work where there is much more RF and lots of things on the mains.

Thanks

Charles

MarkT

Excellent, glad its all working now.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Go Up