Temperature sensing and time application issues with DS18B20

Hello all! Okay, so I have a dilemma. I want to sense three different temperatures, so, I started by using the Maxim DS18B20 temperature sensor. The accuracy and ability to combine multiples on a bus were attractive. I have one now for testing that I ordered and got it working with little or no issue. It does appear to work great and is very accurate. However, I also want to keep a timer or stopwatch (like a kitchen timer) in my application tracking to the second. Here is the issue, these take 750ms to convert the temperature to the data word that I can read out. A “delay(750);” is an eternity in the microcontroller world, especially if I want to do other time sensitive things, such as keeping a stopwatch that ticks every second. So, any ideas? I am worried about when I do need three of these, I know you can put multiples of them on the bus but is it 750ms each??? What about timing issues, how do I know they have each converted their temperature at the same time when reading multiples on the bus?

I am considering changing out to a TMP36 or a thermistor. Granted, I would give up some accuracy but I would be able to read them out in microseconds by doing an analogRead and then some math.

I don’t know, thoughts?

Thanks!

You can initiate a conversion on each sensor and then do something else for the 750 ms. If you ask it (i.e. read the status), a DS18B20 will tell you very quickly whether it is busy, or has finished the conversion.

You don't have to convert them consecutively. There is a SKIP ROM command which you can issue on the bus which tells all of the DS18B20 to execute the next command without first checking for their own address. Then you just issue the temperature conversion command and wait for 750ms after which they will all have finished their conversion and you can read each one.
Also, the 750ms delay is only required if you use the default 12 bit precision (to a sixteenth of a degree). If you set the devices to use 9 bit precision (to half a degree) the required delay is only about 95 milliseconds.

Pete

Thank you both very much for the replies. I think I understand the direction I want to go in now.

  1. I was happy with .5 degree resolution (which is still better than the thermistor and TMP36 devices) so I will set the resolution down to 9 bits. Right out of the gate, that cuts me down to 100ms or just under as you pointed out. This in itself is great.

  2. I didn’t even think that I can issue the command, then move on and do other things. When my other things are done, if they still did not add up to 100ms or 750ms, I can then delay at the end. Also a great suggestion.

  3. I like the SKIP ROM command. I need to research how to do this. If I am understanding it correctly, it may even cut down on the code I need to send to get the temperature, correct? I have pasted below what I am doing now.

  4. What will the device do (or tell you) when it is still busy? Maybe, to build on number 2, instead of waiting a defined period of time, you could do a while loop to keep checking until it is not busy anymore and gets some data. Right?

Thanks again!

This is the code that runs in the loop. Would be nice to cut it down. Would SKIP ROM do this?
//find a device
if (!ds.search(addr)) {
ds.reset_search();
return;
}
if (OneWire::crc8( addr, 7) != addr[7]) {
// Serial.println(“Address incorrect”);
return;
}
if (addr[0] != DS18S20_ID && addr[0] != DS18B20_ID) {
// Serial.println(“Device is not a known temp sensor”);
return;
}
ds.reset();
ds.select(addr);
// Start conversion
ds.write(0x44, 1);
// Wait some time…
delay(750);
present = ds.reset();
ds.select(addr);
// Issue Read scratchpad command
ds.write(0xBE);
// Receive 9 bytes
for ( i = 0; i < 9; i++) {
data = ds.read();
}
// Calculate temperature value
tempc = ( (data[1] << 8) + data[0] )*0.0625;
tempf = (tempc * 1.8) + 32;

please use code tags when posting code, it are the # buttons. (you can modify existing post above)

mbedford:
3. I like the SKIP ROM command. I

You don't need any of that stuff and are just being spooked by a non-existent problem. You can run three sensors at the full 12 bit resolution and one second intervals just fine. The 750 cycle can be dramatically reduced if you use lower resolution and avoid parasitic power, but I stay with 12 bit as a one second cycle is quite fast enough.

I submit there will be plenty of time for all you need. My cycle is

read the time
read 3x DS18B20
display to LCD
Write to SD card
Send to Bluetooth
Send to Internet
delay (850)

... all in one second, and yes, the real work is done in 150. I have never heard of the skip ROM procedure

I have never heard of the skip ROM procedure

Try reading the datasheet. Page 11.

Pete

The Arduino library that I checked doesn’t seem to include an appropriate function call to check the device status, but you could do “other things” and use millis() to check for the appropriate time to elapse while the DS18B20 is converting the temperature.

