Pages: [1] 2 3   Go Down
Author Topic: DS18B20 750ms delay bypass?  (Read 6228 times)
0 Members and 1 Guest are viewing this topic.
Gurnee, IL
Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have 5 sensors oneWire DS18B20's that work just fine, but after some research I found that the reason my menu buttons are sluggish is that there is a 750ms delay for conversion as discussed at the bottom of the first page of this thread:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1263821196/0

So I see the code and I kinda can follow it, but I'm a bit intimidated as to how to shoe horn it into my sketch. His code uses a number of syntax that I'm not familiar with.

Is there a newer/better/streamlined method for not holding up the loop while it converts the temps for 750ms?

I'm kind of guessing not, but I figured I ask before spending the next week trying to figure out how to make it work in my 1600+ lines of code... smiley-sad-blue
« Last Edit: May 22, 2011, 02:23:29 pm by Molehs » Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 71
Posts: 3536
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The technique I use is as follows. The main loop of the sketch has a section that gets executed once per second. It calls a function to read the temperature from the DS18B20. This function will start the temperature conversion on one call, then read the temperature on the next call and store the result in a global variable. Actually the function watches the time from a RTC, and starts the conversion when the seconds reach a certain value. So it only reads the sensor once per minute, but this would be easy to change for more (or less) frequent readings.

I'm using the OneWire library from http://www.pjrc.com/teensy/td_libs_OneWire.html
« Last Edit: May 21, 2011, 10:51:21 pm by Jack Christensen » Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Gurnee, IL
Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Would you mind sharing your code for that section? If I had a 2nd example of how to code that it would be easier for me to decipher. Thanks.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


For the 3.7.0 version of the - http://www.milesburton.com/Dallas_Temperature_Control_Library - I have introduced the asynchronuous reading of the DS18B20 family. Although officially still in beta I've not encountered any failure with the code yet. There are sample sketches showing how to use it.

Rob

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Gurnee, IL
Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So when it says "you can choose to manage the delay in your own code " does that mean setting the resolution? And if I have mine set to 9 for all 5 sensors it should take a very small am mount of time to convert the temps, i.e. less than 100ms according to the WaitingForConversion2 sketch serial print out?

This seems to work for the most part. Basically it would seem that at resolution I now have a 10% chance of hitting a button during the conversion. Does that sound about right?

Not quite the perfect solution but it does make it a lot more responsive than it was.

I'd still be interested if there was less codely way of using the scratchpad to effectively elimination the delay/lag, but for now I'm happy.

Thanks for the help guys.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The DS18S20 has a fixed resolution of 9 bits, so setting the resolution won't help. The B series can be set from 9-12 bit.

In  WaitingForConversion2.pde first a conversion request is send to the DS18B20, the sketch continues while the temp sensor does the conversion.
In the sketch a timeflag is set when thelast Request was done and the needed delay is calculated.

Code:

  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  delayInMillis = 750 / (1 << (12 - resolution));
  lastTempRequest = millis();

In loop() it is checked if this delayInMillis miliseconds has passed before the temperature is fetched from the sensors. In the meanwhile one can do other things. In the example it increases just a counter. You could check if your Button is pressed and hold that in a state variable.

Quote
I'd still be interested if there was less codely way of using the scratchpad to effectively elimination the delay/lag, but for now I'm happy.
The DS18 series need conversion time (There is an ADC within the sensor that need to stabilize) and the asynchronuous method gives you most degrees of freedom.

The sketch below fetches the temperature continuously in the async way so it takes relatively little time. When the button is pressed there is allways an actual temperature available.
Code:
//
// Sample of using Async reading of Dallas Temperature Sensors
//
#include <OneWire.h>
#include <DallasTemperature.h>

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

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

DeviceAddress tempDeviceAddress;

int  resolution = 12;
unsigned long lastTempRequest = 0;
int  delayInMillis = 0;
float temperature = 0.0;
int  idle = 0;

// button
#define BUTTONPIN 4


//
// SETUP
//
void setup(void)
{
  Serial.begin(115200);
  Serial.println("Dallas Temperature Control Library - Async Demo");
  Serial.print("Library Version: ");
  Serial.println(DALLASTEMPLIBVERSION);
  Serial.println("\n");

  // initialization
  sensors.begin();
  sensors.getAddress(tempDeviceAddress, 0);
  sensors.setResolution(tempDeviceAddress, resolution);
 
  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  delayInMillis = 750 / (1 << (12 - resolution));
  lastTempRequest = millis();
 
  pinMode(13, OUTPUT);
}

