Temperature Sensing using DS18B20 Digital Sensors

Note: When referring to Arduino below, this works in the same way on the emonTx which is arduino-based.
 
The DS18B20 is a small thermometer with a built in 12bit ADC; it can be easily connected to Arduino digital input. The sensor communicates over a one-wire bus and requires little in the way of additional components.
 
The sensors have a quoted accuracy of +/-0.5 deg C in the range -10 deg C to +85 deg C. 

Hardware

Multiple sensors can be connected to the same data bus; each sensor identifies itself by a unique serial number.

The sensor can operate in normal or parasite power mode. In normal mode, a 3-wire connection is needed. In parasite power mode the sensor derives its power from the data line, meaning only two wires, the data line and a ground connection, are required.

Note: The Arduino positive supply rail is referred to as Vcc and the positive supply for the DS18B20 as Vdd. In this context, these are the same thing.

Normal Mode

In normal mode, each sensor is connected between a power line (Vdd pin 3) and ground (GND pin 1), and the data output (DQ pin 2) connects to a third, data, line. The data output is a 3-state or open-drain port (DQ pin 2) and a 4k7 pull-up resistor to the power line is required. The data line is connected to a free Arduino digital input or Arduino digital pin 4 in the case of the emontx.

Normal mode is recommended when many devices and/or long distances are encountered.

Parasite Mode

Parasite power mode requires both DS18B20 GND (pin 1) and Vdd (pin 3) to be connected to ground. The DQ pin (pin 2 - the middle pin) is the data/parasite power line. The data line requires a pull-up resistor of 4k7 connected to + 5 V. The data line is connected to a free Arduino digital input or Arduino digital pin 4 in the case of the emonTx.

Parasite mode should only be used when a small number of devices are used over relatively short distances.

 

 Figure 1: Normal Power Connection Diagram

 Figure 2: Parasite Power Connection Diagram

 Figure 3: Three DS18B20's in normal power mode

 Figure 4: Three DS18B20's in parasite power mode
 

Connecting multiple sensors

If the sensors are located relatively close to the Arduino/emonTx, then satisfactory operation should be achieved by making a parallel connection of the sensors at the connection to the Arduino or emonTx . This is called a radial or 'star' arrangement.

If long cable runs are required, consideration should be given to connecting in 'daisy-chain' fashion where one cable runs from the furthest sensor, connecting to each sensor in turn before ending at the Arduino or emonTx.

There is more about this in the note below.

For short cable runs, unscreened two- or three-core cable, or single-core (parasite mode) or twin-core (normal mode) screened audio cable should be suitable. For longer cable runs, low capacitance cable such as rf aerial downlead (parasite mode) has been successfully used over a distance of 10 m. CAT 5 network cable has also been used with success over a distance of 30m, with data & ground using one twisted pair and power & ground using a second twisted pair.

 
 

Temperature Sensing with the emonTx

The emonTx supports direct connection of DS18B20 temperature sensors, however there are significant differences between the emonTx V2 and the emonTx V3.

The emonTx V2

The PCB includes the option to solder a DS18B20 sensor directly onto the PCB for monitoring the temperature where the emonTx is located. A more useful option is to connect DS18B20 temperature sensors to the 3.5mm temperature jack port for monitoring remote temperatures such as outside temperature, living room temperature and boiler temperature. 

The sensors can be connected either in normal or parasite power mode. We recommend normal power mode for increased reliability. 3-core 22AWG wire is perfect for wiring up sensors. The sensors can also be bought ready encapsulated and wired up, and the 4k7 pull-up resistor is provided on the pcb.

Wire up the sensor(s) to a male 3.5mm jack as follows: 

Connection Normal Mode Parasite Mode Voltage
Tip DQ (data line) DQ (data line) 3.9 V approx
Ring Vdd no connection + 5 V
Sleeve GND GND + Vdd 0 V

(Voltages are for V2.2 boards powered at 5 V)

 

Note: If you purchased the Waterproof DS18B20 temperature sensing kit from the shop, it is pre-wired:

Data: White wire
Vcc: Red wire
GND: Black wire

The one-wire temperature data line is hardwired to Arduino Dig I/O 4 on the emonTx PCB. See the emonTx reference page for schematic and PCB layout. 

The emonTx runs internally at 3.3V. On emonTx PCB version 2.0 and 2.1 the DS18B20 also runs at 3.3V.

On emonTx V2.2 the temperature sensors are connected to the PWR rail which is 5V when the emonTx is powered via 5V USB. Note: ignore the solder jumper, if you look carefully it is already connected to PWR. Running the sensors at 5V gives increased reliability and allows for more sensors and longer cable runs to be used.

GitHub emonTx temperature example  also includes a sketch to extract the serial number from the DS18B20.

Software

 
Version 372 works with Arduino 1.0: download it from here
 
This library makes interfacing with the sensors very straightforward and come with good examples.
 
The OneWire protocol communication library is also required. Version 2.0 can be downloaded from here.
 
