Identifying One Wire sensor

Using two DS18s20 chips, I have been playing with the sample code on the forum and got as far as wanting to identify each sensor. I thought I should be able to do it by creating an array of sensor serial numbers

static byte SensorSerial[2][8] = 
                        {
                          {0x10, 0xEA, 0x92, 0x6C, 0x01, 0x08, 0x00, 0x76},
                          {0x10, 0x63, 0xCF, 0x6C, 0x01, 0x08, 0x00, 0x73},
                        };
#define NUM_SENSORS 2

And I thought This code inserted after reading the tremperature and printing the sample code's HEX data string should identify the sensor:

  for( i = 0; i++; i < NUM_SENSORS){
    if (!memcmp(&SensorSerial[i][0],&addr[0], 8))
      break;
  }
  SensorNum = i;

So I could print the Temperature for a given sensor number

  Serial.print("Temp ");
  Serial.print(SensorNum,DEC);
  Serial.print("= ");

I was expecting to see

Temp 0 = 
Temp 1 =

HOwever, I always get Temp1 returned

R=10 EA 92 6C 1 8 0 76 P=1 35 0 4B 46 FF FF 2 10 67  CRC=67
Temp 1= 26.50

R=10 63 CF 6C 1 8 0 73 P=1 E9 FF 4B 46 FF FF 4 10 7B  CRC=7B
Temp 1= -11.50

No more addresses.

So what Am I doing wrong? Any help appreciated.

If its any help, this is what Im using to read the temp from the one wire devices with parasitic power.
Its for the DS18B20 version. Im not using the wire library as I was having problems getting it working like you and also running out of space with my project on the 128. Not a problem now as I have a 328p but why change whats working.

Its a hash together from various sources.
I was having problems before with negative temps but this code worked.

checkTemp() puts the current temperatures in the global variables intTemp and extTemp

// Hardware addresses for ds18B20 devices
#define EXT_ADDR {0x28,0x2E,0xFF,0x77,0x01,0x00,0x00,0xF7}
#define INT_ADDR {0x28,0xF1,0x12,0x78,0x01,0x00,0x00,0xBB}

float intTemp;    // Current internal temperature
float extTemp;    // Current external temperature

void checkTemp(){
  byte addrExt[8] = EXT_ADDR;
  byte addrInt[8] = INT_ADDR;

  extTemp = getTemp(addrExt);
  intTemp = getTemp(addrInt);

}



float getTemp(byte addr[8]){

  int HighByte, LowByte, TReading, SignBit, Whole, Fract,i;
  float temp;

  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0x55);
  for( i = 0; i < 8; i++) OneWireOutByte(TEMP_PIN,addr[i]);
  OneWireOutByte(TEMP_PIN, 0x44); // perform temperature conversion, strong pullup for one sec
  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0x55);

  for( i = 0; i < 8; i++) OneWireOutByte(TEMP_PIN,addr[i]);

  OneWireOutByte(TEMP_PIN, 0xbe);
  LowByte = OneWireInByte(TEMP_PIN);
  HighByte = OneWireInByte(TEMP_PIN);
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit

  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }

  temp = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
  temp /= 100;
  if (SignBit){ // negative
    temp *= -1;
  }

  return temp;
}


// one wire functions
void OneWireReset(int Pin) // reset.  Should improve to act as a presence pulse
{
  digitalWrite(Pin, LOW);
  pinMode(Pin, OUTPUT); // bring low for 500 us
  delayMicroseconds(500);
  pinMode(Pin, INPUT);
  delayMicroseconds(500);
}

void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
  byte n;
  for(n=8; n!=0; n--)
  {
    if ((d & 0x01) == 1)  // test least sig bit
    {
      digitalWrite(Pin, LOW);
      pinMode(Pin, OUTPUT);
      delayMicroseconds(5);
      pinMode(Pin, INPUT);
      delayMicroseconds(60);
    }
    else
    {
      digitalWrite(Pin, LOW);
      pinMode(Pin, OUTPUT);
      delayMicroseconds(60);
      pinMode(Pin, INPUT);
    }

    d=d>>1; // now the next bit is in the least sig bit position.
  }
}