void loop(void)
{
  // this part keeps the var temperature up to date as possible.
  if (millis() - lastTempRequest >= delayInMillis) // waited long enough??
  {
    digitalWrite(13, LOW);
    temperature = sensors.getTempCByIndex(0);
    sensors.requestTemperatures();
    lastTempRequest = millis();
  }
  digitalWrite(13, HIGH);
 
  if (digitalRead(BUTTONPIN) == LOW)
  {
    Serial.println(temperature);
  }
}
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Gurnee, IL
Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My mistake I have DS18B20s. I basically drag and dropped your code in and it does seem to work very well, short of it is only pulling the first temp. The parasitic temps are not returning proper values.

My sketch is constantly displaying the current temps and the buttons change the pages of the menu. Previously the menu buttons would fail to do anything, assuming due to the conversion time, but now buttons work every time. So that is really good, just need to tweak it so that the other temps are displayed properly.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


make temperature an array with 5 elements and fetch all 5 of them in a for loop()

Code:
  // this part keeps the var temperature up to date as possible.
  if (millis() - lastTempRequest >= delayInMillis) // waited long enough??
  {
    digitalWrite(13, LOW);
    for (int i=0; i< 5; i++)  temperature[i] = sensors.getTempCByIndex(i);  // <<<<<<<<<<<<<<<<<<<<
    sensors.requestTemperatures();
    lastTempRequest = millis();
  }
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Gurnee, IL
Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why, originally did I only need have this "sensors.requestTemperatures();" once in the loop and the all the temps were pulled just fine. But now that it's part of the IF statement it only pulls the first one? Placing the values in an array doesn't really work for me because all of my code is based on each address already having a specific variable name.

If I comment out the getTempCByIndex line, either with the for loop or not, it still only populates the first probes temp. It's almost as if the way it's running it ignores all the parasites. It knows if they are plugged in because I get 185 F if they are in and -196.9 F if they are not...
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 71
Posts: 3536
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Would you mind sharing your code for that section? If I had a 2nd example of how to code that it would be easier for me to decipher.

I've copied-and-pasted the pertinent code from a much larger sketch, so this is not guaranteed to run verbatim, but should give the general idea. Note that I am using the DS18B20, not DS18S20. (Too easy to miss that!) HTH.

Code:
#include <OneWire.h>           //http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <Wire.h>              //http://arduino.cc/en/Reference/Libraries
#include <Time.h>              //http://www.arduino.cc/playground/Code/Time
#include "DS1307RTC.h"         //http://www.arduino.cc/playground/Code/Time (declares the RTC variable)

time_t utcNow, utcLast;   //RTC is set to UTC
int utcH, utcM, utcS;   //utc time parts
OneWire  ds(dsPin);            //DS18B20 temperature sensor
int tF10;                      //temperature from DS18B20    

...

