Arduino 1-Wire communication protocol

Arduino 1-Wire is a two-way communication protocol that allows data to be transferred between Arduino and other 1-Wire compatible devices. The 1-Wire protocol is a simple but efficient way to transfer data.

The control device communicates with one or more single-wire peripheral devices via a single data line, which can also be used to power the peripheral, also known as parasitic power.

The 1-Wire protocol was developed by Dallas Semiconductor (now known as Maxim) and has since been widely used in industry and home automation. Devices using the 1-Wire protocol include e.g. temperature sensors, EEPROMs, timers and other sensors.

A popular device, for example, is the DS18B20 digital temperature sensor

TO92 housing, measuring range between 55°C and +125°C, this is displayed in 12-bit resolution on the data output pin.

It supports 3.3V and 5V operating voltage.

ad

A popular device, for example, is the DS18B20 digital temperature sensor

For Arduino 1-Wire communication, we need a 1-Wire bus, which enables e.g. communication between an Arduino and 1-Wire compatible devices. The 1Wire bus is usually connected to the supply voltage with a 4.7 ohm resistor. In the case of a longer cable and a lower supply voltage, the value of the pull-up resistor can be reduced.

In parasitic power mode, only two wires are required, a data wire and a gnd. At the controller, the data line must be pulled up with a 4.7k pull-up resistor. When the data line is high, the device charges its internal capacitor from this voltage.

For example, when a DS18S20 peripheral performs temperature conversion, the current can reach up to 1.5mA. In this case, the bus controller must hold the 1-Wire bus high to provide sufficient power until the operation is complete. The controller cannot use the 1-Wire bus during this time.

arduino ds18b20 1-wire bus with parasitic power supply

For a normal power supply, we need three wires, the data wire, the power supply and the gnd. Here again, we need to place the 4.7k pull-up resistor between the data line and the power line. In this case, the bus is free, so the microcontroller can continuously communicate with the peripheral devices.

arduino ds18b20 1-wire bus with normal power supply

Each 1-Wire device has a unique 64-bit ROM address that the Arduino must know in order to communicate with the device. The first 8 bits are the family code, then the 48-bit serial number and finally the 8-bit CRC.

The family code identifies the device type. For example, the DS18B20 family code is 0x28. CRC (Cyclic Redundancy Check) is a checksum used in communication protocols to detect errors. CRC is used by Arduino to detect communication errors.

DS18B20 digital Temperature sensor

DS18B20 digital Temperature sensor

