Plug and Play DS61S20 Temperature sensors

Hi All

I thought I might post up some code I developed which automatically stores the DS61S20 serial numbers found into the EEPROM so you never need to manually work out and hard code sensor serial numbers. As an added bonus, the code supports printing temperatures to the COM port in RoadRunner format so those of you using this Car PC frontend can substitute the Arduino for the RoadRuner temperature sensor module.

Here is how it works. first you need to define the EEPROM offset to start storing sensor data at. You can leave this at 0 if you don’t use any EEPROM for other things otherwise, set it to the first byte of unused storage

#define EEPROM_OFFSET 0

If you want to see the familiar debug code from the one wire library, #define debug:

#define DEBUG

If you want to output the sensor data in Roadrunner format where sensors are numbered from 1 instead of 0 and set the COM port to the 2400 baud) enable this #define (but then you can’t monitor the outoput in the Auduino IDE)

#define ROADRUNNER_COMPATIBLE

So the code looks in the EEPROM and steps through looking for a match with the serial number returned by the one wire and returns a sensor number from 0 to about 62 (or less if you have used up some EEPROM) using this procedure:

int FindSensor(byte *serialnum)
// Returns -1 if the sensor is not found in EEPROM or there are no readings stored
{
  int j=0, i=0;
  int SerialOffset, found;

  ENumSensors = EEPROM.read(EEPROM_OFFSET);
  if(ENumSensors == 0)
    return(-1);    // Sensor Not found
  i = 0;
  found = 0;
  do{   
    SerialOffset = (i * 8) + 1;
    for( j = 0; j < 8; j++) {
      ESensorSerial[j] = EEPROM.read(SerialOffset); 
      SerialOffset++;
    }
    if(!memcmp(&ESensorSerial, serialnum, 8)){
      return i;
    }
    i++;  
  }while(i <= ENumSensors);
  return -1;    // Will only get here if the sensor is not found

If the sensor is not found, you can add it using this procedure:

byte AddSensor(byte *serialnum)    // Returns SensorNumber added
{
  int j=0;
  
  int SerialOffset;
  ENumSensors = EEPROM.read(EEPROM_OFFSET);
  SerialOffset = EEPROM_OFFSET + (ENumSensors * 8) + 1;
  if (SerialOffset > MEM_LIMIT){      // No more room left in memory
    return 0xFF;
  }  
  Serial.print("Adding Sensor, Serial Offset = ");
  Serial.print(SerialOffset,DEC);
  Serial.print(" ");
  
  for( j = 0; j < 8; j++) {
    EEPROM.write(SerialOffset, *serialnum ); 
    SerialOffset++;
    serialnum++;
  }
  ENumSensors++;  // increment Sensor Count and write it to EEPROM
  EEPROM.write(EEPROM_OFFSET, ENumSensors); 
  return  ENumSensors;
}

So in your loop() after you have got the DS61S20 data, you use some code like this:

  SensorNum = FindSensor(&addr[0]);
  if(SensorNum == -1){   // Not found, so we need to write it to EEPROM so we find it next time
    SensorNum = AddSensor(&addr[0]);  
  }

Note that each byte in the EEPROM is initialised to 0xFF if you have not used it so I also put this in setup();

  ENumSensors = EEPROM.read(EEPROM_OFFSET);
  if(ENumSensors == 0xFF)
    EEPROM.write(EEPROM_OFFSET, 0);    // Initialise memory that has never been used

So this code simply numbers sensors from 0 upwards and checks memory limits before adding a sensor. As you add a new sensor, it should be automatically found, stored in EEPROM and values reported with the next available number. So in my case if I add a third sensor, it’s data will show up as number 3 sensor.

Here is the whole script which is baseed on the one write example on the playground.

#include <EEPROM.h>
#include <OneWire.h>

/* DS18S20 Temperature chip i/o with Road Runner COmpatibility
   my Sensor Serial numbers are:
     10 EA 92 6C 1 8 0 76
     10 63 CF 6C 1 8 0 73
*/


OneWire  ds(10);  // on pin 10
byte ENumSensors = 0;   // Store the number of sensors in EEPROM
byte ESensorSerial[8];  // Store the Sensor Address found in EEPROM here
#define EEPROM_OFFSET 0         

// MEM_LIMIT = 511 bytes total less 8 bytes for address less 1 byte for Number of sensors less any other EEPROM used in front of the sensore storage.
#define MEM_LIMIT ( 502-EEPROM_OFFSET)
//#define ROADRUNNER_COMPATIBLE    
//#define DEBUG


void setup(void) {
  ENumSensors = EEPROM.read(EEPROM_OFFSET);
  if(ENumSensors == 0xFF)
    EEPROM.write(EEPROM_OFFSET, 0);    // Initialise memory that has never been used
#ifdef ROADRUNNER_COMPATIBLE
  Serial.begin(2400);
#else
  Serial.begin(9600);
#endif
}

int FindSensor(byte *serialnum)
// Returns -1 if the sensor is not found in EEPROM or there are no readings stored
{
  int j=0, i=0;
  int SerialOffset, found;

  ENumSensors = EEPROM.read(EEPROM_OFFSET);
  if(ENumSensors == 0)
    return(-1);    // Sensor Not found
  i = 0;
  found = 0;
  do{   
    SerialOffset = (i * 8) + 1;
    for( j = 0; j < 8; j++) {
      ESensorSerial[j] = EEPROM.read(SerialOffset); 
      SerialOffset++;
    }
    if(!memcmp(&ESensorSerial, serialnum, 8)){
      return i;
    }
    i++;  
  }while(i <= ENumSensors);
  return -1;    // Will only get here if the sensor is not found
}

byte AddSensor(byte *serialnum)    // Returns SensorNumber added
{
  int j=0;
  
  int SerialOffset;
  ENumSensors = EEPROM.read(EEPROM_OFFSET);
  SerialOffset = EEPROM_OFFSET + (ENumSensors * 8) + 1;
  if (SerialOffset > MEM_LIMIT){      // No more room left in memory
    return 0xFF;
  }  
  Serial.print("Adding Sensor, Serial Offset = ");
  Serial.print(SerialOffset,DEC);
  Serial.print(" ");
  
  for( j = 0; j < 8; j++) {
    EEPROM.write(SerialOffset, *serialnum ); 
    SerialOffset++;
    serialnum++;
  }
  ENumSensors++;  // increment Sensor Count and write it to EEPROM
  EEPROM.write(EEPROM_OFFSET, ENumSensors); 
  return  ENumSensors;
}

void loop(void) {
  byte i,j,k;
  byte present = 0;
  byte data[12];
  byte addr[8];
  byte Epointer;
  int HighByte, LowByte, TReading, SignBit, Whole, Fract;
  int SensorNum;

  if ( !ds.search(addr)) {
#ifdef DEBUG    
      Serial.print("No more addresses.\n");
#endif
      ds.reset_search();
      return;
  }
#ifdef DEBUG  
  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }
#endif
  if ( OneWire::crc8( addr, 7) != addr[7]) {
#ifdef DEBUG      
      Serial.print("CRC is not valid!\n");
#endif
      return;
  }
  
  if ( addr[0] != 0x10) {
#ifdef DEBUG  
      Serial.print("Device is not a DS18S20 family device.\n");
#endif
      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

#ifdef DEBUG
  Serial.print("P=");
  Serial.print(present,HEX);
  Serial.print(" ");
#endif  
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
#ifdef DEBUG    
    Serial.print(data[i], HEX);
    Serial.print(" ");
#endif    
  }
#ifdef DEBUG  
  Serial.print(" CRC=");
  Serial.print( OneWire::crc8( data, 8), HEX);
  Serial.print(" ");
#endif  
  SensorNum = FindSensor(&addr[0]);
  if(SensorNum == -1){   // Not found, so we need to write it to EEPROM so we find it next time
    SensorNum = AddSensor(&addr[0]);  
  }    
#ifdef ROADRUNNER_COMPATIBLE
  SensorNum++;            // RoadRunner temperature sensors start numbering at 1, not 0 (note RR only supports 4 temp sensors)
#endif  
  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Whole = TReading/2;
  Fract = TReading%2*5;
  Serial.print(SensorNum,DEC);
  if (SignBit) // If its negative
  {
     Serial.print(" -");
  } 
  else
   Serial.print(" ");
   Serial.print("0");
   if(Whole < 100)
     Serial.print("0");
   if(Whole < 10)
     Serial.print("0");
  Serial.print(Whole);
  Serial.print(".");
  Serial.print(Fract);
  Serial.print("0\r\n");
}