[Home] [Downloads] [Search] [Help/forum]

Gammon Forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  Electronics
. -> [Folder]  Microprocessors
. . -> [Subject]  1-Wire Peripheral Interface - for Arduino
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

1-Wire Peripheral Interface - for Arduino

Postings by administrators only.

[Refresh] Refresh page


Posted by Nick Gammon   Australia  (21,669 posts)  [Biography] bio   Forum Administrator
Date Sat 29 Jan 2011 12:59 AM (UTC)

Amended on Mon 07 Feb 2011 05:43 AM (UTC) by Nick Gammon

Message
This post describes how the 1-Wire interface works, with particular reference to the Arduino Uno which is based on the ATmega328P microprocessor chip. A lot of the details however will be of more general interest.

The 1-Wire interface is interesting because it lets you connect a number of devices using a single wire (plus a ground return). This is because the devices are "addressable". Each device is assigned a unique (world-wide) 64-bit code (conceptually similar to a MAC address on Ethernet cards). This means that even if multiple devices are connected to the same pair of wires they can be addressed individually.

The 64-bit address includes a "family code" for example 0x28 for the temperature sensor. It also includes the CRC of the address, so there are actually 6 bytes available per family of devices for unique codes. That is 2^48 (281,474,976,710,656) devices that can be made with a unique address.

Devices which use the 1-Wire interface include temperature sensors, and other devices which can store data (eg. for tracking packages). Some 1-Wire device are mounted inside rugged metal cases (similar to a button-style battery) where the outside is ground, and the button at one end is the data pin.

More information about 1-Wire at:

http://en.wikipedia.org/wiki/One_wire


More information about the Arduino 1-Wire interface at:

http://www.arduino.cc/playground/Learning/OneWire

You can connect the devices to any digital Arduino pin, and use the OneWire library to access them.

Other protocols





Pull-up resistor and power


The data wire requires a 4.7K pull-up resistor (that is, connect it to +5v via the 4.7K resistor). This provides power to the devices, and also allows them to communicate by forcing the data wire to a "low" value.

Of course, you also need to connect the GND (ground) pins to complete the circuit.

You can optionally power the devices "parasitically" by letting them use the data wire as a power source (obviously it is interrupted during data transfers).

To allow the device to function when the data pin is low it stores a "backup" of power in its parasite power capacitor, which can store enough to tide it over during brief low pulses.

Master reset


The tricky part about the 1-Wire interface is that power, clocking and data all have to share the same wire. Thus the wire is normally held high via the 4.7K pull-up resistor, which has the side-effect of powering the devices on the wire. There is also an option in some cases to use a third wire directly connected to 5v, in case the "parasitic" use of the data wire is insufficient.

To get started: There is always a single master, the other devices are slaves. The master starts to communicate by forcing the data line low for at least 480 microseconds, to which any connected devices respond briefly with a "presence" pulse. The master then issues a command (eg. to address a particular slave), and then the slave replies.

This is an overview of getting a temperature reading from the DS18B20 temperature probe:



Zooming on on the start of the sequence we see this:




  • We start with a "reset" pulse which consists of the master pulling the data line low for at least 480 microseconds. In this case it held it for 500 microseconds.

  • Then there is a brief delay, and then all slaves connected reply with a "presence" pulse of between 60 to 240 microseconds.


Master Write


If one or more slaves are present then the master starts transmitting a command.



Bytes are 8 bits, with the least-significant bit sent first. In this case the master is sending a "match ROM" command (that is, only the matching slave is being addressed) which is 0x55 (0b01010101).

Taking the least significant bit first we expect it to send: 10101010 (which is what we see). Each bit is allocated a 60 microsecond time slot, with at least 1 microsecond recovery between each slot. In the graphic above these are shown as the purple boxes, each 60 microseconds.

The width of the pulse determines if each bit is a zero or one bit. Zooming in further we see the first couple of bits:




