DS18B20 - temperature on request, battery lifetime?

Started by Lukapple, July 26, 2017, 03:27:23 AM

Lukapple

Hi all,
I'm working on simple temperature node, which will report temperature reading on request - base node sends RF "request-temperature" message. I've already searched forum for simmilar projects, but most of projects reports temperature reading to base station in intervals, so radio can be most of time in a sleep mode.
Currently my setup(see attachment) drains 9v battery in a day or so.
Do you guys have any suggestion how to preserve battery life in my case?


TomWS

Quote from: Lukapple on July 26, 2017, 03:27:23 AM
Hi all,
I'm working on simple temperature node, which will report temperature reading on request - base node sends RF "request-temperature" message. I've already searched forum for simmilar projects, but most of projects reports temperature reading to base station in intervals, so radio can be most of time in a sleep mode.
Currently my setup(see attachment) drains 9v battery in a day or so.
Do you guys have any suggestion how to preserve battery life in my case?
Is there a reason you want to be able to request the temperature at any arbitrary moment?

General practice is low duty cycle periodic reporting to a central, mains powered server of some sort, so, as you point out, power isn't wasted between samples.  The server can then be queried at any arbitrary time and the data is sufficiently fresh.

With on demand temperature reading you need your radio on all the time (or use Listen Mode, which hasn't proven all that reliable) and this puts your device in constant mA type current drain, where a battery efficient design would target single digit microamp (or less) average current drain.

Also, a 9V battery is wasting 2/3s of your available power unless you use a switching regulator to drop 9V to 3.3V.  And this is tricky to do at these low power levels.

Tom

ChemE

How are you sleeping your radio and microcontroller?  If you were using listen mode you should be able to get your idle current down to 250nA plus the draw from the DS18B20.  The temperature sensor draws little enough current that you can elect to power it from a digital pin and thus be able to turn it off completely when not needed.  Finally, you can skip the pullup resistor and just use those built into the 328p.  I posted some hyper fast code for a DS18B20 that uses the internal pullups. 

https://github.com/cdl1051/DS18B20_NROO

This code is also non-blocking so you can sleep the uC while the temperature conversion happens and then wake back up and TX the result.  You should be able to get the project down well below 1uA and your 9V battery should last well over a year.

Regarding batteries, a 9V battery wastes a lot of power since you only need 3.0V for the temperature sensor according to the datasheet.  The Mote will run all the way down to 1.8V.  A LiPo or two AAA batteries will give you a lot more mAh for the same space.

Lukapple

Thanks for your answers guys. Sorry for newbie questions - electronics is something that interests me, but otherwise I'm a software dev.

@Tom
QuoteIs there a reason you want to be able to request the temperature at any arbitrary moment?
Well probably not, looks like I've chosen wrong approach. I'm measuring pool water temperature and for template sketch I took my garage mote sketch, which sends door status on request :). I'll probably switch to periodic reporting.  Thanks for your explanation.

@ChemE
QuoteHow are you sleeping your radio and microcontroller?
Currently I'm not using any sleep methods. In a loop I call radio.receiveDone() and then 1s delay.

QuoteThe temperature sensor draws little enough current that you can elect to power it from a digital pin and thus be able to turn it off completely when not needed.
For temperature reading I'm using DallasTemperature library, with default settings:
init:
  _oneWire = OneWire(pin);
  _sensors = DallasTemperature(&_oneWire);
  _sensors.begin();


temperature request:
_sensors.requestTemperatures();
_sensors.getTempCByIndex(0);


How can I completly turn off digital pin#4?

This code is also non-blocking so you can sleep the uC while the temperature conversion happens and then wake back up and TX the result.  You should be able to get the project down well below 1uA and your 9V battery should last well over a year.

That sounds fantastic, thanks for the code, I'll check it out.
My goal is to get battery running for at least for a month or 2. I hope that your code will help me to achieve this goal, otherwise I'll probably switch to periodic reporting.

