OneWire Library
This library is available from 86Duino Coding 102 and is an 86Duino porting of Paul Stoffregen’s OneWire library.
The 1-Wire Protocol
Dallas Semiconductor (now Maxim) produces a family of devices that are controlled through a proprietary 1-wire protocol. There are no fees for programmers using the Dallas 1-Wire (trademark) drivers.
On a 1-Wire network, which Dallas has dubbed a “MicroLan” (trademark), a single “master” device communicates with one or more 1-Wire “slave” devices over a single data line, which can also be used to provide power to the slave devices. (Devices drawing power from the 1-wire bus are said to be operating in parasitic power mode. Many 1-Wire chips can operate in both parasitic and normal power modes.) Tom Boyd’s guide to 1-Wire may tell you more than you want to know… but it may also answer questions and inspire interest.
Powering OneWire devices
The chip can be powered two ways. One (the “parasitic” option) means that only two wires need go to the chip. The other may, in some cases, give more reliable operation (parasitic often works well), as an extra wire carrying the power for the chip is involved. For getting started, especially if your chip is within 20 feet of your 86Duino, the parasitic option is probably fine.
Parasite power mode
When operating in parasite power mode, only two wires are required: one data wire, and ground. At the master, a 4.7k pull-up resistor must be connected to the 1-wire bus. When the line is in a “high” state, the device pulls current to charge an internal capacitor.
This current is usually very small, but may go as high as 1.5 mA when doing a temperature conversion or writing EEPROM. When a slave device is performing one of these operations, the bus master must keep the bus pulled high to provide power until the operation completes; a delay of 750ms is required for a DS18S20 temperature conversion. The master can’t do anything during this time, like issuing commands to other devices, or polling for the slave’s operation to be completed. To support this, the OneWire library makes it possible to have the bus held high after the data is written.
Normal (external supply) mode
With an external supply, three wires are required: the bus wire, ground, and power. The 4.7k pull-up resistor is still required on the bus wire. As the bus is free for data transfer, the microcontroller can continually poll the state of a device doing a conversion. This way, a conversion request can finish as soon as the device reports being done, as opposed to having to wait 750ms in “parasite” power mode.
Note on resistors: For larger networks, you can try smaller resistors.
Addressing a OneWire device
Each 1-Wire device contains a unique 64-bit ‘rom’ code, consisting of an 8-bit family code, a 48-bit serial number, and an 8-bit CRC. The CRC is used to verify the integrity of the data. For example, the sample code, below, checks if the device being addressed is a DS18S20 temperature sensor by checking for its family code, 0x10
. To use the sample code with the newer DS18B20 sensor, you’d check for a family code of 0x28
, instead, and for the DS1822 you’d check for 0x22
.
Before sending a command to a slave device, the master must first select that device using its rom code. Alternatively, you can address a command to all slave devices by issuing a ‘skip rom’ command (This is only safe if you are sure there is only one slave device on the MicroLan.)
Please see the DS18S20 or DS18B20 datasheets for more detailed information.
Example code
#include <OneWire.h> // DS18S20 Temperature chip i/o OneWire ds(10); // on pin 10 void setup(void) { // initialize inputs/outputs // start serial port Serial.begin(9600); } void loop(void) { byte i; byte present = 0; byte data[12]; byte addr[8]; if ( !ds.search(addr)) { Serial.print("No more addresses.\n"); ds.reset_search(); return; } Serial.print("R="); for( i = 0; i < 8; i++) { Serial.print(addr[i], HEX); Serial.print(" "); } if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.print("CRC is not valid!\n"); return; } if ( addr[0] == 0x10) { Serial.print("Device is a DS18S20 family device.\n"); } else if ( addr[0] == 0x28) { Serial.print("Device is a DS18B20 family device.\n"); } else { Serial.print("Device family is not recognized: 0x"); Serial.println(addr[0],HEX); return; } ds.reset(); ds.select(addr); ds.write(0x44,1); // start conversion, with parasite power on at the end delay(1000); // maybe 750ms is enough, maybe not // we might do a ds.depower() here, but the reset will take care of it. present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad Serial.print("P="); Serial.print(present,HEX); Serial.print(" "); for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); Serial.print(data[i], HEX); Serial.print(" "); } Serial.print(" CRC="); Serial.print( OneWire::crc8( data, 8), HEX); Serial.println(); }
For more compact version of the code above, as well as for description of sensor’s command interface, please refer to Simon Tushev’s article.
The text of the 86Duino reference is a modification of the Arduino reference, and is licensed under a Creative Commons Attribution-ShareAlike 3.0 License. Code samples in the reference are released into the public domain.