Once the libraries have been extracted to the Arduino libraries folder and Arduino IDE has been restarted I recommend checking out the ‘simple’ and ‘multiple’ examples which are part of the Dallas Temperature Control Library. These two examples demonstrate two methods to identify and communicate with each sensor.
 
Addressing the sensors.

Each sensor has an unique serial number given to it in manufacture, and your sketch (unless it is the "low-power" one that only expects a single sensor) must be programmed with these numbers so that it can identify and interrogate each sensor individually. Download the examples from GitHub emonTx temperature example and in there you will find the temperature search test sketch. You need run this once only to extract and list the serial number from each DS18B20, then you manually copy the serial numbers into your monitoring sketch.

The emonTx V3

The emonTx V3 has the connection for the temperature sensors available on a screw terminal block. Full details can be found on the Wiki page. The pre-loaded sketch will sense a single temperature sensor at start-up and requires no further configuration. Note that the examples for the emonTx V2 and the temperature search sketch will not work without modification.

Notes and further reading 

For large numbers of sensors and long cable runs use the DS2480B 1-wire driver chip. More info here. Thanks to Chris Shucksmith for sharing. 

"If you intend to have a large 1-wire network, it is important that you design the network correctly, otherwise you will have problems with timing/reflection issues and loss of data. For very small networks, it is possible to connect each sensor in a star or radial arrangement. This means that each sensor is connected via its own cable back to a central point and then connected to the 1-wire to serial adapter. However, it is strongly recommend that you connect each sensor to a single continuous cable which loops from sensor to sensor in turn (daisy chain). This will reduce potential mis-reads due to reflections in the cable. Each sensor should have a maximum of 50mm (2") of cable connected off the main highway. Even using this method, connecting more than 10-15 sensors will still cause problems due to loading of the data bus. To minimise this effect, always place a 100-120 ohm resistor in the data leg of each sensor before connecting to the network."

quoted from: http://www.jon00.me.uk/onewireintro.shtml

Lots of info about 1-wire bus problems here: http://www.shucksmith.co.uk/blog/ds2480bds18b20drivers-1

 

 
 
Paul Reed's picture

Re: DS18B20 temperature sensing

 I have tried replacing the code in the Simple example

  sensors.requestTemperatures(); 

  Serial.print(sensors.getTempCByIndex(0));

with

   sensors.requestTemperatures(); 

   if(sensors.getAddress(0x28, 0xC0, 0x5E, 0x9C, 0x03, 0x00, 0x00, 0xA1, 0))
   temp0=(sensors.getTempC(0x28, 0xC0, 0x5E, 0x9C, 0x03, 0x00, 0x00, 0xA1,));

   if(sensors.getAddress(0x28, 0xC0, 0x5A, 0x9C, 0x09, 0x00, 0x00, 0xB1, 1))
   temp1=(sensors.getTempC(0x28, 0xC0, 0x5A, 0x9C, 0x09, 0x00, 0x00, 0xB1,));

but I get a zillion error messages when I try and compile it. Have I done it wrong? (again!)

 

glyn.hudson's picture

Re: DS18B20 temperature sensing

Hi Paul, 

Hope this help, below is an example taken from my monitoring system I'm currently running at home. 


//------------------------------------------------------------

  // Setup one-wire sensors

  //------------------------------------------------------------

 // Start up the library

  sensors.begin();

  delay(100);

  

  // Grab a count of devices on the wire

  numberOfDevices = sensors.getDeviceCount();

  

  // locate devices on the bus

  Serial.print("Locating devices...");

  

  Serial.print("Found ");

  Serial.print(numberOfDevices, DEC);

  Serial.println(" devices.");


  // report parasite power requirements

  Serial.print("Parasite power is: "); 

  if (sensors.isParasitePowerMode()) Serial.println("ON");

  else Serial.println("OFF");

  

  // Loop through each device, print out address

  for(int i=0;i<numberOfDevices; i++)

  {

    // Search the wire for address

    if(sensors.getAddress(tempDeviceAddress, i))

 {

 Serial.print("Found device ");

 Serial.print(i, DEC);

 Serial.print(" with address: ");

 printAddress(tempDeviceAddress);

 Serial.println();

 

 Serial.print("Setting resolution to ");

 Serial.println(TEMPERATURE_PRECISION,DEC);

 delay(100);

 // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)

 sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);

 

  Serial.print("Resolution actually set to: ");

 Serial.print(sensors.getResolution(tempDeviceAddress), DEC); 

 Serial.println();

 }else{

 Serial.print("Found ghost device at ");

 Serial.print(i, DEC);

 Serial.print(" but could not detect address. Check power and cabling");

 }

  }  

  

    //------------------------------------------------------------

   // Get inital sensor readings 

   //------------------------------------------------------------

    sensors.requestTemperatures();            //issue global request for each temp sensor on network to retunr a temp

       

       if(sensors.getAddress(tempDeviceAddress, 0))

          temp0=(sensors.getTempC(tempDeviceAddress)); //read temp from sensor 0 and store in accumulator 0

    

       if(sensors.getAddress(tempDeviceAddress, 1))

          temp1=(sensors.getTempC(tempDeviceAddress));

       

       if(sensors.getAddress(tempDeviceAddress, 2))

         temp2=(sensors.getTempC(tempDeviceAddress));

         

 //if tempsensor error

 if (temp0 == DEVICE_DISCONNECTED)

  {

    sensors.begin();

    for(int i=0;i<numberOfDevices; i++)

      sensors.getAddress(tempDeviceAddress, i);

      Serial.println("problem");

  }

     //------------------------------------------------------------

  

  Ethernet.begin(mac, ip, gateway);            //Setup ethernet client

  

}//end setup 

  


   

