How can i efficiently read DS18B20 (onewire)

Hi! I have been working on a project for quite some time now. It contains a PCB with a Arduino Nano, current sensors, ACD's RS422 networking, etc. The PCB has over 200 components and is already produced. It also features a external temperature sensor. I picked a DS18B20 as i figured its a cheap and accurate sensor thats easy to program.

Until today i never bothered to add code for this sensor as i thought it would be very simple, but i really should have checked better i'm afraid. Its reasonably easy to set up with some sample code and its working fine. To be honest i have a little trouble really understanding the example code as i'm not great with programming.

I have been reading a lot about onewire and the DS18B20, but i have trouble understanding its timing. Apparently it needs a huge amount of time to convert something which can take up 750ms. There is no way my program van wait that long. Currently my program looks like something like this:

Loop:

  • Check RX buffer for new data, and do some stuff
  • Check if timer has passed (every 0,25s), if so run function A (takes approx 16ms)
  • Check if timer has passed (every 1s) if so run function B (takes approx 1ms)
  • etc...
  • Check if timer has passed (every 2s) if so run function with DS18B20 code
  • Send all variables over serial
    end of loop.

So it i need to give the DS18B20 function more than a few ms to complete im slowing down my look by a huge amount. It will read the serial way to late and process messages to switch relays, much to late!

Why does the DS18B20 needs so much time and how can i make it faster? I have found something about using the DallasTemperature library which has a function to speed up the process, but i dont understand how to use it, and i also try to prevent using additional librarys.

While i'm in the function that is running the onewire code, the rest of the program waits, but if i leave the function there is no way to be ready to receive the data from the sensor.

Can you guys help with this, or do i really need another sensor?

With the ds18b20 you issue the command to start a conversation and depending on resolution set, a while later the result is given .
A lot of libraries ( eg Dallas) block whilst this is happening .
If you google something like “ Arduino fast ds18b20 no delay “ or similar you will find examples of how to initiate a conversation, continue your program and go back later to get the result using “millis” .
Has the advantage of not needing the Dallas library too .

You can also get the required info from data sheets

Look at the library - you can learn from its code even if you don't want to use the whole thing.

Getting the temp from the sensor has two parts. First you tell the sensor (or all of them) to get the temperature. When it has done so, you can read it. The first part can take 750mS, but you can get on with other things while that time passes.

You can use millis to keep track of the time and avoid reading the temperature from the sensor until enough time has passed or you can ask the sensor if it is done.

Personally, I just use the library. YMMV.

hammy:
A lot of libraries ( eg Dallas) block whilst this is happening .

The Dallas library can be run in non-blocking mode. If you actually look at the source code, you'll see how it works. You initiate the temperature conversion and come back later to read the results. How much later depends on the resolution you've selected.

This sketch only slows the loop() long enough to do transfers, math and print every 800 milliseconds, it does NOT WAIT 800 ms for the conversion..
The readout is ℃_ 1/16℃ in HEX.

#include <OneWire.h>
OneWire  ds(7);  // on pin 7 (a 4.7K resistor is necessary)

unsigned long start;
int end = 800;

byte addr[8],
     data[12],
     i;

void setup()
{
  Serial.begin(9600);
  Serial.println("\n"__FILE__"\n");
  pinMode(LED_BUILTIN,OUTPUT); // <<<<< NEW
  ds.search(addr);
}
void loop()
{
  if (millis() - start > end)
  {
    start += end;
    int val, newVal;
    static byte cntr = 0;
    ds.reset();
    ds.select(addr);
    ds.write(0xBE);         // Read Scratchpad
    for ( i = 0; i < 9; i++)   // we need 9 bytes, read conversion results here
      data[i] = ds.read();    // 800 ms after conversion start
    newVal = data[1] << 8 | data[0];
    val = antiDither(newVal);
    if (++cntr > 15)
    {
      cntr = 0;
      Serial.println("tempC");
    }
    Serial.print(val >> 4);
    Serial.print("_");
    Serial.println(val & 0x000F, HEX);
    ds.reset();
    ds.select(addr);
    ds.write(0x44); // start conversion
  }
  // do other programming here
  digitalWrite(LED_BUILTIN,bitRead(millis(),5)); // <<<<< NEW
  //...
  //......
  //.........
}

int antiDither(int newVal) // prevents +1 <-> -1 dither
{
  static int val = 0, oldVal = 0;
  if (newVal != val && newVal != oldVal)
  {
    oldVal = val;
    val = newVal;
  }
  return val;
}

EDIT: Added a LED blinking at 31Hz (every 32 millis) so you can see the blinking does not pause for the temperature read and display, it's all done between blinks.

superkris:

  • Check if timer has passed (every 1s)

In that case, you don't have a problem. This implies a one second loop in your code, and any number of DS18B20s can do what you want them to do in that time - using the standard libraries.

You can run the sensors faster, but at lower resolution. If you really do need to go any faster, you are probably using the wrong sensors.

Every 750 milliseconds, read the temperature from the scratchpad and request a new conversion.