About batteries, will my setup work on two AAA batteries, 2x1.5V? Doesn't Moteino require minimum 3.3V input? Sorry again for noob questions.

ChemE

The Moteino is actually quite happy down to 1.8V and there have been a number of folks who have proven this out pretty thoroughly so don't worry about that.  You'll have to switch your brown out protection bits off though (I've never had any success changing my fuse bits personally) otherwise the 328p will reboot at 2.7V due to the brown out protection.  And don't worry about asking questions I enjoy sharing what I've learned which is little compared to some others here.

ChemE

Quote from: Lukapple on July 26, 2017, 09:12:19 AM
Thanks for your answers guys. Sorry for newbie questions - electronics is something that interests me, but otherwise I'm a software dev.
...
That sounds fantastic, thanks for the code, I'll check it out.
My goal is to get battery running for at least for a month or 2. I hope that your code will help me to achieve this goal, otherwise I'll probably switch to periodic reporting.

If you use Felix's LowPower library to sleep the processor between temperature measurements you will drop your current from 4mA down to 4.4uA.  That alone will push your battery life well past two months.  Additionally, there are software tricks to extend things even further.  This node absolutely does not need to run at 16MHz to serve this purpose.  You can divide down the clock to run at 8MHz or less and still have full speed conversations with the temperature probe and radio.  That will significantly cut your active current (but not change your sleep current).  It won't be hard to get that battery to last a year.

TomWS

Quote from: Lukapple on July 26, 2017, 09:12:19 AM
About batteries, will my setup work on two AAA batteries, 2x1.5V? Doesn't Moteino require minimum 3.3V input? Sorry again for noob questions.
The setup will work quite well on a couple of AAA batteries IF you remove the voltage regulator chip (easy to do, it's 3 pins and you lift the single pin side first) AND you reprogram the fuses to operate at 8MHz instead of 16MHz (which further extends battery life). 
UPDATE: ChemE is correct that you can keep the fuses at 16MHz and use the external crystal as a time base and then, in setup() reprogram the prescaler to run at a lower speed.  This saves power, but won't be as low as the internal 8MHz RC oscillator (which requires the fuse change).

If you don't want to or don't have the means to reprogram the fuses, you can run very nicely on 2 Lithium AAA (Eveready Ultimates) which will give you a nominal voltage of about 3.4V.

Tom

Felix

I have a slightly different approach, because I am "lazy".
Below is my approach and it works well for me, so you have a few different opinions to consider.

I have used a few Moteinos (stock, with LDO) on LiPos for years when properly put to sleep (with watchdog sleep, which yields ~6uA). I have some that are before the RFM69_ATC era and still keep going. The LDO uses 2uA, not a ton when other things can use many times more than that.

As mentioned before, to run LDO-less (saves you the cost of a 1xAA) you will need to load the 8mhz bootloader version and reprogram fuses for internal 8mhz resonator. And you have to be careful not to feed more than 3.6v onto any of the pins - that would permanently damage the RFM radio (and FLASHMEM). So you have to make sure your FTDI/USB-serial adapter is all 3.3v, not more. This allows you to save an extra 2uA and run from less than ~3.4v.
I need to mention that a stock Moteino can also run from less than that, but the LDO's 2uA quiescent becomes 200uA when you reach that point.

By "proper sleep" I mean put the MCU (moteino atmega328p) to watchdog sleep (periodic wakeup, 4uA), or deep sleep (wakeup by external source/interrupt, 0.1uA). All my sleepy nodes use the 328p watchdog to wakeup periodically (8second max watchdog timer sleep then wakeup to do something or just sleep again, so thats a 4uA that watchdog uses).
The LDO takes ~2uA. The radio is 0.1uA in sleep mode.
Of course, your sensor has to be slept too when not used, whatever that means (powering from another digital pin or via mosfet and cutting power, or if it has a "sleep" mode).

So overall my nodes sip ~6-7uA and are very happy. My MotionMote nodes are around 9-10uA (with the panasonic 2uA PIRs) and I got tired to keep looking at their voltage because they just go "forever" even with tiny LiPo cells, and when they do run out they charge the LiPo via USB and back to work.

IMHO before you sweat too much about the LDO, try it without, you can screw up too many variables going that route and you will (I did too). Getting your code right and sleeping your sensors and any other power drains is more important than saving 2uA.

TomWS

Quote from: Felix on July 26, 2017, 10:35:01 AM
IMHO before you sweat too much about the LDO, try it without [sic removing the LDO], you can screw up too many variables going that route and you will (I did too). Getting your code right and sleeping your sensors and any other power drains is more important than saving 2uA.
If you use can use LiPo batteries, with a simple solar charger, the battery will last 'forever'1 and you WILL need to keep the LDO in that case.

Tom
Note 1:  Where 'forever' means as long as the LiPo has recharge cycles left in it and your ambient temperature stays above -10C.  Since you're measuring pool water temperature, I think we're safe here...

Lukapple

#9
Hi Guys,
whoa, thanks for all the informations.
You are all talking about "periodic" reporting, where radio is in sleep mode, right?
Here are all the informations, that I gathered from your posts.
I'll try setup with options, that are marked with red. I've also added some questions, that are marked with blue.



   
   
   
   
   
   
   
   
   
   
Battery2x 1.5V AA (do I have to remove LDO voltage regulator if on 2xAA?)1x 9V
Voltage regulator(LDO)yes(default)no
Data requestperiodicon demand
Pullup resistorexternalinternal(328p) - sketch DS18B20 posted by ChemE
Sleep mode MCUsleep MCU between temp. measurements (lib by Felix) and periodic sleep (so this is watchdog sleep?)none
Sleep mode temp. sensor DS18B20not sure how. sensor doesn't have sleep mode. I should use mosfet or feed it from another digital pin?none
Temperature libDallasTemperature
https://github.com/milesburton/Arduino-Temperature-Control-Library
DS18B20 by ChemE
 https://github.com/cdl1051/DS18B20_NROO
Brown out protection bitson(default) do I need to turn that off if on 2x1.5 AA?off
328p clock8Mhz (do I have to remove LDO?)16Mhz
Solar chargeryesno

ChemE

#10
If you use the Energizer Ultimate Lithium batteries that are recommended you do not need to worry too much about removing the LDO.  Below is the discharge curve for these batteries (the AAA, the l92, has the same shape just smaller capacities).  Two of these will run your project from their initial voltage all the way down to 1.5V for certain.  I have some DS18B20s that I can test out to see if they will still behave properly at lower voltages than that but the datasheet says 3.3V minimum.  The Mote itself will behave perfectly all the way down to a single-cell voltage of 1.35V at which point the brown out protection will start forcing reboots.  If you were wanting to go further than that, you could change the fuse bits to disable BOP and then the Mote would run down to a single-cell voltage of 0.9V which is flat dead meaning you've been able to use the battery's entire charge. You can see from the graph that there is very little difference in mAh between 1.35V and 0.9V so the view doesn't really justify the climb in this case.  As Felix said, at some point the voltage will go low enough that the LDO will start consuming far more than 2uA.  This could be as high as 1.7V which sucks for these batteries since you get there essentially right away.  It is a shame that Felix didn't use the 3.0V LDOs but I understand why he went with 3.3V.



Concerning the DS18B20, just power it from any three digital pins don't worry about a MOSFET.  The sensor does not have a sleep mode but there is little penalty to cutting the cord and then powering it up again next time you want a reading.  The Dallas library will work fine it is just bloated, blocking, and slow compared to my code (not that I'm biased mind).

Felix

In my post above I referred to periodic reporting of some variable. For instance temperature and humidity is something you want to report not more often than every 5-10 minutes in normal circumstances (a room or garage or attic or even outside). To do that I sleep my Moteinos+WeatherShield (this uses a BME280 which is 0.1uA in sleep mode) using the 328p watchdog timer. So overall the consumption is around 6-7uA of the whole node, powered from a LiPo. Runs for a very long time, reports temp+hum+voltage every 5 minutes. Transmits at full power (no ATC), I have one deployed in summer 2015 at ~4.1v, now at 3.89v.

The watchdog uses a timer that alllows up to 8seconds max sleep before a wakeup occurs. So to sleep more than that I just use multiples of 8seconds.
The DS18B20 is not exactly a very low power friendly sensor. It's been discussed here in the forum before. It's also slow to measure and uses a lot of current when measuring. I think to make it low power enough you have to keep measuring cycle long enough and power it off while not in use. You might need to initialize it every time you power it back up, which might also be a power hungry process. I would recommend a sensor like BME280 which is far better in all aspects.

For 2xAA you will need to remove LDO to make consumption low enough.
There's many ways to keep consumption low. Tom uses a hardware TPL5110 watchdog chip to keep consumption below 0.1uA.

Brown-out - I would think you don't need this even if running from 2xAA. When voltage gets below 2V I would consider that the dead point.

ChemE

Quote from: Felix on July 27, 2017, 08:58:18 AM
Brown-out - I would think you don't need this even if running from 2xAA. When voltage gets below 2V I would consider that the dead point.

I thought the stock fuse bits set the BOD at 2.7V is it actually 2.0V?

Lukapple

@Felix
QuoteFor 2xAA you will need to remove LDO to make consumption low enough.
For now I don't want to remove LDO. Could you suggest which LiPo cells should I use(V, mAH) ?

QuoteThe DS18B20 is not exactly a very low power friendly sensor.
I choose DS18B20 because it's in waterproof housing. I hope that it will last for 2 months with LiPo.

@ChemE
QuoteThe Dallas library will work fine it is just bloated, blocking, and slow compared to my code (not that I'm biased mind).
Thanks, I'll try to use your code for DS18B20.

ChemE

#14
I decided to fool around with this a little and I've modified my code to be Moteino friendly.  Place Pin 3 (Vdd) of the DS18B20 in pin 7 of the Mote and Pin 1 (GND) of the DS18B20 in pin 9 of the Mote like I've pictured below.


Here is the code I'm using...
#include <LowPower.h>

// Solder-free method of detecting the ROM of a DS18B20 - spread the 3 legs of the sensor wide enough to fit into GND, 13, and 12 
// and place the sensor in these pins with the flat side facing the LED on the Uno and the round side facing away from the Uno.  
// Then upload and open a serial monitor with a baud rate of 9600.
#include <util/delay.h>

// ====================================================== Pre-Compiler Definitions ====================================================== 
#define DEBUG 1   // Controls the inclusion or exclusion of serial debug information
#define CLOCK 1   // Controls whether or not temperature reading duration is timed

// Direct port manipulation needed to conduct the OneWire bus
#define   PowerPin              PB1                      // Pin 12 - we will be using this pin to supply Vcc to the DS18B20
#define   POWER_TEMP_PROBE      PORTB |= (1<<PowerPin)    // Define method for powering the DB18B20
#define   DEPOWER_TEMP_PROBE    PORTB &= ~(1<<PowerPin)   // Define method for depowering the DB18B20
#define   GroundPin             PD7
#define   Pin                   PB0                       // Set up pin 13 as the data pin
#define   DIRECT_MODE_OUTPUT    DDRB |= (1<<Pin)//_BV(Pin)          // Much faster and smaller version of pinMode(Pin, OUTPUT)
#define   DIRECT_MODE_INPUT     DDRB &= ~(1<<Pin)         // Much faster and smaller version of pinMode(Pin, INPUT)
#define   DIRECT_WRITE_HIGH     PORTB |= (1<<Pin)         // Much faster and smaller version of digitalWrite(Pin, HIGH)
#define   DIRECT_WRITE_LOW      PORTB &= ~(1<<Pin)        // Much faster and smaller version of digitalWrite(Pin, LOW)
#define   DIRECT_READ           PINB & (1<<Pin) ? 1 : 0   // One line if else statement using the format [test ? true return : false return]

// Delay values needed for conducting a OneWire bus
#define   clk_div               1                         // This code assumes a processor frequency of 16MHz but this can be lowered as long as clk_div is updated
#define   DELAY_A               6/clk_div                 // Delay values obtained from http://www.maximintegrated.com/app-notes/index.mvp/id/126
#define   DELAY_B               64/clk_div
#define   DELAY_C               60/clk_div
#define   DELAY_D               10/clk_div
#define   DELAY_E               9/clk_div
#define   DELAY_F               55/clk_div
#define   DELAY_G               0/clk_div
#define   DELAY_H               480/clk_div
#define   DELAY_I               72/clk_div
#define   DELAY_J               410/clk_div

// DS18B20 command codes
#define   READROM               0x33                      // Read the ROM of a OneWire device; there must only be one OneWire device on the bus!
#define   STARTCONVO            0x44                      // Tells device to take a temperature reading and put it on the scratchpad
#define   READSCRATCH           0xBE                      // Read from the scratchpad
#define   WRITESCRATCH          0x4E                      // Write to the scratchpad
#define   COPYSCRATCH           0x48                      // Tells the DS18B20 to copy the contents of the scratchpad to EEPROM
#define   SKIPROM               0xCC                      // Tells all OneWire sensors on the bus that the next command applies to them
#define   MATCHROM              0x55                      // Tells all OneWire sensors on the bus to listen for a specific ROM next

#define   BAUD_RATE             57600
#define   myubbr                (F_CPU/clk_div/16/BAUD_RATE-1) // Baud rate for UART

int main() {  
  bool present = 0;
  uint8_t ROM[8] ;
  
  #if DEBUG
    #if CLOCK
      unsigned long start_time, end_time;
      // Timer 0 initialization from wiring.c for a ATmega 328P (Arduino Uno rev 3) + 12 bytes to sketch size
      TCCR0A = _BV(WGM01) | _BV(WGM00);      // set timer 0 prescale factor to 64
      TCCR0B = _BV(CS01) | _BV(CS00);        // set timer 0 prescale factor to 64
      TIMSK0 = _BV(TOIE0);                 // enable timer 0 overflow interrupt
    #endif
    
    // Initialize the UART
    UBRR0H = (unsigned char)(myubbr>>8);
    UBRR0L = (unsigned char)myubbr;
    UCSR0A = 0;//Disable U2X mode
    UCSR0B = (1<<TXEN0);//Enable transmitter
    UCSR0C = (3<<UCSZ00);//N81
    _delay_ms(100);
  #endif

  // Setup for the power pin
  DDRB |= (1<<PowerPin);    // Set the power pin as an output
  POWER_TEMP_PROBE;         // Drive the power pin high to power the DS18B20
  
  // Setup for the ground pin
  DDRD |= (1<<GroundPin); // Set the ground pin as an output  
  PORTD &= ~(1<<GroundPin);  // Pull the ground pin low
  
  // Set the sensor's resolution to 11 bits
  SetResolution(9);
  
  for(;;) {  // Loop forever

    POWER_TEMP_PROBE;
    // Perform a OneWire reset pulse and see if we detect a presence pulse afterward
    present = reset();
    
    // If a one-wire device is present, attempt to read its ROM
    if (present) {
      write(READROM);
      for(uint8_t i=0;i<8;i++) {
        ROM[i]=read();
      }
    }
    
    #if DEBUG
      simpletx("Presence pulse: ");
      if(present) {
        simpletx("Detected");
      } else {
        simpletx("Not Detected");
      }
      
      simpletx("\tROM is: ");
      for(uint8_t i=0;i<8;i++) {
        simpletx("0x");
        txByteAsHex(ROM[i]);
        if (i!=7) simpletx(",");
      }
      simpletx("\t\t");
    #endif
    
    
    // If we detected a Dallas family sensor, let's go ahead and take a temperature reading
    if (ROM[0]=0x28) {  // The first byte of all dallas sensors is always 0x28
      reset();
      write(SKIPROM);
      write(STARTCONVO);
      
      #if CLOCK
        start_time = millis();
      #endif
      
      LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF);   // Put the uC to sleep while the temperature conversion proceeds to save power
      LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);   // Put the uC to sleep while the temperature conversion proceeds to save power
      //while(!read());  //_delay_ms(750);    // Can either wait 750 ms for the conversion to be done or else read until we get a 1 back from the DS18B20 meaning it is signaling complete
      
      #if CLOCK
        end_time = millis();
      #endif
      
      reset();
      write(SKIPROM);
      write(READSCRATCH);
      uint8_t tempLSB = read();
      uint8_t tempMSB = read();
      DEPOWER_TEMP_PROBE;  // Rather than perform a reset to tell the probe to stop sending data, just cut the power and it will get the message!
      
      #if DEBUG
        simpletx("Temperature: ");
        txRawTempAsFloat( tempMSB<<8 | tempLSB );
        simpletx("F");
        
        #if CLOCK
          simpletx("\tConversion took "); 
          txInt(end_time-start_time);
          simpletx(" ms");
        #endif
        simpletx("\n");
        _delay_us(300);
      #endif
    }

    uint8_t sleep_count=0;
    do LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    while (++sleep_count < 4);
    //_delay_ms(10000);
  }  // End for
}  // End main