byte OneWireInByte(int Pin) // read byte, least sig byte first
{
  byte d, n, b;

  for (n=0; n<8; n++)
  {
    digitalWrite(Pin, LOW);
    pinMode(Pin, OUTPUT);
    delayMicroseconds(5);
    pinMode(Pin, INPUT);
    delayMicroseconds(5);
    b = digitalRead(Pin);
    delayMicroseconds(50);
    d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
  }
  return(d);
}

Gordon,

Thank you for that, I'll work it out from here. I noticed you don't appear to Check the CRC for valid input. I wonder if this should be done? Maybe the function could return a number out of range chip eg (-999.00) which can never exist as the coldest we can get to is absolute zero (eg -273 C)

Here is some very efficient looking code to print a float which i found somewhere, which maight be of interest but I have not tried it:

void print_float(float f, int num_digits)
{
    int f_int;
    int pows_of_ten[4] = {1, 10, 100, 1000};
    int multiplier, whole, fract, d, n;
 
    multiplier = pows_of_ten[num_digits];
    if (f < 0.0)
    {
        f = -f;
        Serial.print("-");
    }
    whole = (int) f;
    fract = (int) (multiplier * (f - (float)whole));
 
    Serial.print(whole);
    Serial.print(".");
 
    for (n=num_digits-1; n>=0; n--) // print each digit with no leading zero suppression
    {
         d = fract / pows_of_ten[n];
         Serial.print(d);
         fract = fract % pows_of_ten[n];
    }
}

Im only looking at domestic temperatures -15 to +45 is the max range for the south of the UK.
Ocassionaly I get a figure of 85 which I only get if the sensors arnt ready at startup.
So I havnt added the crc check. I think it takes quite a lot of memory on the Arduino.
Doesnt it need a lookup table?
Im going to put a check in for a variation of probably +-10% on the temp's returned and then recheck if outside of these bounds.

Floats arnt a problem as from version 13 of the IDE the print library can handle them.
So any library like Ethernt, Serial or liquidcrystal that inherit print.h will print to 2 decimal places as standard.
Soon the IDE will accept a precision value, but for now you need to do a minor hack to print.cpp to add it.
There are posts about the hack on the forum.

Gordon

Thanks for the pointers Gordon. I'll try serial.printing floats as I started with Arduino at version 013.

The latest One Wire code on the playground says that the CRC table has been eliminated. I had a look at the CRC code and there only a dozen or so lines of code plus some #defines in the header file that select the CRC mode between table or direct calculation.

I found no problems with the current code except that it must calculate the temperature based on the DS18B20 which I think has greater precision than the DS18S20 I am using so the temperature Serial.printed was out by a factor of about 10.

With the DS18S20, you can do some calculations using data returned in the scratch register to adjust readings to give precision of 0.0625 degrees instead of 0.5 degrees returned in the main registers which I think is the same precision as the B chip anyway. By using floats, the maths for this adjustment becomes quite trivial. I might try using this technique.

Ok, I got my code in the original post working by substituting a do-while loop instead of the for loop. It must be something about how/when the loop counter (i++) was being incremented in the for loop.

So now for each pass through loop(), the system gets a device serial number and data array in turn using the one wire library and then it looks up the serial number in my SensorSerial array and numbers the sensor accordingly based on the position in the array.

So now I have been thinking instead of hard coding a list of device serial numbers and the number of them in the array like this:

static byte SensorSerial[2][8] =
                        {
                          {0x10, 0xEA, 0x92, 0x6C, 0x01, 0x08, 0x00, 0x76},
                          {0x10, 0x63, 0xCF, 0x6C, 0x01, 0x08, 0x00, 0x73},
                        };
#define NUM_SENSORS 2

it would make more sense to store the SensorSerial array and NUM_SENSORS dynamically in the EEPROM. If a new sensor was found that did not exist in the SensorSerial array, we could add it to the list in the EEPROM and increment NUM_SENSOR.

That way, it would be a trivial matter to add extra sensors as there would be no need to run each sensor up in turn to find the serial number and hard code it into the sketch. Voilia! Plug and play Sensors, isn't that how this should work?

There is enough memory in the EEPROM to support 63 sensors.

I saw that it takes 3.3 ms to write a byte into EEPROM (26.4 ms for each serial number) but what about read times? Would they be too slow to do this directly from EEPROM or would I need to read the SensorSerial array into core memory?

I thought this might be quite a valuable addition to the One Wire features supported by Arduino. Any thoughts?