Spark-dallas-temperature MANUAL mode

When I’m connected to wifi it works fine AKA SYSTEM_MODE(AUTOMATIC); or SYSTEM_MODE(SEMI_AUTOMATIC);, with wifi.on(); without wifi it doesn’t return data… Any ideas?

Considering the description is rather vague, seeing some code would be nice.

Hello,

Sorry I’m new to this, but here is a example… I’ve been trying to chip away at the issue, and I think it has to do more with the timing of things than anything, since If I use a timer it doesn’t seem to work, but if I use it in the main loop it’s fine. Any idea why?:

// Only include One of the following depending on your environment!
#include "OneWire/OneWire.h"  // Use this include for the Web IDE:
// #include "OneWire.h" // Use this include for Particle Dev where everything is in one directory.


// Comment this out for normal operation
SYSTEM_MODE(MANUAL);  // skip connecting to the cloud for (Electron) testing

OneWire ds = OneWire(D4);  // 1-wire signal on pin D4

unsigned long lastUpdate = 0;

Timer get_weather_timer(1000, getSoilTemp);


void setup() {
  Serial.begin(9600);
  get_weather_timer.start();
}



void loop(void) {
//  getSoilTemp()
}




void getSoilTemp()
{
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }

  // The order is changed a bit in this example
  // first the returned address is printed

  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  // second the CRC is checked, on fail,
  // print error and just return to try again

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();

  // we have a good address at this point
  // what kind of chip do we have?
  // we will set a type_s value for known types or just return

  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS1820/DS18S20");
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    case 0x26:
      Serial.println("  Chip = DS2438");
      type_s = 2;
      break;
    default:
      Serial.println("Unknown device type.");
      return;
  }

  // this device has temp so let's read it

  ds.reset();               // first clear the 1-wire bus
  ds.select(addr);          // now select the device we just found
  // 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)

  // just wait a second while the conversion takes place
  // different chips have different conversion times, check the specs, 1 sec is worse case + 250ms
  // you could also communicate with other devices if you like but you would need
  // to already know their address to select them.

  delay(1000);     // maybe 750ms is enough, maybe not, wait 1 sec for conversion

  // we might do a ds.depower() (parasite) here, but the reset will take care of it.

  // first make sure current values are in the scratch pad

  present = ds.reset();
  ds.select(addr);
  ds.write(0xB8,0);         // Recall Memory 0
  ds.write(0x00,0);         // Recall Memory 0

  // now read the scratch pad

  present = ds.reset();
  ds.select(addr);
  ds.write(0xBE,0);         // Read Scratchpad
  if (type_s == 2) {
    ds.write(0x00,0);       // The DS2438 needs a page# to read
  }

  // transfer and print the values

  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 == 2) raw = (data[2] << 8) | data[1];
  byte cfg = (data[4] & 0x60);

  switch (type_s) {
    case 1:
      raw = raw << 3; // 9 bit resolution default
      if (data[7] == 0x10) {
        // "count remain" gives full 12 bit resolution
        raw = (raw & 0xFFF0) + 12 - data[6];
      }
      celsius = (float)raw * 0.0625;
      break;
    case 0:
      // 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
      if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
      if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
      // default is 12 bit resolution, 750 ms conversion time
      celsius = (float)raw * 0.0625;
      break;

    case 2:
      data[1] = (data[1] >> 3) & 0x1f;
      if (data[2] > 127) {
        celsius = (float)data[2] - ((float)data[1] * .03125);
      }else{
        celsius = (float)data[2] + ((float)data[1] * .03125);
      }
  }

  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");

}

Thank you in advance!

@magnum129

Just an observation, but the code for getting the temperature looks way too complex. What model of sensor are you using?

You need to include the spark-dallas-temperature library in your code.

To get the temperature in Celsius you can just do:

ds.requestTemperatures();
float celsius = ds.getTempCByIndex(0);

Also, you should probably change:

OneWire ds = OneWire(D4);  // 1-wire signal on pin D4

to

DallasTemperature ds(new OneWire(D4));

getSoilTemp should look like this:

void getSoilTemp()
{
  ds.requestTemperatures();
  float celsius = ds.getTempCByIndex(0);
  float fahrenheit = ds.getTempFByIndex(0);
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
}

Also, you can substitute a timer by putting this in your loop():

if (millis()/1000 % 1 == 0) // Every second
{
  getSoilTemp();
}

I'm not sure what's wrong with your code exactly, but this example works ok for me. What happens if you increase your Timer interval to 5000?


SYSTEM_MODE(MANUAL);

Timer ledTimer(1000, toggleD7);

void toggleD7() {
    digitalWrite(D7, !digitalRead(D7));
}

void setup() {
    pinMode(D7, OUTPUT);
    ledTimer.start();
}

void loop() {
}

Even though the title seems to suggest they @magnum129 is using the Spark-Dallas-Temperature library, their code only seems to use the OneWire library and default DS18B20 example wrapped up in a Timer.

This is exactly the same code abstracted by the Spark-Dallas-Temperature library (which oddly enough has no examples shown yet has 2000+ uses).

I would recommend the Timer over using modulus code since when using modulus it is only true on every even multiple of 1000. Therefor you must call at least every 1ms for it to be responsive. If you are late there is no forgiveness.

What about the example in the readme for the library?

Or these examples? https://github.com/tomdeboer/SparkCoreDallasTemperature/tree/master/firmware/examples

They are written for Arduino but they should work.

Right, but you have to poke about to discover that repo and the examples. 2400 people did that? So weird. I think those examples would be included if they were not .pde files, but .ino instead.

There are actually three independent libraries in Particle Build

  • Spark-Dallas-Temperature
  • DS18B20
  • DS18X20

The other two come with samples :wink:

Since the first library has gone a bit stale (open issues and PRs not addressed) it might be good if Particle could take ownership of that lib and open the repo for registered contributors to keep it fresh :wink:
Especially with Libraries 2.0 round the corner.

Don't forget the official OneWire library which has a DS18B20 demo example :smile:

1 Like

I was using the spark-dallas lib, but wanted to test without it to see if it was the cause.

I ended up moving the dallas temp stuff to the main loop and can just pull the value when using the timer. Thank you all for your help!

Not sure how you’re calling things, but you should treat a timer as an interrupt. Keep it as short as possible (e.g. Don’t use library functions in there). Set a flag in the timer and check for that in the loop, then do whatever is needed.

1 Like

I just did this instead. I like using the timer, since it’s the most reliable method. Thank you for the suggestion and the help!