To write a "1" the master pulls the data line low (at point A), and then releases it back to a "high" state within 15 microseconds. The slave then has from between 15 and 60 microseconds from when the line was pulled low to read the data bit. In the first case above, the bit was "1" (sampled somewhere in the yellow box, typically around where the arrow is).

To write a "0" the master pulls the data line low (at point B), and keeps it low for the full 60 microseconds. The slave then has from between 15 and 60 microseconds from when the line was pulled low to read the data bit. In the second case above, the bit was "0" (sampled somewhere in the yellow box, typically around where the arrow is).

The code in the OneWire library (written by Jim Studt) to achieve the above is:


//
// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
void OneWire::write_bit(uint8_t v)
{
	uint8_t mask=bitmask;
	volatile uint8_t *reg asm("r30") = baseReg;

	if (v & 1) {
		cli();
		DIRECT_WRITE_LOW(reg, mask);
		DIRECT_MODE_OUTPUT(reg, mask);	// drive output low
		delayMicroseconds(10);
		DIRECT_WRITE_HIGH(reg, mask);	// drive output high
		sei();
		delayMicroseconds(55);
	} else {
		cli();
		DIRECT_WRITE_LOW(reg, mask);
		DIRECT_MODE_OUTPUT(reg, mask);	// drive output low
		delayMicroseconds(65);
		DIRECT_WRITE_HIGH(reg, mask);	// drive output high
		sei();
		delayMicroseconds(5);
	}
}



The code pretty-much agrees with the observed behaviour. To write a "1" we drive the line low for 10 microseconds, and then back high for 55 (giving a total of 65). To write "0" we simply drive the line low for the full 65 microseconds. The extra 5 microseconds over the required 60 would be the "recovery time" between write slots.

Family, Address, CRC, and Command


Zooming back out, we see after the "match ROM" code that the master is requesting a response from family 0x28 (DS18B20 family code) and the specific 48-bit (6 byte) serial number (0x000002CDADC6) which was assigned to this chip.

This is then followed by a 1-byte CRC (cyclic redundancy check) which guards against bad data due to noise on the line.

After that is another command 0xBE (read scratchpad). This is asking the sensor for the temperature reading it was previously commanded to take (not shown here).




Response from sensor


Now the temperature sensor replies to the 0xBE (read scratchpad) command. The next sceenshot starts with that command, and shows the response:




  • First two bytes: 0x01, 0x44

    Combined this makes 0x0144 (324 in decimal). This is the temperature it read. According to the data sheet you multiply that by 0.0625 to get the temperature in Celsius (in this case, 20.25 which sounds about right).

  • Next 6 bytes, various other features like an alarm, and reserved bytes.

  • Last (ninth) byte: CRC check, to confirm that the data was not corrupted.


The code from the DallasTemperature.cpp file to do the above reading of the temperature is as follows:


// read device's scratch pad
void DallasTemperature::readScratchPad(uint8_t* deviceAddress, uint8_t* scratchPad)
{
  // send the command
  _wire->reset();
  _wire->select(deviceAddress);
  _wire->write(READSCRATCH);     //    0xBE 
 
  // read the response
  
  scratchPad[TEMP_LSB] = _wire->read();         // byte 0: temperature LSB
  scratchPad[TEMP_MSB] = _wire->read();         // byte 1: temperature MSB
  scratchPad[HIGH_ALARM_TEMP] = _wire->read();  // byte 2: high alarm temp
  scratchPad[LOW_ALARM_TEMP] = _wire->read();   // byte 3: low alarm temp
  scratchPad[CONFIGURATION] = _wire->read();    // byte 4
  scratchPad[INTERNAL_BYTE] = _wire->read();    // byte 5
  scratchPad[COUNT_REMAIN] = _wire->read();     // byte 6
  scratchPad[COUNT_PER_C] = _wire->read();      // byte 7
  scratchPad[SCRATCHPAD_CRC] = _wire->read();   // byte 8: CRC

  _wire->reset();
}