// ============================================================================================================================================================
// Sets the temperature measurement resolution of the DS18B20 to either 9, 10, 11, or 12 bits  If any other number is passed, the sensor will be set to 12 bits
// Only works if there is a single DS18B20 on the one wire network
// ============================================================================================================================================================
static inline void SetResolution(uint8_t resolution) {
  reset();
  write(SKIPROM);
  write(WRITESCRATCH);
  write(0x00);
  write(0x00);
  switch (resolution) {
    case 9: write(0x1F);  break;
    case 10: write(0x3F); break;
    case 11: write(0x5F); break;
    default: write(0x7F); break;
  }
  reset();
  write(SKIPROM);
  write(COPYSCRATCH);
  //_delay_ums(15);
}


static inline uint8_t read() {
  uint8_t r=0;
      
  noInterrupts();
  for (uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) {
    DIRECT_MODE_OUTPUT;
    DIRECT_WRITE_LOW;
    _delay_us(DELAY_A);
    DIRECT_MODE_INPUT;
    DIRECT_WRITE_HIGH;  // New line for no resistor modification / enable pull-up resistor
    _delay_us(DELAY_E);
    if (DIRECT_READ) r |= bitMask;
    _delay_us(DELAY_F);
  }
  interrupts();
  return r;
}

static inline void write(uint8_t v) {
  noInterrupts();
  for (uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) {
    DIRECT_WRITE_LOW;
    DIRECT_MODE_OUTPUT;
    if (bitMask & v) {
      _delay_us(DELAY_A);
      DIRECT_WRITE_HIGH;
      _delay_us(DELAY_B);
    } else {
      _delay_us(DELAY_C);
      DIRECT_WRITE_HIGH;
      _delay_us(DELAY_D);
    }
  }
  DIRECT_MODE_INPUT;
  interrupts();
}

