Illustrated guide to interfacing Maxim OneWire (1-Wire) devices DS18B20 on TI Launchpad MSP-EXP430G2

Print Friendly

Maxims proprietary one wire devices have been popular with hobbyist for a long time.  The small and incredibly accurate (for hobbist) DS18B20 and DS18S20 series of temperature sensors from this family of devices have been used on many platforms.

I too have used this temperature sensor, DS18B20 in particular in some of my hobby projects. But on all occasions the code routines that I used to interface the sensors, had been the hard-work of somebody else. However that did not matter as it solved my immediate purpose then. Comprehensive and easy to use routines are available for AVR, PICs and the Arduino Community so why rack your brains!

However as I ‘made the switch’ to TI MCU, I realised that there was no out of the box support for these devices and libraries /code snippets available were either arcane (in assembly) or difficult to understand and implement. Initially in my earlier exploits I used to just gloss over the sensors datasheet. So this time around, making an exception, I decided to read through the datasheet and try to make sense of the language and code routines all by your own self.

Thus coming to the moot point of the post, in this post I shall try to explain how to read a DS18B20 sensor using a TI Launchpad running MSP430G2452. This guide has been written to read only for single one wire device on bus. Do not expect me to give all ‘gyaan’ (knowledge) on the sensor in this post. Read the datasheet yourself to understand the specs. 

Hardware :TI MSP430G2 Launchpad running MSP430G2452, Maxim DS18B20,  4.7K ohm resistor
Software :Code Composer Studio Version: 4.2.3.00004
Test Equipment: Rigol 1052e DSO
Wiring The Sensor:

Launchpad Interface Matrix:

MCU Port Port Pin DS18B20 Pin
P2 0 GND
P2 1 Vdata
P2 2 VCC

Generation of delay period: A look at the datasheet will reveal that timing is of essence for establishing communication with limits being defined. So getting and setting up your delay period becomes an important task. The delay period varies from 1 ?s to 750ms.  Hence the minimum granularity for the delay is 1 ?s. So the clock speed of the MCU has to be in excess of 1MHz (1/1 ?s). MSP430G2452 is a fairly capable chip and a big brother of the MSP430 lineup and executes one instruction per clock cycle. In absence of any external crystal on the Launchpad in stock mode, we shall use the internal dco in the MCU to generate the required delays.

Be advised though , due to code overheads, in reality an instruction (as written in HLL) can take more than one clock cycle and also an internal clock can never replace an external crystal, so expect drifts in timings when you see the signals on oscilloscope.   i.e a delay of 16 cycles at 16MHz will not necessarily give you a 1 ?s delay, in reality it will give you more. However we can live with this till we are in the specified limits (they are fairly large). Following is the code snippet of functions  I have used to generate a milli-second and micro-second delay.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void delay_ms(int ms)
{
while (ms--)
{
__delay_cycles(16000); // set for 16Mhz change it to 1000 for 1 Mhz
}

}

void delay_us(int us)
{
while (us--)
{
__delay_cycles(8); // set for 16Mhz change it to 1000 for 1 Mhz
}

}

Transaction Sequence to read from a single sensor on bus:

There are three basic requests , as with any bidirectional  communication request.

  1. Initiation. This request establishes and acknowledges presence of both  (Master and Slave) devices on the bus. This is akin to saying ‘Hello’.
  2. Write Data. Either master or slave writes data on bus.
  3. Read DataEither master or slave read data from the  bus.

The Master in this case is the MCU on launchpad and the Slave is the 1-Wire device. It should be noted that all communication on the bus is half-duplex i.e there is only one talker on bus at any given point in time.

Caveats: Before I tread ahead, here are some things that I learnt the hard way and I am sharing so that you dont have to relearn them the harder way.

  • As we have a pull up resistor on data pin of the sensor (DQ), the bus floats high at the VCC potential, always. This is the idle state of the bus when it is not transacting.
  • When Master/Slave release the bus, it should float back to VCC.
  • Pulling the bus high to VCC is not the same as releasing the bus. I learnt this by burning the midnight oil.
  • Master on the bus is the Master, period. It initiates all requests, including bit wise transmission of data by slave.

I shall now attempt to explain each of them with a signal snapshot from oscilloscope and a code snippet.

Initiation: Initiation or Initialization as it is referred to in the datasheet consists of a reset pulse transmitted by the bus master. If there is a slave device on the bus (properly connected) it acknowledges its presence  to the bus master by transmitting a presence pulse.  A presence pulse is generated by the slave by pulling the bus low,

