Arduino and OneWire

In preparation for my DIY BrewPi project, I picked up a few DS18B20 temperature sensors from Amazon. These sensors use something called the OneWire protocol; this allows you to connect multiple sensors so the same wire, simplifying the wiring.

That simplicity comes at a cost, and the cost in this case is complexity in code. I found a number of explanations for how “simple” it is to use these, and then they’d proceed with some example code that is 100+ lines. While not terribly challenging, I’d avoid tagging this with “simple”.

The challenge with having more than one sensor on the same data wire is knowing which sensor you’re interacting with. The steps needed in your code following something like this:

  1. Identify the addresses on the bus (commone wire used for data).
  2. Request a temperature reading from each sensor.
  3. Read the reading from each sensor.


That doesn’t sound so bad, and it’s not. However, the benefit of moving the complexity into the code is that you can use libraries to do the heavy lifting; someone else can figure out the gritty details, publish an API and an example, and we can have something simple and functional.

I’ll be using the OneWire library for finding the addresses of the sensors and the DalllasTemperature library for obtaining readings.

Finding the addresses

The first thing you need to do is find the addresses of the sensors you’ll be using. You could do this dynamically with the code, but there is a practical problem with this – I need to know which sensor is giving each reading for my project. With this contraint, there’s no getting around hardcoding the addresses.

This sketch continually loops through all addresses found on the bus and prints the 8-byte hex addresses.

#include <OneWire.h>
#define ONEWIRE_BUS 10 // data pin

OneWire onewire(ONEWIRE_BUS);

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

void loop(void){
  byte addr[8];
  int i;
  
  delay(1000);

  if (!onewire.search(addr)){
    Serial.println("No more addresses found!");
    onewire.reset_search();
    return;
  }

  // print current address
  Serial.print("Address: ");
  for (i = 0; i < 8; i++){
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }

  Serial.println();
}

Obtaining temperature readings

Once you have the addresses, the code for obtaining the temperature readings is fairly simple. Declare the number of sensors at the array of device addresses toward the top. From there, the setup function will start the serial monitor and set the resolution of the sensors. I chose 12, the most precise. It costs a small amount of extra time, which is fine for the application I have in mind.

The loop function just loops over the sensors, requests and obtains readings, and prints them to the serial monitor.

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONEWIRE_BUS 10 // Pin being used for data
#define NUM_SENSORS 2  // Number of sensors

OneWire onewire(ONEWIRE_BUS);
DallasTemperature sensors(&onewire);
float temps[NUM_SENSORS];

// List addresses of sensors here!
DeviceAddress tempSensors[NUM_SENSORS] = {
  {0x28, 0xFF, 0x50, 0x1C, 0x90, 0x15, 0x3, 0x2E}
 ,{0x28, 0xFF, 0xB,  0x13, 0x90, 0x15, 0x3, 0x51}
};

void setup(void) {

  // Start the serial monitor
  Serial.begin(9600);
  
  // Set temperature resolution
  for (int i = 0; i < NUM_SENSORS; i++)
    sensors.setResolution(tempSensors[i], 12);

}

void loop(void) {

  // Print temperature for each sensor
  for (int i = 0; i < NUM_SENSORS; i++) {
    sensors.requestTemperaturesByAddress(tempSensors[i]);
    temps[i] = DallasTemperature::toFahrenheit(sensors.getTempC(tempSensors[i]));
    Serial.print("Sensor ");
    Serial.print(i);
    Serial.print(": ");
    Serial.print(temps[i]);
    Serial.print(" ");
  }
  
  Serial.println();
  delay(1000);
}

Resources

I did a fair of amount of Googling research for figuring out how all of this works. Some of the useful sites I found:

  • Datasheet from Maxim Integrated.
  • The Arduino Playground describes the ideas behind working with a DS18B20 device.
  • The PJRC site has a nice, brief overview of the OneWire library.
  • Henry Bench’s manual provided a simple explanation and code snippet for using the OneWire and DallasTemperature libraries together.