static inline uint8_t reset(void) {
  noInterrupts();
  DIRECT_MODE_INPUT;      
  DIRECT_WRITE_LOW;
  DIRECT_MODE_OUTPUT;
  _delay_us(DELAY_H);
  DIRECT_MODE_INPUT;
  DIRECT_WRITE_HIGH;  // New line for no resistor modification / enable pull-up resistor
  _delay_us(DELAY_I);
  uint8_t ret = !(DIRECT_READ);
  interrupts();
  _delay_us(DELAY_J);
  return ret;
}

static inline void simpletx( char * string ) {
  /*if (UCSR0B != (1<<TXEN0)) { //do we need to init the uart?
    UBRR0H = (unsigned char)(myubbr>>8);
    UBRR0L = (unsigned char)myubbr;
    UCSR0A = 0;//Disable U2X mode
    UCSR0B = (1<<TXEN0);//Enable transmitter
    UCSR0C = (3<<UCSZ00);//N81
    _delay_ms(30);
  }*/
  while (*string) {
    while ( !( UCSR0A & (1<<UDRE0)) );
    UDR0 = *string++; //send the data
  }
}

static inline void txByteAsHex(uint8_t inp) {
  char snd[3];
  uint8_t tmp = inp>>4;
  
  if (tmp<10) {
    snd[0]=48+tmp;
  } else {
    snd[0]=55+tmp;
  }
  
  tmp=inp%16;
  if (tmp<10) {
    snd[1]=48+tmp;
  } else {
    snd[1]=55+tmp;
  }
  snd[2]='\0';
  simpletx(snd);
}

