chipKIT® Development Platform

Inspired by Arduino™

Last edit: 2021-03-21 22:34 by Majenko

OneWire

OneWire
Quick Look
Hardware (External hardware)
Include OneWire.h

The OneWire library allows the chipKIT to communicate with 1-Wire devices.

  1. Detailed Introduction

  2. Wiring

  3. Introductory Programs

    1. DS18x20_Temperature

    2. DS250x_PROM

  4. Full library usage

    1. OneWire

      1. Constructors

        1. OneWire( uint8_t pin)

      2. Public Functions

        1. reset(void)

        2. select( uint8_t rom[8])

        3. skip(void)

        4. write(uint8_t v, uint8_t power = 0)

        5. write_bytes(const uint8_t *buf, uint16_t count, bool power = 0)

        6. read(void)

        7. read_bytes(uint8_t *buf, uint16_t count)

        8. write_bit(uint8_t v)

        9. read_bit(void)

        10. depower(void)

        11. reset_search()

        12. search(uint8_t *newAddr)

        13. crc8( uint8_t *addr, uint8_t len)

        14. check_crc16(uint8_t* input, uint16_t len, uint8_t* inverted_crc)

        15. crc16(uint8_t* input, uint16_t len)

  5. External Links

Detailed Introduction

1-Wire is a bus communications protocol much like I2C but with slower data rates. 1-Wire was developed by Dallas Semiconductor who is now known as Maxim. A 1-Wire bus can have one host/master device and one or many slave devices. Each 1-Wire device contains a unqiue 64bit address which has been burned into ROM at the factory and this address cannot be altered.

Wiring

300px Despite the name 1-Wire requires 3 wires (Power, Ground, and Signal). Power consumption should be taken into consideration when deciding how to power your 1-Wire device. Be sure not to exceed the power ratings of your power supply.

Introductory Programs

DS18x20_Temperature

This example searches for a 1-Wire devices on the bus and prints the address to the serial console window. It then prints the part number which is indicated by the first byte in the address. It then uses the address to select the device and obtain a temperature reading from it. This example supports DS18S20, DS18B20, and DS1822 Temperature devices.

#include <OneWire.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire  ds(10);  // on pin 10

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

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;
  
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      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("  Data = ");
  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();

  // convert the data to actual temperature

  unsigned int raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // count remain gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
    // default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
}

DS250x_PROM

This sketch communicates with the DS250x family of PROMs (programmable read only memory). It shows a method of skipping the search phase of finding 1-wire devices and instead assumes that we only have a single slave device and also assumed that we know it's connected. The example calculates a CRC and stores it in the PROM. Then reads it back and prints it to the serial console.

/*
DS250x add-only programmable memory reader w/SKIP ROM.
 
 The DS250x is a 512/1024bit add-only PROM(you can add data but cannot change the old one) that's used mainly for device identification purposes
 like serial number, mfgr data, unique identifiers, etc. It uses the Maxim 1-wire bus.
 
 This sketch will use the SKIP ROM function that skips the 1-Wire search phase since we only have one device connected in the bus on digital pin 6.
 If more than one device is connected to the bus, it will fail.
 Sketch will not verify if device connected is from the DS250x family since the skip rom function effectively skips the family-id byte readout.
 thus it is possible to run this sketch with any Maxim OneWire device in which case the command CRC will most likely fail.
 Sketch will only read the first page of memory(32bits) starting from the lower address(0000h), if more than 1 device is present, then use the sketch with search functions.
 Remember to put a 4.7K pullup resistor between pin 6 and +Vcc
 
 To change the range or ammount of data to read, simply change the data array size, LSB/MSB addresses and for loop iterations
 
 This example code is in the public domain and is provided AS-IS.
 
 Built with Arduino 0022 and PJRC OneWire 2.0 library http://www.pjrc.com/teensy/td_libs_OneWire.html
 
 created by Guillermo Lovato <glovato@gmail.com>
 march/2011
 
 */

#include <OneWire.h>
OneWire ds(6);                    // OneWire bus on digital pin 6
void setup() {
  Serial.begin (9600);
}