void loop(void) {
    utcNow = now();
    if (utcNow != utcLast) {           //once through here per second ought to be enough
        utcLast = utcNow;
        utcH = hour(utcNow);
        utcM = minute(utcNow);
        utcS = second(utcNow);
        readTemperature();
}

/*-------------------------------------------------------------*
 * Start the temperature conversion at second 55, read it back *
 * at second 56.                                               *
 *-------------------------------------------------------------*/
int readTemperature() {
    byte dsData[12];

    if (utcS == 55) {
        ds.reset();
        ds.skip();
        ds.write(0x44);        //start temperature conversion
    }

    if (utcS == 56) {
        ds.reset();
        ds.skip();
        ds.write(0xBE);        //read scratchpad

        for ( int i=0; i<9; i++) {    //read 9 bytes
            dsData[i] = ds.read();
        }
        if (OneWire::crc8( dsData, 8) == dsData[8]) {
            tF10 = tempF_DS18B20(dsData[1], dsData[0]);
            haveTemperature = true;
        }
        else {
            Serial.print(" CRC ERR");
        }
    }
}

int tempF_DS18B20(byte tempMSB, byte tempLSB) {
    /* Convert 12-bit °C temp from DS18B20 to an integer which is °F * 10    *
     * Jack Christensen 30Jan2011                                            */

    int tC16;        //16 times the temperature in deg C (DS18B20 resolution is 1/16 °C)
    int tF160;       //160 times the temp in deg F (but without the 32 deg offset)
    int tF10;        //10 times the temp in deg F

    tC16 = (tempMSB << 8) + tempLSB;
    tF160 = tC16 * 18;
    tF10 = tF160 / 16;
    if (tF160 % 16 >= 8) tF10++;        //round up to the next tenth if needed
    tF10 = tF10 + 320;                  //add in the offset (*10)
    return tF10;
}
« Last Edit: May 22, 2011, 02:13:48 pm by Jack Christensen » Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


    if (utcNow != utcLast) {           //once through here per second ought to be enough

That should be enough but this code is no guarantee it will be called every second. Suppose that the executing part of the if statement takes 3 seconds to execute then the if statement will be true every time its called, but every 3 seconds two will be missed.

That said if you check the readTemperature() function it does a hard check it utcS == 55 or 56, but maybe these two values are skipped ... Don't know but can be.
Get the point?

I changed the readTemperature code to cope with skipping seconds.

(code not tested/compiled, just edited)
Code:
void readTemperature()
{
    static boolean tempRequested == false;

    byte dsData[12];

    if (utcS >= 55)     // notice the  >=  iso  ==
    {
        ds.reset();
        ds.skip();
        ds.write(0x44);           
        tempRequested = true;
        return;      // <<<<<<<<<<<<<<<<<<<<<< we're ready  so return.
    }

    if (utcS >= 56 && tempRequested == true)
   {
        ds.reset();
        ds.skip();
        ds.write(0xBE);        //read scratchpad
        tempRequested == false;  // reset flag for next iteration

        for ( int i=0; i<9; i++) dsData[i] = ds.read();

        if (OneWire::crc8( dsData, 8) == dsData[8])
        {
            tF10 = tempF_DS18B20(dsData[1], dsData[0]);
            haveTemperature = true;
        }
        else {
            Serial.print(" CRC ERR");
        }
    }
}

This code is not failsafe yet, A better approach would be to separate the two activities, request a temperature conversion and fetch the temperature. Check if there was a reqwuest at least a second ago. Could be something like ...

Code:
void loop(void)
{
    utcNow = now();
    if (utcNow != utcLast)
    {         
        utcLast = utcNow;
        utcH = hour(utcNow);
        utcM = minute(utcNow);
        utcS = second(utcNow);
        if (utCS >= 55) requestTemperature();
        if (utcS >= 56) readTemperature();
}

boolean tempRequested = false;
long timeRequestTime = 0;

void requestTemperature()
{
    ds.reset();
    ds.skip();
    ds.write(0x44);        //start temperature conversion
    tempRequested = true;
    timeRequestTime = utcLast;
}


void readTemperature()
{
   if (tempRequested == false) return;  // only if temp was requested
   utcNow = now();
   if (utcNow - timeRequestTime <  1)  return;  // at least a second ago

    byte dsData[12];
    ds.reset();
    ds.skip();
    ds.write(0xBE);        //read scratchpad
    tempRequested = false;

    for ( int i=0; i<9; i++) dsData[i] = ds.read();

    if (OneWire::crc8( dsData, 8) == dsData[8])
    {
        tF10 = tempF_DS18B20(dsData[1], dsData[0]);
        haveTemperature = true;
    }
    else
    {
        Serial.print(" CRC ERR");
    }
}

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 71
Posts: 3536
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That should be enough but this code is no guarantee it will be called every second. Suppose that the executing part of the if statement takes 3 seconds to execute then the if statement will be true every time its called, but every 3 seconds two will be missed.

Rob, that is, of course, quite correct. Thanks for pointing it out. In the case of my sketch, nothing comes close to taking even a second, so I felt the code was safe for my purposes (and there are actually several other things going on in the loop that I omitted as they had no bearing on the central question here).

Moral of the story: Assumptions that may be reasonable for one application may be completely unreasonable for the next!
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Assumptions that may be reasonable for one application may be completely unreasonable for the next!
A good lesson, in fact it is even worse,

Assumptions for one application at a given time/place my even be incorrect later/somewhere else.


Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
The Netherlands
Offline Offline
Sr. Member
*****
Karma: 1
Posts: 287
don't panic...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Small note on the conversion time. You can assume the max. delay from the datasheet or poll the data line to the sensor. It will go high when conversion is finished.
Something like;
Code:
while (ds.read() == 0) { // wait for completion }

regards,

Jeroen.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jeroen,

Read that too before but never tried in real life. Do you know the following?

Suppose you have multiple T sensors, same resolution (or not -> bonus points smiley
When will the line go high, (A) when the first sensor is ready or (B) when they are all ready or (C) something else?

if A then the signal cannot be trusted to read all sensors.
B would be very useable as one could test, fail -> continue, succeed -> getTemp()
C ??

Rob
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1] 2 3   Go Up
Jump to: