welcome to the world of…

Looks like a small bulb used to indicate something unusual, like a malfunction.

1-Wire and MSP430

Filed under: Uncategorized — Tags: , , , , , , , , , , , — admin @ 2012/05/06 20:04

I bought a digital thermometer DS18B20 and I wanted to connect it to my LaunchPad. DS18B20 communicates via 1-Wire protocol. I used a bit banging to emulate the protocol. CPU speed should be over 1 MHz since the protocol requires timing almost on a microsecond level.

If you are not very familiar with 1-Wire protocol I suggest to check out an excellent analysis and illustrated guide by Ishan.

I used only two wires connection where the DS’s VDD is connected to the ground. DS’s datasheet requires an external pull up 4.7 kohm resistor on the data line but I successfully used the MSP’s internal pull up resistor.

Download

Github.

Example of communication with DS18B20

Lets connect the thermometer e.g. to pin P1.7.

#include <msp430.h>
#include "onewire.h"
#include "delay.h"
 
int main()
{
  onewire_t ow;
  int i;
  uint8_t scratchpad[9];
 
  WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
  BCSCTL1 = CALBC1_8MHZ;
  DCOCTL = CALDCO_8MHZ;
 
  ow.port_out = &P1OUT;
  ow.port_in = &P1IN;
  ow.port_ren = &P1REN;
  ow.port_dir = &P1DIR;
  ow.pin = BIT7;
 
  onewire_reset(&ow);
  onewire_write_byte(&ow, 0xcc); // skip ROM command
  onewire_write_byte(&ow, 0x44); // convert T command
  onewire_line_high(&ow);
  DELAY_MS(800); // at least 750 ms for the default 12-bit resolution
  onewire_reset(&ow);
  onewire_write_byte(&ow, 0xcc); // skip ROM command
  onewire_write_byte(&ow, 0xbe); // read scratchpad command
  for (i = 0; i < 9; i++) scratchpad[i] = onewire_read_byte(&ow);
 
  _BIS_SR(LPM0_bits + GIE);
  return 0;
}

Search ROM command

Materials for inspiration:

  • DS18B20 datasheet contains a flowchart but it doesn’t show very well the recursive nature of the algorithm
  • 1-Wire Search Algorithm from Maxim

Following example shows usage of search ROM command (0xF0). I used printf() and UART for debugging.

#include <msp430.h>
#include <stdio.h>
#include <stdint.h>
 
#include "onewire.h"
#include "delay.h"
 
/***************************************************************/
 
int putchar(int c)
{
  if (c == '\n') putchar('\r');
  while (!(IFG2&UCA0TXIFG));
  UCA0TXBUF = c;
  return 0;
}
 
/***************************************************************/
 
void uart_setup()
{
  P1SEL = BIT1 + BIT2;
  P1SEL2 = BIT1 + BIT2;
  P1DIR &= ~ BIT1;
  P1DIR |= BIT2;
  UCA0CTL1 |= UCSSEL_2;                     // SMCLK
  UCA0BR0 = 0x41;                            // 8MHz 9600
  UCA0BR1 = 0x03;                              // 8MHz 9600
  UCA0MCTL = UCBRS0;                        // Modulation UCBRSx = 1
  UCA0CTL1 &= ~UCSWRST;
}
 
/***************************************************************/
 
void search(onewire_t *ow, uint8_t *id, int depth, int reset)
{
  int i, b1, b2;
 
  if (depth == 64)
  {
    // we have all 64 bit in this search branch
    printf("found: ");
    for (i = 0; i < 8; i++) printf("%02x", id[i]);
    printf("\n");
    return;
  }
 
  if (reset)
  {
    if (onewire_reset(ow) != 0) { printf("reset failed\n"); return; }
    onewire_write_byte(ow, 0xF0); // search ROM command
 
    // send currently recognized bits
    for (i = 0; i < depth; i++)
    {
      b1 = onewire_read_bit(ow);
      b2 = onewire_read_bit(ow);
      onewire_write_bit(ow, id[i / 8] & (1 << (i % 8)));
    }
  }
 
  // check another bit
  b1 = onewire_read_bit(ow);
  b2 = onewire_read_bit(ow);
  if (b1 && b2) return; // no response to search
  if (!b1 && !b2) // two devices with different bits on this position
  {
    // check devices with this bit = 0
    onewire_write_bit(ow, 0);
    id[depth / 8] &= ~(1 << (depth % 8));
    search(ow, id, depth + 1, 0);
    // check devices with this bit = 1
    id[depth / 8] |= 1 << (depth % 8);
    search(ow, id, depth + 1, 1); // different branch, reset must be issued
  } else if (b1) {
    // devices have 1 on this position
    onewire_write_bit(ow, 1);
    id[depth / 8] |= 1 << (depth % 8);
    search(ow, id, depth + 1, 0);
  } else if (b2) {
    // devices have 0 on this position
    onewire_write_bit(ow, 0);
    id[depth / 8] &= ~(1 << (depth % 8));
    search(ow, id, depth + 1, 0);
  }
}
 
/***************************************************************/
 
int main()
{
  onewire_t ow;
  uint8_t id[8]; // 64 bits
 
  WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
  BCSCTL1 = CALBC1_8MHZ;
  DCOCTL = CALDCO_8MHZ;
  uart_setup();
 
  ow.port_out = &P1OUT;
  ow.port_in = &P1IN;
  ow.port_ren = &P1REN;
  ow.port_dir = &P1DIR;
  ow.pin = BIT7;
 
  printf("start\n");
  search(&ow, id, 0, 1);
  printf("done\n");
 
  _BIS_SR(LPM0_bits + GIE);
  return 0;
}

11 Comments »

  1. hi
    can you elaborate a bit more on the code.
    like how do you select a thermometer when you have multiple connected on the line?
    the code does not compile as is, most likely
    onewire_…_(ow)
    should be
    onewire_…_(&ow)?
    i’m a newbie with the msp430, i just received a launchpad in the mail and was testing it out.

    cheers,
    kf

    Comment by kristfin — 2012/05/08 @ 02:22

  2. kristfin: Hi! Thanks for pointing out the uncompilable code. I copied fragments of my code here and I didn’t test this example. Now it should work.
    About the ROM searching – I have those thermometers each on individual line so I only issue “skip ROM”. I’ll try ROM searching and I’ll post the result.

    Comment by admin — 2012/05/08 @ 09:39

  3. I tried the “Example of communication with DS18B20″ code and I constantly get:

    scratchpad[2] = 0x4B
    scratchpad[3] = 0×46
    the others are 0
    which is 52 celsius, in room temp. (doesn’t even change)
    18B20 has stable power.
    What could be the problem?

    Thanks,

    Comment by Zoli — 2012/07/25 @ 22:28

  4. Zoli: Hi! This is strange because at least scratchpad[5...7] must be 0xFF, 0x0C, 0×10. Did you try it with more DS18B20 samples? It might be broken. Also try only reading the scratchpad without previous temperature command sequence.

    Comment by admin — 2012/07/26 @ 07:22

  5. Using recursion might be not such a good idea taking into account small amount of memory available.
    Take a look at this http://www.pjrc.com/teensy/td_libs_OneWire.html library – it uses simple iteration.

    Comment by ss — 2013/01/09 @ 10:49

  6. Hello!
    Why are you not using function ewire_write_b()?

    Maybe function newire_write_bit() must have this body:

    void onewire_write_bit(onewire_t *ow, int bit)
    {
    DELAY_US(2); // recovery, min 1us
    onewire_line_hight(ow); //this changes
    if (bit)
    DELAY_US(6); // max 15us
    else
    DELAY_US(64); // min 60us
    onewire_line_release(ow);
    // rest of the write slot
    if (bit)
    DELAY_US(64);
    else
    DELAY_US(6);
    }

    Comment by Oleg — 2013/01/16 @ 23:46

  7. …. or maybe that:
    void onewire_write_bit(onewire_t *ow, int bit)
    {
    DELAY_US(2); // recovery, min 1us
    onewire_line_low(ow); //this changes
    if (bit)
    {
    DELAY_US(6); // max 15us
    onewire_line_high(ow); //!this changes
    }
    else
    DELAY_US(64); // min 60us
    onewire_line_release(ow);
    // rest of the write slot
    if (bit)
    DELAY_US(64);
    else
    DELAY_US(6);
    }

    Comment by Oleg — 2013/01/16 @ 23:55

  8. Oleg: What do you mean “not using function ewire_write_b()”? Where?
    OneWire protocol is time/delay based so the bit value is determined by a delay length and not the line state.

    Comment by admin — 2013/01/17 @ 15:05

  9. I learned the protocol. I used your code:
    ow.port_out = &P1OUT;
    ow.port_in = &P1IN;
    ow.port_ren = &P1REN;
    ow.port_dir = &P1DIR;
    ow.pin = BIT7;

    onewire_reset(&ow);
    onewire_write_byte(&ow, 0xcc); // skip ROM command
    onewire_write_byte(&ow, 0×44); // convert T command
    onewire_line_high(&ow);
    DELAY_MS(800); // at least 750 ms for the default 12-bit resolution
    onewire_reset(&ow);
    onewire_write_byte(&ow, 0xcc); // skip ROM command
    onewire_write_byte(&ow, 0xbe); // read scratchpad command
    for (i = 0; i < 9; i++) scratchpad[i] = onewire_read_byte(&ow);


    but ALL scratchpad[i] = 0xFF;(scratchpad[0] = 0xFF, scratchpad[1] = 0xFF …)
    Why this code does not work?
    I also replaced the code on the other:
    int id[8];

    onewire_reset(&ow);
    onewire_write_byte(&ow, 0×33); // skip ROM command
    for (i = 0; i < 9; i++) id[i] = onewire_read_byte(&ow);

    all id's also equals '0xFF'. Whats wrong?!

    Comment by Elvin — 2013/01/18 @ 21:58

  10. Elvin: Hi! There might be many places where it should go wrong – wrong delay function (depends on CPU speed), wrong thermometer connection, … What MCU do you have? What frequency?

    Comment by admin — 2013/01/19 @ 13:56

  11. Hi! My project:http://www.shelezyakin.ru/?p=104
    It’s work!

    Comment by Eugene — 2013/03/19 @ 12:41

RSS feed for comments on this post. TrackBack URL

Leave a comment