Master initiates a reset request by pulling the bus low for 480us. After that he releases the bus and waits for  60us-100us to read for a presence pulse. In the interim , after the Master releases the bus the Salve waits for 15 to 60 us before its pulls the bus low. The slave holds the bus low of 60 to 240 us  before it releases the bus again.

Following is an annotated screen capture of such a transaction from oscilloscope.

Following code will accomplish such a request.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned int ResetDS1820 ( void )
{
/* Steps to reset one wire bus
* Pull bus low
* hold condition for 480us
* release bus
* wait for 60us
* read bus
* if bus low then device present set / return var accordingly
* wait for balance period (480-60)
*/

int device_present=0;
DS1820_LO(); // Drive bus low
delay_us (480); // hold for 480us
DS1820_DIR &= ~DS1820_DATA_IN_PIN; //release bus. set port in input mode
delay_us(60); //wait for slave to pull bus low
if(DS1820_IN & DS1820_DATA_IN_PIN)
{
device_present=0;
}
delay_us (480); //wait for 480us
return device_present;
}

Since earlier I mentioned about that releasing bus is not as same as pushing the bus high, illustrated below is a screen shot of a reset request initiated by a master, but the difference being instead of releasing the bus and letting the bus float high, I pulled up the bus programmatically, the result below is self explanatory

Incorrect Reset Pulse

Bit-Banging: Before we start exchanging  pleasantries on the bus we need to get our ones and zeros correct . In One Wire communication parlance  bit wise transmission and reception is done in a concept of slots . So there is a read slot and a write slot. Master initiates slots for its own transmission and for slaves transmission.

Depicted below is an illustration of Write Slot. Remember duration of each individual write slot (either zero or one) is 60us(tSlot)

Illustration of Write Slots

Write 0 Slot (Master Transmits Bit Wise Zero)Master pulls the bus low and just holds low for 60us and then releases it.  In the interim after about 15us after Master pulls the bus low, the bus is sampled by the slave, since we are holding the bus low, it reads a logical zero.

Write 1 Slot (Master Transmits Bit Wise One) Master pulls the bus low and releases the bus within 15us (that the period after which the slave sample the bus). After pulling the bus low, after 15us the slave samples the bus and assuming that the master has released the bus, the bus is now floating high and the slave reads a logical zero. However since the slot window is 60us and one 1us window for recovers , the Master waits for the balance period before it exits the function.

In the screen capture above the blue trace is the Write 1 slot also shown is the yellow trace which shows the total slot windows width for the sake of comparison.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void WriteZero(void)
{
/*Steps for master to transmit logical zero to slave device on bus
* pull bus low
* hold for 60us
* release bus
* wait for 1us for recovery
*/

DS1820_LO(); // Drive bus low
delay_us (60); //sample time slot for the slave
DS1820_DIR &= ~DS1820_DATA_IN_PIN; //release bus. set port in input mode
delay_us (1); //recovery time slot

}
void WriteOne(void)
{
/*Steps for master to transmit logical one to slave device on bus
* pull bus low
* hold for 5us
* release bus
* wait for 1us for recovery
*/

DS1820_LO(); // Drive bus low
delay_us (5);
DS1820_DIR &= ~DS1820_DATA_IN_PIN; //release bus. set port in input mode
delay_us (55); //sample time slot for the slave
delay_us (1); //recovery time slot

}

Reading data from the Slave:Now we shall come to the second half of bit-banging. This method deals with Master reading data put on bus by the Slave device i.e Slave Tx and Master Rx. As as I mentioned above the Master initiates all bit wise data transactions on the bus. So how does master come into picture when slave is transmitting. Consider Slave to be the cow and Master to be the Milkman or a Maid (;-p) . So the Master milks the cow. Also it is important to note that slave does not put data on bus on its whim and fancy but has to be explicitly addressed and commanded to do so. We shall deal with this a subsequently . For the time being assume that the Slave has been commanded to put data on bus. Since the master has issued the command the master is aware that there is going to be data available on the bus.

So in order to retrieve the data from the slave the master issues a read slot. It does so by pulling the bus low for a short period and then releasing the bus.

Illustration of Read Slot

As with write slots, all read time slots are of a minimum of 60µs in duration with a minimum of a 1µs recovery time. So slot width is 61us.