//**************************************************************************************************

// LOOP

//**************************************************************************************************

   

void loop(){   

      


  //------------------------------------------------------------

  // Read temperatuere sensors  

  //------------------------------------------------------------ 

   //if tempsensor error

 if (temp0 == DEVICE_DISCONNECTED)

  {

    sensors.begin();

    for(int i=0;i<numberOfDevices; i++)

      sensors.getAddress(tempDeviceAddress, i);

      Serial.println("problem");

  }

    if (acc_count <= temp_samples){


      sensors.requestTemperatures();            //issue global request for each temp sensor on network to retunr a temp

       

       if(sensors.getAddress(tempDeviceAddress, 0))

          acc0=acc0 + (sensors.getTempC(tempDeviceAddress)); //read temp from sensor 0 and store in accumulator 0

       

       if(sensors.getAddress(tempDeviceAddress, 1))

          acc1=acc1 + (sensors.getTempC(tempDeviceAddress));

       

       if(sensors.getAddress(tempDeviceAddress, 2))

         acc2=acc2 + (sensors.getTempC(tempDeviceAddress));

       

       acc_count++;                              //increment accumulator count


     }

   

   if (acc_count >temp_samples)                                          //after 30 samples have been taken...

     {

     

      temp0=acc0/acc_count;    //get average temperature sensor reading 

      temp1=acc1/acc_count;    //get average temperature sensor reading 

      temp2=acc2/acc_count;    //get average temperature sensor reading 

  

      acc0=0;                  //reset accumulator 

      acc1=0;                  //reset accumulator 

      acc2=0;                  //reset accumulator 

      

      acc_count=0;             //reset accumulator count

     }

     

    Serial.print(temp0);

    Serial.print("  ");

    //Serial.print(acc0);

    //Serial.print("   ");

    Serial.print(temp1);

    Serial.print("  ");

    Serial.println(temp2);

    //Serial.print("  ");

   //------------------------------------------------------------   

 

Paul Reed's picture

Re: DS18B20 temperature sensing

 Glyn, do you have the rest of the sketch please, the first part is missing, variable declarations etc.

Thanks

glyn.hudson's picture

Re: DS18B20 temperature sensing

Sure, here's all the code from my home monitor setup: http://openenergymonitor.org/emon/sites/default/files/HomeMonitorV4.zip.

Its a bit outdated, its been running for a few years now. The emonTx was only a pipedream at this stage! 

Paul Reed's picture

Re: DS18B20 temperature sensing

 Thanks Glyn for your sketch,  it has been time well spent working through your code. I have learnt a lot from you!

Paul Reed's picture

Re: DS18B20 temperature sensing

 Glyn, I have used extracts from your sketch for a few months now, and occassionally get a rogue reading posted to Pachube, usually a large negative number (it's averaged over 3 or 4 readings), the last one was -25.4 degC.

I wondered if the error catching code should be;

if (temp0 == -127)   { ...reset sensors

instead of

if (temp0 == DEVICE_DISCONNECTED)   { ...reset sensors

glyn.hudson's picture

Re: DS18B20 temperature sensing

Good observation. Why not have both. Anything less than -40 higher than about 50 (for ambient temperaure monitoring in the UK)  could be considered a rouge value. 

Paul Reed's picture

Re: DS18B20 temperature sensing

 Thanks, I'll mod the code to:



  sensors.requestTemperatures(); // Send the command to get temperatures

  if(sensors.getAddress(tempDeviceAddress, 0))

  tmpSenseP = (sensors.getTempC(tempDeviceAddress));

      //---Error rejection---//

      if ((tmpSenseP < -50) || (tmpSense > 50))  {

      sensors.begin();

      for(int i=0;i<numberOfDevices; i++)

      sensors.getAddress(tempDeviceAddress, i);      }

 else tmpSense = tmpSenseP;            //If no error, then copy provisional data to temp variable

 

glyn.hudson's picture

Re: DS18B20 temperature sensing

Looks great. Thanks 

Paul Reed's picture

Re: DS18B20 temperature sensing

 I have built the '2 channel Mains AC: non-invasive 3.0' with a LCD display, and wondered if the addition of a few DS18B20 temperature sensors could be added to the sketch without spoiling the functions of energy monitoring?