void loop() {
  byte i;                         // This is for the for loops
  boolean present;                // device present var
  byte data[32];                  // container for the data from device
  byte leemem[3] = {              // array with the commands to initiate a read, DS250x devices expect 3 bytes to start a read: command,LSB&MSB adresses
    0xF0 , 0x00 , 0x00   };       // 0xF0 is the Read Data command, followed by 00h 00h as starting address(the beginning, 0000h)
  byte ccrc;                      // Variable to store the command CRC
  byte ccrc_calc;

  present = ds.reset();           // OneWire bus reset, always needed to start operation on the bus, returns a 1/TRUE if there's a device present.
  ds.skip();                      // Skip ROM search

  if (present == TRUE){           // We only try to read the data if there's a device present 
    Serial.println("DS250x device present");
    ds.write(leemem[0],1);        // Read data command, leave ghost power on
    ds.write(leemem[1],1);        // LSB starting address, leave ghost power on
    ds.write(leemem[2],1);        // MSB starting address, leave ghost power on

    ccrc = ds.read();             // DS250x generates a CRC for the command we sent, we assign a read slot and store it's value
    ccrc_calc = OneWire::crc8(leemem, 3);  // We calculate the CRC of the commands we sent using the library function and store it

    if ( ccrc_calc != ccrc) {      // Then we compare it to the value the ds250x calculated, if it fails, we print debug messages and abort
      Serial.println("Invalid command CRC!");
      Serial.print("Calculated CRC:");
      Serial.println(ccrc_calc,HEX);    // HEX makes it easier to observe and compare
      Serial.print("DS250x readback CRC:");
      Serial.println(ccrc,HEX);
      return;                      // Since CRC failed, we abort the rest of the loop and start over
    }
    Serial.println("Data is: ");   // For the printout of the data 
    for ( i = 0; i < 32; i++) {    // Now it's time to read the PROM data itself, each page is 32 bytes so we need 32 read commands
      data[i] = ds.read();         // we store each read byte to a different position in the data array 
      Serial.print(data[i]);       // printout in ASCII
      Serial.print(" ");           // blank space 
    }
    Serial.println();
    delay(5000);                    // Delay so we don't saturate the serial output
  }
  else {                           // Nothing is connected in the bus 
    Serial.println("Nothing connected");
    delay(3000);
  }
}

Full library usage

OneWire

Constructors


OneWire( uint8_t pin)

OneWire( uint8_t pin);

pin is the chipKIT pin number connected to the 1-Wire Signal pin.

Public Functions


reset(void)

uint8_t reset(void);

Perform a 1-Wire reset cycle. Returns 1 if a device responds with a presence pulse. Returns 0 if there is no device or the bus is shorted or otherwise held low for more than 250uS.

select( uint8_t rom[8])

void select( uint8_t rom[8]);

Issue a 1-Wire rom select command, you do the reset first. rom is set to the address of the device.

skip(void)

void skip(void);

Issue a 1-Wire rom skip command. This allows you to address all devices on the bus regardless of their address.

write(uint8_t v, uint8_t power = 0)

void write(uint8_t v, uint8_t power = 0);

Write a byte. If 'power' is one then the wire is held high at the end for parasitically powered devices. You are responsible for eventually depowering it by calling depower() or doing another read or write.

write_bytes(const uint8_t *buf, uint16_t count, bool power = 0)

void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);

Same as above but writes multiple bytes from a buffer.

read(void)

uint8_t read(void);

Read a byte.

read_bytes(uint8_t *buf, uint16_t count)

void read_bytes(uint8_t *buf, uint16_t count);

Read multiple bytes into a buffer.

write_bit(uint8_t v)

void write_bit(uint8_t v);

Write a bit. The bus is always left powered at the end, see note in write() about that.

read_bit(void)

uint8_t read_bit(void);

Read a bit.

depower(void)

void depower(void);

Stop forcing power onto the bus. You only need to do this if you used the 'power' flag to write() or used a write_bit() call and aren't about to do another read or write. You would rather not leave this powered if you don't have to, just in case someone shorts your bus.

reset_search()

void reset_search();

Clear the search state so that if will start from the beginning again.

search(uint8_t *newAddr)

uint8_t search(uint8_t *newAddr);

Look for the next device. Returns 1 if a new address has been returned. A zero might mean that the bus is shorted, there are no devices, or you have already retrieved all of them. It might be a good idea to check the CRC to make sure you didn't get garbage. The order is deterministic. You will always get the same devices in the same order.

crc8( uint8_t *addr, uint8_t len)

static uint8_t crc8( uint8_t *addr, uint8_t len);

Compute a Dallas Semiconductor 8 bit CRC, these are used in the ROM and scratchpad registers.

check_crc16(uint8_t* input, uint16_t len, uint8_t* inverted_crc)

static bool check_crc16(uint8_t* input, uint16_t len, uint8_t* inverted_crc);

Compute the 1-Wire CRC16 and compare it against the received CRC.

Parameter Definitions

@param input - Array of bytes to checksum.

@param len - How many bytes to use.

@param inverted_crc - The two CRC16 bytes in the received data. This should just point into the received data, not at a 16-bit integer.

@return True, iff the CRC matches.

crc16(uint8_t* input, uint16_t len)

static uint16_t crc16(uint8_t* input, uint16_t len);

Compute a Dallas Semiconductor 16 bit CRC. This is required to check the integrity of data received from many 1-Wire devices. Note that the CRC computed here is not what you'll get from the 1-Wire network, for two reasons:

  1. The CRC is transmitted bitwise inverted.

  2. Depending on the endian-ness of your processor, the binary representation of the two-byte return value may have a different byte order than the two bytes you get from 1-Wire.

Parameter Definitions

@param input - Array of bytes to checksum.

@param len - How many bytes to use.

@return The CRC16, as defined by Dallas Semiconductor.

External Links