The working C code below was written for WinAVR on a non-Arduino ATmega168 setup that addresses a single (now obsolete) DS1820 sensor, and it includes its own set of one-wire routines. Perhaps you will find it useful. It shows how to use the SKIP ROM command, starts the conversion then repeatedly calls the device read status routine to check the busy flag. See the function OW_read_temperature() at the end of the listing for the overall flow. Hope this helps.

//this version for obsolete DS1820 sjr 12/2013
// don't forget pullup resistor on DQ!

/* DS1820 Connections */
#define OW_PORT PORTC
#define OW_DDR DDRC
#define OW_PIN PINC
#define OW_DQ PC0

/* Utility function defs */
#define OW_INPUT_MODE() OW_DDR&=~(1<<OW_DQ)
#define OW_OUTPUT_MODE() OW_DDR|=(1<<OW_DQ)
#define OW_LOW() OW_PORT&=~(1<<OW_DQ)
#define OW_HIGH() OW_PORT|=(1<<OW_DQ)

#define OW_CMD_CONVERTTEMP 0x44
#define OW_CMD_RSCRATCHPAD 0xbe
#define OW_CMD_WSCRATCHPAD 0x4e
#define OW_CMD_CPYSCRATCHPAD 0x48
#define OW_CMD_RECEEPROM 0xb8
#define OW_CMD_RPWRSUPPLY 0xb4
#define OW_CMD_SEARCHROM 0xf0
#define OW_CMD_READROM 0x33
#define OW_CMD_MATCHROM 0x55
#define OW_CMD_SKIPROM 0xcc
#define OW_CMD_ALARMSEARCH 0xec


uint8_t OW_reset(void){
	uint8_t i;
//Pull line low and wait for 480uS
    OW_LOW();
    OW_OUTPUT_MODE();
    _delay_us(480);
//Release line and wait for 60uS
    OW_INPUT_MODE();
    _delay_us(60);
//Store line value and wait until the completion of 480uS period
    i=(OW_PIN & (1<<OW_DQ));
    _delay_us(420);
//Return the value read from the presence pulse (0=OK, 1=WRONG)
    return i;
}

void OW_write_bit(uint8_t bit){

//Pull line low for 1uS
    OW_LOW();
    OW_OUTPUT_MODE();
    _delay_us(1);
//If we want to write 1, release the line (if not will keep low)
    if(bit) OW_INPUT_MODE();
//Wait for 60uS and release the line
    _delay_us(60);
    OW_INPUT_MODE();
}

uint8_t OW_read_bit(void){
	uint8_t bit = 0;
//Pull line low for 1uS
    OW_LOW();
    OW_OUTPUT_MODE();
    _delay_us(1);
//Release line and wait for 14uS
    OW_INPUT_MODE();
    _delay_us(14);
//Read line value
    if(OW_PIN&(1<<OW_DQ)) bit=1;
//Wait for 45uS to end and return read value
    _delay_us(45);
    return bit;
}

uint8_t OW_read_byte(void){
uint8_t i = 8, n = 0;
    while(i--){
    //Shift one position right and store read value
        n >>= 1;
        n |= (OW_read_bit()<<7);
        }
    return n;
}

void OW_write_byte(uint8_t byte){
	
	uint8_t i = 8;
    while (i--){
    //Write actual bit and shift one position right to make the next bit ready
    OW_write_bit(byte&1);
    byte >>= 1;
    }
}

// reads DS1820 and returns signed integer temp in (degrees C)*10

signed int OW_read_temperature(void) {

    uint8_t tbytes[2];

signed int temp;

//Reset, skip ROM and start temperature conversion
    OW_reset();
    OW_write_byte(OW_CMD_SKIPROM);
    OW_write_byte(OW_CMD_CONVERTTEMP);
//Wait until conversion is complete
    while(!OW_read_bit());

//Reset, skip ROM and send command to read Scratchpad
    OW_reset();
    OW_write_byte(OW_CMD_SKIPROM);
    OW_write_byte(OW_CMD_RSCRATCHPAD);
    //Read Scratchpad (only 2 first bytes)
    tbytes[0] = OW_read_byte();
    tbytes[1] = OW_read_byte();
    OW_reset();

	temp = ((signed int) tbytes[1]<<8) | tbytes[0];

	temp *= 5; //in tenth's C 
    return temp;
}