Master read


Below is the timing for the first byte (0x44 or 0b01000100). Since we get the least significant bit first, we expect to see 00100010.



The timing for master reading is a bit different from that for master writing:



To read from the slave, the master briefly takes the wire low (for a minimum of 1 microsecond), and then releases control. The slave can then choose to keep the line low (to signal a zero) by forcing the wire low itself, or letting it float back high by not doing anything.

In the example above the master pulls the wire low (small yellow box). The slave then immediately forces it low itself. The master then has to read the value within 15 microseconds of when it pulled the wire low (the green box).

For the second bit (the "1" bit) the master pulls the wire low and releases it. The pull-up resistor then pulls it back to a "1", which the master then reads, again within 15 microseconds.

The code in the OneWire library to achieve the above is:



//
// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
uint8_t OneWire::read_bit(void)
{
	uint8_t mask=bitmask;
	volatile uint8_t *reg asm("r30") = baseReg;
	uint8_t r;

	cli();
	DIRECT_MODE_OUTPUT(reg, mask);
	DIRECT_WRITE_LOW(reg, mask);
	delayMicroseconds(3);
	DIRECT_MODE_INPUT(reg, mask);	// let pin float, pull up will raise
	delayMicroseconds(9);
	r = DIRECT_READ(reg, mask);
	sei();
	delayMicroseconds(53);
	return r;
}


Again, this pretty-much agrees with the spec. The line is driven low for 3 microseconds, and then the code waits another 9 microseconds, which means it is sampled 12 microseconds in from being driven low. The spec recommends sampling towards the end of the 15 microsecond window, which is what this does. A further delay of 53 microseconds adds up to a total of 65 microseconds for the read slot.

Timing


Timing varies a bit depending on what you are doing. However as an example:


  • Reset, Skip ROM command (0xCC), Read Temperature (0x44): 2.16 milliseconds

  • Reset, Match ROM command (0x55), 64-bit address (family code, 6 unique bytes, CRC), Read Scratchpad command (0xBE), data (8 bytes plus CRC), reset: 12.5 milliseconds


The second case (reading the temperature) took 12.5 ms to send/receive 19 bytes, which averages out to 657 microseconds per byte. Thus you could say the protocol can handle 1520 bytes per second.

Timing for a single data byte indicates (in my test case) that it took 559 microseconds (0.559 milliseconds) to transfer one byte, so that is a rate of 1789 bytes per second.

However it is probably more meaningful to talk about how many "readings" you could take in a second, so since querying one device for its temperature reading took 12.5 ms, you could say that you could take around 462 temperature readings per second.


Device Search


Since devices are allocated a 64-bit unique code, and you eventually want to address them individually, it is necessary for the master to find out the addresses of the connected devices. It does this by using a rather complex algorithm (documented on the Dallas Semiconductor web site). Basically the master works its way through each bit of the 64 possible bits in the address, asking in turn for any slaves which have a zero in that position, and then a one in the same position, to reply by driving the line low. If the line stays high for any case the master knows that bit is not used by any slave. If it is driven low then one or more slaves are using it. By a process of elimination it can quickly find out which bits are used overall, and derive a table of slave addresses.

Arduino Library



#include <OneWire.h>


Applications


The temperature sensors alone are certainly an interesting application. Just by running a pair of wires around your house you could tap into it with multiple temperature sensor devices. I am uncertain about the maximum cable run, or maximum number of sensors, but the OneWire library claims to have tested with 12 sensors. Over a long cable run it might be worthwhile to have a third wire to provide power to the devices to avoid them all having to use the "parasitic" power option which presumably eventually places too much load on the wire for reliable operation.

The sensors themselves are quite tiny as you can see from this photo of one adjacent to an ordinary match:



- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


14,649 views.

Postings by administrators only.

[Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at FutureQuest]