Specification

  • Power supply range: 3.0v to 5.5v
  • Operating temperature range: -55°C to +125°C (-67°F to +257°F
  • Accuracy over the range of -10°C to +85°C: ±0.5°C
  • Cable length: 1 meter

ad

For Arduino 1-Wire communication, we need the OneWire library. If it is not already installed, install it via the Arduino library manager. The OneWire library must be inserted at the beginning of the Arduino sketch.

#include <OneWire.h>

advertising – Amazon.com

OneWire object

Creates an instance of the OneWire object, the pin used by the 1 Wire bus must be specified as a parameter. Several peripherals can be connected to the 1 Wire bus. If we still want to use more 1 Wire buses with our Arduino device, we need a OneWire copy for each pin.

OneWire myWire(pin);

Table of contents

When using the search() function, Arduino searches for all devices on the 1 Wire network. The 1 Wire protocol uses unique identifiers to identify devices. The search() function returns the IDs of all devices found on the 1 Wire bus. The “addrArray” parameter is an 8-byte array. If it finds a device, it writes its address to the array and returns true. Returns false if no more devices are found.

myWire.search(addrArray);

Table of contents

The reset_search() function is used to reset the search process to find all devices on the 1-wire bus. The function reset_search() allows the arduino to search again for peripheral devices on the 1 Wire bus.

if ( !myWire.search(addrArray)) 
{
  Serial.println("No more addresses.");
  myWire.reset_search();
  delay(250);
  return;
}

Table of contents

reset()

The reset() function resets the 1 wire bus and sends a presence query to the peripheral devices. If the devices are present, the function returns true, otherwise false. It is usually used before starting communication.

boolean present = myWire.reset();

Table of contents

select()

This function selects the device with the given ROM address on the 1 wire bus. The value specified as a parameter is a constant array containing the ROM address of the device to be selected.

After the reset, we use the select() function to select which peripheral device we want to communicate with, then all communication is done with the selected peripheral until we reset the 1 Wire bus again with the reset() function.

myWire.select(const uint8_t rom[8])

Table of contents

skip()

The skip() function skips the selection of peripheral devices. If we have only one peripheral device on the 1 Wire bus, we can avoid searching and access a device immediately.

myWire.skip();

Table of contents

write()

The write() function is used to write data to the peripheral device. The value specified as a parameter is of type byte.

write(byte mydata);

The following function is used to write the peripherals of the 1 Wire bus with parasitic power supply. It writes a byte to the peripheral and leaves the 1 Wire bus powered until the end of communication.

myWire.write(byte mydata, 1);

Table of contents

read()

The read() function reads the data from the 1 wire bus. Returns them in a variable of type byte.

byte myData = myWire.read();

Table of contents

crc8()

This function calculates the CRC8 checksum for the data given as a parameter. The data specified as a parameter must be in an array of type uint8_t, and the len parameter specifies the size of the array.

uint8_t crc = myWire.crc8(uint8_t dataArray, uint8_t len);

Table of contents

1 Wire example codes

In the following example, we read a DS18B20 temperature sensor with Arduino on the 1 Wire bus.

#include <OneWire.h>

// Arduino pin 10 is the data line of the 1 Wire bus
const char oneWirePin = 10;

// we create a OneWire object instance
OneWire oneWire(oneWirePin);

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

void loop()
{
  // We create an array for the data read from Scratchpad
  byte data[12];

  // And you also need an array to read the ROM
  byte addr[8];

  // 1 Wire bus reset,this is required before starting communication
  oneWire.reset();
  

  // Read sensor ID
  // This command allows the bus master to read 
  // the DS18B20's 8-bit family code, 
  // unique 48-bit serial number, and 8-bit CRC.
  // This command can only be used if there is only one DS18B20 on the bus.
  oneWire.write(0x33);
  for (int i = 0; i < 8; i++)
  {
    addr[i] = oneWire.read();
  }

  // CRC check
  if (OneWire::crc8(addr, 7) != addr[7])
  {
    Serial.println("Sensor ID CRC error.");
    return;
  }

  // Reset the 1 Wire bus
  oneWire.reset();

  // The Convert T [0x44] command starts the temperature conversion.
  oneWire.write(0x44);
  
  // Adding a second parameter indicates that 
  // the sensing device is powered by parasitic power.
  // oneWire.write(0x44, 1);

  // Waiting for the measurement to finish.
  // During the measurement, the ds18b20 is busy and does not accept commands
  // According to the data sheet, with a resolution of 12 bits,
  // the measurement takes a maximum of 750ms.
  delay(1000);

  oneWire.reset();

  // Scratchpad reading, 
  // the measured temperature can be found in this memory area
  oneWire.write(0xBE);
  
  for (int i = 0; i < 9; i++)
  {
    data[i] = oneWire.read();
  }

  // CRC check
  if (OneWire::crc8(data, 8) != data[8])
  {
    Serial.println("Data CRC error.");
    return;
  }

  // Calculation of temperature
  int16_t raw = (data[1] << 8) | data[0];
  byte cfg = (data[4] & 0x60);
  if (cfg == 0x00) raw = raw & ~7;
  else if (cfg == 0x20) raw = raw & ~3;
  else if (cfg == 0x40) raw = raw & ~1;
  
  // convert it into a readable form
  float celsius = (float)raw / 16.0;
  float fahrenheit = celsius * 1.8 + 32.0;


  // Then we print the temperature on the serial monitor
  Serial.print("Temperature: ");
  Serial.print(celsius);
  Serial.println(" °C");
  Serial.print(fahrenheit);
  Serial.println(" °F");
  Serial.println();
  
  delay(1000);
}
ARDUINO MEGA 2560 REV3
ARDUINO MEGA 2560 REV3 – advertising

The above code can only be used to query a single DS18B20. Let’s see what happens if we want to connect several sensors to the 1 Wire bus.

To use multiple DS18B20 sensors, we need to know each sensor’s unique address. This is important because when using 1 Wire communication the Arduino needs to know which sensor it is polling. DS18B20 sensors have a unique 64-bit address that is assigned to the sensors at the factory. To get unique addresses, we use the search() function of the OneWire library in the following example.

In the loop() cycle, we use the search(addr) function of the OneWire library to find the devices on the 1 Wire bus. The address of the found device is stored in the search() function parameter, in the addr array.

With the search() function, we search for all the devices on the bus and print the temperature data on the serial monitor in the manner known from the previous example.

Once all the devices have been found, the reset_search() function is used to restart the process.

#include <OneWire.h>

// Arduino pin 10 is the data line of the 1 Wire bus
const char oneWirePin = 10;

// we create a OneWire object instance
OneWire oneWire(oneWirePin);

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

void loop() 
{
  // We create an array for the data read from Scratchpad
  byte data[12];

  // And you also need an array to read the ROM
  byte addr[8];
  
  // the search() function searches for devices on the 1 Wire bus
  if(!oneWire.search(addr))
  {
    Serial.print("no more devices.");
	Serial.println();
	Serial.println();
	
	// ha a search() függvény befejezte a keresést 
	// reset_search() hívásával újraindítjuk a keresést
    oneWire.reset_search();
    delay(1000);
    return;
  }
  
  Serial.print("ROM: ");
  for(int i = 0; i < 8; i++)
  {
    // we print the address of the current device
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }

  // CRC check
  if (OneWire::crc8(addr, 7) != addr[7])
  {
    Serial.println("Sensor ID CRC error.");
    return;
  }
  
  // Reset the 1 Wire bus
  oneWire.reset();
  
  // we select the device on the 1 Wire bus
  oneWire.select(addr);
  
  // The Convert T [0x44] command starts the temperature conversion.
  oneWire.write(0x44);
  
  // Waiting for the measurement to finish.
  delay(1000);
  
  oneWire.reset();
  oneWire.select(addr);

  // Reading Scratchpad
  oneWire.write(0xBE);

  for(int i = 0; i < 9; i++)
  {
    data[i] = oneWire.read();
  }
  
  // CRC check
  if (OneWire::crc8(data, 8) != data[8])
  {
    Serial.println("Data CRC error.");
    return;
  }
  
  // Calculation of temperature
  int16_t raw = (data[1] << 8) | data[0];
  byte cfg = (data[4] & 0x60);
  if (cfg == 0x00) raw = raw & ~7;
  else if (cfg == 0x20) raw = raw & ~3;
  else if (cfg == 0x40) raw = raw & ~1;
  
  // convert it into a readable form
  float celsius = (float)raw / 16.0;
  float fahrenheit = celsius * 1.8 + 32.0;


  // Then we print the temperature on the serial monitor
  Serial.print("Temperature: ");
  Serial.print(celsius);
  Serial.print(" °C, - ");
  Serial.print(fahrenheit);
  Serial.println(" °F");
  
  delay(1000);
}	

Table of contents