Read Slot (Slave Transmits Bit Wise Zero or One)Master issues as read slot by pulling the bus low for a minimum of 1us and then releases it. If the slave wants to transmit Zero, it will continue to hold the bus low for the slot window period. If the slave is transmitting One, once the master releases the bus, the slave will allow the bus to float high and will take no action.  Also data transmitted by 1-Wire device on the bus is only valid for 15us after the bus has been pulled low by the Master. So in effect to read the data the master has to poll the bus within 15us of the bus being pulled low.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
unsigned int ReadBit (void)
{

/*Steps for master to issue a read request to slave device on bus aka milk slave device
* pull bus low
* hold for 5us
* release bus
* wait for 45us for recovery (46us+5us=61us)
*/

int bit=0;
DS1820_LO(); // Drive bus low
delay_us (5); //hold for 5us
DS1820_DIR &= ~DS1820_DATA_IN_PIN; //release bus. set port in input mode
delay_us (10); //wait for slave to drive port either high or low
if(DS1820_IN & DS1820_DATA_IN_PIN) //read bus
{
bit=1; //if read high set bit high
}
delay_us (46); //recovery time slot
return bit;

}

Till now we saw how to initialize communication between Master and Slave and do bit-banging and this is almost 80% of the battle.  The next logical step is  to do byte wise communication, thats where the juice lies.
Commands for the One wore bus as one byte(8bit) in data width and come in two flavours

      1. ROM Commands
      2. Function Commands

ROM Commands:  If you have gone through the datasheet you will realise that you can have multiple one wire devices on a single bus and each device has a unique, addressable 64 bit serial code (ROM Code), which allows multiple DS18B20s to function on the same 1-Wire bus. Thus the ROM commands are used primarily to either search devices on a bus or target a specific device on bus to push or pull data to/from it  or if any device on the bus has experienced an alarm condition.There are five ROM commands for DS18B20

  • Search ROM: This command is used to search devices on the one wire bus. Will not be discussed here as we are going to use only one device on bus and hencenot going to use it.
  • Skip ROMWe shall be using this command. Used when there is only one device on the bus. Instructs the Slave that it shall not be uniquely addressed.
  • Match ROM: Not used in this guide. Master uses this command to target a specific device in a multi-node scenario.
  • Read ROM: Not Used.  Useful to read ROM code from a device. Used only in a single device scenario.
  • Alarm Search: Not Used. The command allows the master device to determine if any DS18B20s has experienced an alarm condition during the most recent temperature conversion. Usage similar to Search ROM.

Function Commands:  These commands allow the master to write to and read from the DS18B20’s scratchpad memory, initiate temperature conversions and determine the power supply mode. It is important to note that the master can issue one of the DS18B20 function commands.  Following are list of function commands relevant to DS18B20

  • CONVERT T: Used by Master to instruct the Slave to initiate temperature conversion. If the DS18B20 is powered by an external supply, the master can issue read time slots after the Convert T command and the DS18B20 will respond by transmitting a 0 while the temperature conversion is in progress and a 1 when the conversion is done. Temperature conversion takes a minimum of 750ms .. yes that is millisecond , you read that correctly. So after issuing the command the master has to wait for minimum 750ms before its polls the bus for slave’s reply.
  • WRITE SCRATCHPAD: Not Used. This command allows the master to write 3 bytes of data to the DS18B20’s scratchpad.
  • READ SCRATCHPAD: This command allows the master to read the contents of the scratchpad. Data is read LSB first. The master may issue a reset to terminate reading at any time if only part of the scratchpad data is needed. He does so by issuing a reset command.
  • COPY SCRATCHPAD: This command copies the contents of the scratchpad in the Slave device to EEPROM also in the Slave device.
  • RECALL E2: Not Used. This command recalls the alarm trigger values and configuration data from EEPROM and places the data in bytes 2, 3, and 4, respectively, in the scratchpad memory.
  • READ POWER SUPPLY: Not Used. The master device issues this command followed by a read time slot to determine if any DS18B20s on the bus are using parasite power (Read datasheet to understand what it means).

Note that The master can interrupt the transmission of data by Slave at any time by issuing a Reset Command. Below are some screen shots of  a byte full of data transmission in progress

Screen Captire of Skip ROM Command

As you can see in the above screen shot the data is being transmitted LSB first. The data being transmitted is 0xCC

So in a nutshell we are going to issue the following commands to read the temperature from the sensor

  • Reset / Init
  • Skip ROM
  • Convert T
  • Read Scratchpad
As per one-wire scheme of things it has to be noted that after issuing a ROM command a reset command is required to be issued. So the sequence of commands will now look like

  • Reset
  • Skip ROM
  • Convert T
  • Wait for 750us
  • Reset
  • Skip ROM
  • Read Scratchpad
  • Master loops a read slot to receive data from the device LSB First

Interpreting Data: Once data is received bit wise by the master, the next step is to digest the data in such a way that you get current temperature read by the device. The default resolution of temperature data at power-up is 12-bit and is calibrated in Celsius and not Fahrenheit  . However options are available to get data at lower resolutions at 9,10,11 bits corresponding to increments of 0.5°C, 0.25°C, 0.125°C, and 0.0625°C, respectively.

. But I am sticking with higher 12 bit resolution here.

The temperature data is stored as a 16-bit sign-extended two’s complement number in the temperature register in the slave device with last 4 bits of the MSB (15,14,13,12) containing the sign bit for the reading. This is useful while reading sub-zero temperatures. For positive temperatures the sign bit is not set but is set to 1 for sub zero temperatures. Lets attempt to interpret data using a screen shot below

The blue trace is the data trace while the yellow trace is the byte window width (just for reference. Interpreting bits from the left and side of the screen we get

LSB End 0010001001000000  MSB End

 Since I had mentioned earlier data is read LSB first we will have to flip it around to get it MSB first

MSB End 0000001001000100 LSB End

Converting the above bit pattern to a 16 bit hex we get the value of 0x244h = 580
As the bit resolution is 0.0625 deg/bit in 12 bit mode we will multiply the value by 0.0625
Hence 580*0.0625=36.25 C which is rightly the temperature here where I stay. Yes thats indoor temperature.

Mission Accomplished.
You can download the complete source here (code is for MSP430G2452, you can adapt it for any MSP430MCU)
David also has made a much more capable library for One Wire devices  here
Ishan Karve

About Ishan Karve

Ishan Karve is just an every day normal guy next door who happens to be an Electronics Engineer by profession and dabbles with PHP, Javascript, C++ and python. His interests vary as seasons change.. they change from astronomy to soul searching. This site is just a reflection of what he does to keep his mind engaged when he is not occupied by work and family. He is an extremely objective guy and is always ready for some good arguments.. of course over a glass of 40% proof alcohol.
This entry was posted in DIY, Electronics, MSP-GCC, MSP430 and tagged , , , , , , , , . Bookmark the permalink.

19 Responses to Illustrated guide to interfacing Maxim OneWire (1-Wire) devices DS18B20 on TI Launchpad MSP-EXP430G2

  1. David says:

    Nice analysis. I’ve made similar OneWire library with example of search ROM command: http://www.smallbulb.net/2012/238-1-wire-and-msp430

  2. Bela says:

    I tried your code, but I can’t get it work, the red LED blinks briefly when it’s reading.
    But the float variable always remains 0.0.
    The Pins are set correctly, 18b20 power is ok, MCU freq is ok, header delay checked.
    I have run out of options.

    Thank you,

    • Ishan Karve Ishan Karve says:

      Have you made any changes to the code. Also have you connected a 4.7k resistor between the VCC and Dq pin of the sensor?

      • Rodrigo says:

        I’m getting the same issues. I’m using the Launchpad with a MSP430G2553. It isn’t working with both the original code or when changing the headers to msp430g2553.h.

  3. Eugene says:

    Hello, Ishan. Thank fo your post, but your code did not work. I modified it, now the code works even without an external pull-up resistor. It does not work just search for devices on the bus.

    • Ishan Karve Ishan Karve says:

      Thanks Eugene. I shall clarify on the issue.. I am a bit busy on other project.. I shall be able to clarify and demonstrate my code shortly..
      BTW thanks for sharing your code.

  4. emrullah says:

    MSP430 sends me with the sample applications.

  5. Ant says:

    Karve,

    Interesting and good explanation, just starting out with the MSP430 so will use this in future.

    Ant

  6. Roger says:

    Many thanks for this guide to the DS18B20 temperature sensor. In order to get it to work, I had to use the following ports on the MSP430G to use your code:
    P2.1 to Pin 1 (GND) 0f the DS18B20
    P2.4 to Pin 2 (DQ) ”
    P2.3 to Pin 3 (VCC) ”

    I added a floating point to ascii conversion routine, a Celsius to Fahrenheit conversion routine and a display similar to the common HD44780. I now have a device that displays the temperature in both Fahrenheit and Celsius – cool!

    Thanks again!

  7. Mustafa says:

    Thank you .

  8. John Scott says:

    Best info I’ve seen re ds18b20 interfacing, but in your 2nd (ie detailed) version of reading temperature you say 750 usec; it should be 750 msec. You also earlier say “hencenot” when you mean “hence not”. As well, it would be helpful include the hex commands, eg to say “CONVERT T: (0×44) Used by Master..” instead of “CONVERT T: Used by Master..”.

Leave a Reply

Your email address will not be published. Required fields are marked *

* Copy This Password *

* Type Or Paste Password Here *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>