Pages: 1 [2] 3   Go Down
Author Topic: DS18B20 750ms delay bypass?  (Read 8176 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
The Netherlands
Offline Offline
Sr. Member
*****
Karma: 1
Posts: 287
don't panic...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What understand from the datasheet (and reality so it seems, it works for me smiley ) is that a sensor stops pulling the line low when finished converting. Only the last sensor that is finished will let the line go up because of the pull up resistor. (never tried parasitic powering)

small part of my code:
Code:
// tell all sensors on bus to convert temperature and wait until done (NOT PARASITIC POWERED)
void convertTempAll()         
{       
  ds.reset();                      // reset bus
  ds.skip();                        // broadcast to all sensors
  ds.write(0x44,0);             // start conversion
  while (ds.read() == 0) {  }  // wait for conversion end.  ( ~600 milliS on average at room temperature)
}

After this i read the sensors individually to get the actual data (no conversions in between readings). Especially useful as the conversion time isn't (very) dependent on number of sensors any more.

Regards,

Jeroen.
Logged

Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 217
Posts: 13742
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
( ~600 milliS on average at room temperature)
That's interesting, that is 150 millis == 20% faster response. Currently no duino free to test smiley-sad  => todo list .
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

That is in my room, in my situation, with 7 or so sensors, with my code etc. Your mileage may vary.

Jeroen.
Logged

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

OK, but it is probably allways faster than waiting the fixed 750 millis which is staed in the datasheet, I assume the makers of the DS18* have specified a save margin of 5-20%.

regards,
Rob
Logged

Rob Tillaart

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

USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 90
I’m no expert, but I play one on the Internet…
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the 750ms delay is only needed when you are running in parasite power mode, since you have to give the sensor time to "steal" power from the DQ line and charge up enough juice to perform the conversion.

From the Maxim Datasheet (http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf):
Quote
CONVERT T [44h]
This command initiates a single temperature conversion. Following the conversion, the resulting thermal data is stored in the 2-byte temperature register in the scratchpad memory and the DS18B20 returns to its low-power idle state.  If the device is being used in parasite power mode, within 10µs (max) after this command is issued the master must enable a strong pullup on the  1-Wire  bus for the duration of the conversion (tCONV) as described in the Powering the DS18B20 section. If the DS18B20 is powered by an external supply, the master can issue read time slots after the Convert T command and the DS18B20 will respond by transmitting a 0 while the temperature conversion is in progress and a 1 when the conversion is done. In parasite power mode this notification technique cannot be used since the bus is pulled high by the strong pullup during the conversion.

In the code I use for reading DS18B20 sensors without parasite power I have either 100ms or zero delay between issuing the CONVERT T [44h] write to the scratchpad then reading the results of the conversion and both seem to work fine. Keep in mind I am cycling through the sensors found from a "search" request one at a time and reading each one individually.  It seems the time it takes my Arduino to issue the reset to the 1-Wire bus then "select" the particular sensor it is working with so it can then read the temp from the scratchpad is enough time for the DS18B20 to finish computing the temperature.

If you like just keep lowering your delay to zero and stop when it doesn't work anymore - you can't really break it. In my experience 100ms should be more than enough time if you don't feel comfortable with zero delay.

FYI - In the code I use for reading temperature and voltage on the ADC of a DS2438 I do wait 100ms each for temp/voltage conversion, but I haven't had a need to try to shorten that yet.


Hope it helps,
willnue
Logged

Lancashire, UK
Offline Offline
Edison Member
*
Karma: 9
Posts: 1991
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You don't need to use delay at all, just because the temperature sensor wants 750 ms doesn't mean you have to stop the microcontoller to give it what it wants. Several of my sketches contain this line :

Code:
#include <DallasTemperature.h> // this is stephen's modified version
// added requestTemperaturesnodelay() function based on similar existing function
// but with no delays

I appended this this code to DallasTemperature.cpp in the library and called it with requestTemperaturesnodelay in the sketch and allow for the timing in the sketch (hint : blink without delay).

Code:
// sends command for all devices on the bus to perform a temperature without any delays built in (this must be allowed for in the sketch)
void DallasTemperature::requestTemperaturesnodelay(void)
{
  _wire->reset();
  _wire->skip();
  _wire->write(STARTCONVO, parasite);
}

every second it calls the the dallastemp.getTempCByIndex function immediately followed by requestTemperaturesnodelay so its ready for next time round, the initial request is done in setup, the DS1820 gets a whole second for its conversion, and the sketch doesn't stop whilst its doing it.
« Last Edit: May 24, 2011, 03:35:18 am by pluggy » Logged


USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 90
I’m no expert, but I play one on the Internet…
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I agree that managing tasks outside the confines of the main loop is a more robust solution, especially when you require user interaction. I was just trying to give a simple solution.

FYI - Not sure how you are determining 1 second has passed, but if you are counting millis() you might want to check into millis() rollover handling.

Questions about millis():
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200662708

willnue
Logged

Portugal
Offline Offline
God Member
*****
Karma: 6
Posts: 962
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

after 52 days it will overflow, is there a problem with that? or will your app run for 52 days or more?
Logged

USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 90
I’m no expert, but I play one on the Internet…
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Senso,
    I always thought it was a little over 9 hours, but I see now it is 50 days. Either way, you just need to be mindful that it will occur if your application requires long run times...

willnue
Logged

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

I think I'm a bit lost with all of this. I'll lay out what I've got and perhaps I can get a more tailored solution. This is what I have running right now.

I've assigned a name to each sensor:
Code:
DeviceAddress  TankTemp = { 0x28, 0xD3, 0x05, 0xB0, 0x02, 0x00, 0x00, 0x8F };
DeviceAddress SumpTemp = { 0x28, 0xE7, 0x08, 0xB0, 0x02, 0x00, 0x00, 0x52 };
DeviceAddress BaseTemp = { 0x28, 0xE0, 0xDE, 0xAF, 0x02, 0x00, 0x00, 0xB7 };
DeviceAddress UpTemp = { 0x28, 0x4A, 0xD3, 0xAF, 0x02, 0x00, 0x00, 0xC8 };
DeviceAddress LEDTemp = { 0x28, 0x2B, 0xF6, 0xAF, 0x02, 0x00, 0x00, 0x16 };

In the setup:
Code:
  sensors.begin();
  sensors.setResolution(SumpTemp, 10);
  sensors.setResolution(TankTemp, 10);
  sensors.setResolution(UpTemp, 10);
  sensors.setResolution(BaseTemp, 10);
  sensors.setResolution(LEDTemp, 10);
in the loop:
Code:
sensors.requestTemperatures();

Example of a pulled temp:
Code:
DallasTemperature::toFahrenheit(sensors.getTempC(TankTemp)

I have 5 of those temps/sensors (all wired up parasitically) on my main screen that I'd like updated about once per second. As well I have heaters/fans/chillers triggered by those temps. All of that works. But due to the delay I get lag trying to navigate screen/menus with momentary buttons with  "uniquePress".

It seems like it should be something fairly simple to suit my needs, but I just don't understand enough to get it coded. I appreciate the help you all have tried to offer so far, but I need just a little more.
Logged

Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 217
Posts: 13742
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 dallas temperature library comes with an example with multiple (2) sensors. Please check that one, copy it and adapt to 3 4 5 sensors

Furthermore you might check the use of arrays - http://www.arduino.cc/en/Reference/Array -

Code:
#define DASIZE 5
#define TANKTEMP 0
#define SUMPTEMP 1
etc

DeviceAddress DA[DASIZE ] = {
  { 0x28, 0xD3, 0x05, 0xB0, 0x02, 0x00, 0x00, 0x8F },
  { 0x28, 0xE7, 0x08, 0xB0, 0x02, 0x00, 0x00, 0x52 },
  { 0x28, 0xE0, 0xDE, 0xAF, 0x02, 0x00, 0x00, 0xB7 },
  { 0x28, 0x4A, 0xD3, 0xAF, 0x02, 0x00, 0x00, 0xC8 },
  { 0x28, 0x2B, 0xF6, 0xAF, 0x02, 0x00, 0x00, 0x16 }
}
....

sensors.begin();
for (int i=0; i< DASIZE. i++)   sensors.setResolution(DA[i], 10);
...

sensors.requestTemperatures();
for (int i=0; i< DASIZE. i++)  Serial.println(sensors.getTempC(DA[i]));
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


The dallas temperature library comes with an example with multiple (2) sensors. Please check that one, copy it and adapt to 3 4 5 sensors
Actually that is basically what I have which is where I'm stuck at. It's multiple sensors are stuck with the delay.
[/quote]
Furthermore you might check the use of arrays - http://www.arduino.cc/en/Reference/Array -

Code:
#define DASIZE 5
#define TANKTEMP 0
#define SUMPTEMP 1
etc

DeviceAddress DA[DASIZE ] = {
  { 0x28, 0xD3, 0x05, 0xB0, 0x02, 0x00, 0x00, 0x8F },
  { 0x28, 0xE7, 0x08, 0xB0, 0x02, 0x00, 0x00, 0x52 },
  { 0x28, 0xE0, 0xDE, 0xAF, 0x02, 0x00, 0x00, 0xB7 },
  { 0x28, 0x4A, 0xD3, 0xAF, 0x02, 0x00, 0x00, 0xC8 },
  { 0x28, 0x2B, 0xF6, 0xAF, 0x02, 0x00, 0x00, 0x16 }
}
....

sensors.begin();
for (int i=0; i< DASIZE. i++)   sensors.setResolution(DA[i], 10);
...

sensors.requestTemperatures();
for (int i=0; i< DASIZE. i++)  Serial.println(sensors.getTempC(DA[i]));

[/quote]

Something must be off or I'm messing up. But I used your code with changes to DA[TankTemp], because otherwise the array wouldn't have been acting in the rest of the code, instead of TankTemp and I got it to compile just fine. But it still only displays the first temp.

I use the "sensors.requestTemperaturesnodelay();" to pull the temps. Sorry, I could have sworn I had that in my last post but I can see I didn't. Not sure if it makes a difference. But I've been using it for a couple days as it makes the screen/menu navigation work very well.

As well I tried several variations of things that looked like they 'should' maybe work and compile fine but still only return the first sensors value. One was:
Code:
#define TankTemp DA[0]
#define SumpTemp DA[1]
...
But I really don't have a clue what I'm doing...

What really bothers me is that no matter what I try it works, but only for the first value...(I'd feel better if some variations failed...lol)
Logged

USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 90
I’m no expert, but I play one on the Internet…
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have only used the OneWire library before so I wasn't that familiar with the DallasTemperature Library, but I did a little looking into it and unfortunately I don't think you are going to be able to do what you want since the Delay()s are built into the library and not exposed to your main program:

From DallasTemperature.cpp file you can see the delays are performed in the Case statements within the requestTemperaturesByAddress function depending on the resolution of the sensor that was found:
Code:
// sends command for one device to perform a temperature by address
// returns FALSE if device is disconnected
// returns TRUE  otherwise
bool DallasTemperature::requestTemperaturesByAddress(uint8_t* deviceAddress)
{
  // check device
  ScratchPad scratchPad;
  if (false == isConnected(deviceAddress, scratchPad)) return false;
  
  _wire->reset();
  _wire->select(deviceAddress);
  _wire->write(STARTCONVO, parasite);
  
  // ASYNC mode?
  if (false == waitForConversion) return true;  
  
  if (deviceAddress[0] == DS18S20MODEL)
  {
    delay(750);  // max value found in datasheet
return true;
  }
  // other models
  switch(scratchPad[CONFIGURATION])
  {
    case TEMP_9_BIT:
      delay(94);
      break;
    case TEMP_10_BIT:
      delay(188);
      break;
    case TEMP_11_BIT:
      delay(375);
      break;
    case TEMP_12_BIT:
    default:
      delay(750);
      break;
  }
  return true;
}

Since you can only call the requestTemperaturesByAddress function you can't control the delay. You might think to edit the library directly, but I would caution against that since it would then no longer match the original and you wouldn't be able to update it etc...

I'll see if I can work a sample using only the OneWire library that does what you are looking for. Using the OneWire library by itself is not that complicated and will give you much more control over the steps.

willnue
Logged

USA
Offline Offline
Jr. Member
**
Karma: 0
Posts: 90
I’m no expert, but I play one on the Internet…
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, I made a sample sketch for you to try. The sketch is based on the example in the Arduino Playground: http://www.arduino.cc/playground/Learning/OneWire

I am also using the OneWire V2 Library from PJRC:
http://www.pjrc.com/teensy/td_libs_OneWire.html

To test I would do the following:

1. Add the OneWire V2 library to your Arduino library folder
2. Paste the code below into a new sketch
3. Update the OneWire ds(10); line to match the pin your data line is connected to or connect your data line to pin #10.
4. Upload the sketch & check the serial output window
5. You should see all your sensors displayed on a seperate line.
6. Edit the code again and uncomment the following line
Code:
//Serial.println("Checking for button presses...");
7. Upload the edited sketch & check the serial output window
8. You should now see "Checking for button presses..." mixed in between the sensor info.

Code:
#include <OneWire.h>

/* DS18S20 Temperature chip i/o */

OneWire  ds(10);  // 1-Wire Data line connected to pin 10

int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
byte present = 0;
byte data[12];
byte addr[8];
boolean TempConvertInProg = false;
long ConvertDuration = 750; // ms to wait for conversion
long ConvertStart; //Time when convert was started

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

void loop(void) {
 
  if (TempConvertInProg == false) {
    //Search for sensors
    if ( !ds.search(addr)) {
      //No Sensor found
      Serial.print("No more addresses.\n");
      ds.reset_search();
      delay(250);
      return;
    }
    else  {
      //Serial.print("Found a sensor!");
      TempConvertInProg = true;
      //Kick off temp conversion
      startTempConvert();
      //Mark the start time;
      ConvertStart = millis();
    }
  }
  else {
    //Check to see if it is time to read the sensor
    if (millis() >= (ConvertStart + ConvertDuration)){
      // Enough time has passed
      //Read temp from sensor
      readTemp();
      TempConvertInProg = false;
    }
  }
 
  //Code placed here will execute on every pass of the loop regardless
  //of whether or not the sensor temp conversion is in progress or not
 
  //Uncomment the line below to see when the button presses could be checked
  //Serial.println("Checking for button presses...");
 
}


// function to kick off the temperature conversion for selected sensor
void startTempConvert()
{
  byte i;
 
  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.print("CRC is not valid!\n");
      return;
  }
 
//    if ( addr[0] != 0x10) {
//        Serial.print("Device is not a DS18S20 family device.\n");
//        return;
//    }
   
    if ( addr[0] != 0x28) {
        Serial.print("Device is not a DS18B20 family device.\n");
        return;
    }


  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end
}


// function to read the temperature from the selected sensor
void readTemp()
{
  byte i;

 
  present = ds.reset();
  ds.select(addr);   
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("P=");
  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();
 
  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;

  Serial.print(" >> Temp: ");

  if (SignBit) // If its negative
  {
     Serial.print("-");
  }
  Serial.print(Whole);
  Serial.print(".");
  if (Fract < 10)
  {
     Serial.print("0");
  }
  Serial.print(Fract);

  Serial.print(" C \n");

}

Let me know what you think or if you run into any issues.
willnue
Logged

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

LOL okay working on it. I'm having to set up the Arduino software on my netbook as I had already installed the hardware with the fish tank. Once I get it all set up and tested I'll check back in.
Logged

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