static inline void txInt(long inp) {
  long temp = inp;
  uint8_t numChars=0;
  boolean isNegative=false;
  
  // Check to see if there is a negative sign
  if(temp<0){
    isNegative=true;
    numChars++;
    temp*=-1;
  }
  
  do {
    numChars++;
    temp /= 10;
  } while ( temp );
  char buf[numChars];
  
  // Write the negative sign if present and the terminating null character
  temp=inp;
  buf[numChars]=0;
  if(isNegative) {
    temp*=-1;
    buf[0]='-';
  }
  
  int i = numChars - 1;
  do {
      buf[i--] = temp%10 + '0';
      temp /= 10;
  } while (temp);
  
  simpletx(buf);
}

// Converts the raw temperature from a DS18B20 directly to a string containing the temperature in °F with 1 decimal place
// avoids unnecessary floating point math, float variables, and casts, and 32-bit math
// TODO: May not work properly with temperatures below 32°F
static inline void txRawTempAsFloat(uint16_t raw) {  
  char buffer[6];

  uint8_t decimalPos = 2;  // default case of a temp between 0 and 99.9
  uint8_t nullPos = 4;     // default case of a temp between 0 and 99.9
  uint16_t temp;
  
  // Check to see if the temperature passed in is negative
  if (raw>>11) {
    // Can't get here unless one of the 5 most-significant bits are ones which means we have a negative number, convert it
    raw = ~(raw-1);    // Convert the two's compliment number back into one's compliment
    
    if (raw > 284) {  // This temperature is far enough negative in the celcius scale that it is also negative on the farhenheit scale
      decimalPos += 1;   // Account for the negative sign's place in the string
      nullPos += 1;      // Account for the negative sign's place in the string
      buffer[0] = '-';   // Write the negative sign in the string
    }
    temp = (9*raw)/8-320;                   // Keeps only 1 decimal place but uses 16-bit math
  } else {
    temp = (9*raw)/8+320;                   // Keeps only 1 decimal place but uses 16-bit math
  }


  // Convert the raw temperature into the temperature in Fx10 so that one decimal place is kept
  //uint32_t temp = (raw*1125ul+320000ul)/1000ul;  // Keeps all 4 decimal places but uses 32-bit math  
  if(temp>=1000) {  // We're looking at a positive number with three digits
    decimalPos += 1;
    nullPos += 1;
  }
  
  buffer[nullPos--] = '\0';
  do {
    if (nullPos==decimalPos) buffer[nullPos--] = '.';
    buffer[nullPos--] = temp % 10 + '0';
    temp /= 10;
  } while (temp);  
  
  simpletx(buffer);
}


This uses Felix's LowPower library to sleep the processor for 32 seconds between temperature readings.  I also sleep the processor for 75ms during a 9-bit temperature conversion which saves a teeny amount of power.  There are still things you could and should do to extend this.  I'm not sleeping the radio, you most certainly should that saves a good amount of power.  Also, you can turn up the clock divider in code without messing with fuse bits (I'll add this soonish just to have a play myself).  As Felix said, the DS18B20 isn't all that battery friendly but 75ms of active time every 5 minutes is a 0.025% duty cycle.  At a current draw of 1mA when it is measuring that works out to an average current draw of 250nA which is all kinds of acceptable on a 2xAAA battery powered project.