DS18B20 doubt on serial number and using Array

Hi guys I managed to make this code work on dallas 1wire sensor, but I have a couple doubts regarding how data is accesed from the sensor. I obviously read the datasheet from dallas.

1) I know there’s a 64 bit rom code, 8 bit crc, 48-bit serial, and family code.
I’m confusing myself where’s this data stored is it on the scratchpad.
I know the scratchpad has 9 bytes of data going from

Byte 0 Temperature LSB
1 Temperature MSB
Byte 2 Th Register
3 TL Register
Byte 4 Configuration Register
6 Reserved
7 Reserved
8 CRC

So to read the serial number this is used in the code example. Why does looping from 0 to 8 show up the hex values from the sensor, if addr as an array it’s initialized with nothing inside ?

Serial.print(“ROM =”);
for( i = 0; i < 8; i++) {
Serial.write(’ ');
Serial.print(addr*, HEX);*
2)

  • ds.select(addr); *
  • ds.write(0xBE); // Read Scratchpad*
    I don’t understand ds.select(addr) where its pointing at. Addr was an array I understand that. Command BE it’s instructed to start reading values coming out of the sensor?
    3)
    * *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(" ");* *
  • This makes sense to me there’s a for loop to read into data array data coming from byte 0 to 9 . So ds.read() it’s the function from onewire instructing the DS object defined to read data from the registers ?*
    4)
    Here I’m completely lost , somehow, I understand datap[1] contains byte 1 from sensor which in turn contains MS Byte and data[0] Lsb , but why is data[1] bit shifted left 8 positions t that way it’s been left with 00000000 and bitwise or with data[0] ending with just an 8 bit value.
  • Then I’m lost with if (type_s) and so on. type_s evaluates if it’s DS18B20 family . So if it’s 1 if it’s true goes on…*
    ```
  • int16_t 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);
       // at lower res, the low bits are undefined, so let’s zero them
       if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
       else if (cfg == 0x20) raw = raw & ~3; // 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
     }*
    * *Complete Code - Dallas DS18B20* *
    *OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)

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
 // because the result is a 16 bit signed integer, it should
 // be stored to an “int16_t” type, which is always 16 bits
 // even when compiled on a 32 bit processor.
 int16_t 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);
   // at lower res, the low bits are undefined, so let’s zero them
   if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
   else if (cfg == 0x20) raw = raw & ~3; // 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");
}*
```

Question 4 is the easy one. That is how you combine two bytes into a 16-bit int.

You put the most significant byte into a 16 bit value, and then you multiply by 256 or shift left 8 times ( same thing ), and then you add or bitwise OR ( same thing ), the least significant byte.

If you MSB is 0xAB and your LSB is 0xCD,

then you take the AB, shift it left so you have AB00 and then you add the CD, so you get ABCD as a 16 bit number.

It looks like you have combined codes from several different places, and that is why you are confused.

You need to have one program to get the serial number of your devices. This program basically has to consider every 64 bit number that the device could possibly have, and try to find it. This takes a long time, although there are some shortcuts to the procedure. Then you find the device address of your devices, and write them down, and put them into the code of your second program.

Your second program will attempt to communicate with the devices you have, whose addresses you already know, and get the temperature off them. Your second program will have the address of the devices you have, hard-coded into it.

You can combine these, but you put the address-search activity into the setup( ) function of your arduino sketch, not into the loop ( ). You only do this once.

michinyon:
Question 4 is the easy one. That is how you combine two bytes into a 16-bit int.

You put the most significant byte into a 16 bit value, and then you multiply by 256 or shift left 8 times ( same thing ), and then you add or bitwise OR ( same thing ), the least significant byte.

If you MSB is 0xAB and your LSB is 0xCD,

then you take the AB, shift it left so you have AB00 and then you add the CD, so you get ABCD as a 16 bit number.

Listen the chunks of code I'm quoting here are from the entire ds18B20 arduino code example. There are no mixed fragments.
going back to combining the MSB and LSB bit of data.

I'm slowly getting the point now .. I was going to be more graphical in binary say we have

MSB 0xAB = 1 0 1 0 1 0 1 1 if we left shift 8 times this we're left with 0 0 0 0 0 0 0 0 , we're bit shifting an 8 bit value we're not ending up with 1 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0 right?

LSB 0xCD = 1 1 0 0 1 1 0 1

Ending up with 0 0 0 0 0 0 0 0 Or'ed with 1 1 0 0 1 1 0 1 or I'm wrong ?

about how to obtain the unique serial number mask in hex. I didn't understand why using a loop cycling from ADDR (which is an array previously initialized brought up the hex values of the unique serial. I didn't understand how the array was already filled up with those values. As the ARRAY was initialized in the program code and we all know once we initialize variables the don't have any information unless you assign any values to it.

thanks

data

To go back to question 1, the device's 64 bit address is not stored in it's scratchpad memory or anywhere else. It is hardcoded into the logic in the device, which enables the device to determine if it should reply to your requests.

addr is an array of 8 bytes defined in your program. when you pass the address of this array to the ds.search( ) function, this array can be both an input and an output to the function.

when you call ds.search( ), the function starts looking for devices. it looks for device 0, then device 1, then device 2, until it gets to device 2 to the power of 64. Whenever it finds a device the responds to it, it stops looking and puts the address where it found a response into your addr array.

Then you can print it.

Then you ask the device to start measuring the temperature.

The you ask the device to send you the temperature, and you print.

And then loop( ) starts again, and it calls ds.search( ), and ds.search is smart enough to start looking for another device, starting with the possible address which is 1 more than the last device it found. In this way, it can find multiple devices in your system, one after the other. It will find one device for each iteration of loop( ).

When it eventually gets to possible address 2 to the power of 64, it goes back and starts looking from device address 0 again.

You would not normally do this searching process over and over again. It would be very slow.

If you had say 5 devices, you would find the address of those 5 devices, and put those numbers into your program, and then just use those 5 addresses. That would make more sense than looking at 2 to the power of 64 possible addresses over and over again.

const int MAXADD=10 ;
byte addr[MAXADD][8] ;
byte temp_addr[8] ;
int n_addr=0 ;

void setup()
{
    while ( n_addr < MAXADD )
    {
        if ( ds.search( temp_addr ))
        {
               for ( int i=0 ; i<8 ; i++ ) addr[n_addr][i] = temp_addr[i] ;
               n_addr++ ;
        }
        else
        {
            Serial.println("Found all the addresses");
            break ;
        }
    }
}

This code will find all the addresses once .

The unique serial number does not appear in the memory ( scratch pad ) of the device. It appears in the control logic of the device which determines which control requests it responds to.

You cannot ask the device "tell me your serial number".

You have to try communicating with the device, using address 0, address 1, up to address 2 to the power of 64, and see what address it responds to. You can read ds.search( ) to see how this happens. There is also a detailed explanation of how this works at the dallas/maxim website.

michinyon:
To go back to question 1, the device’s 64 bit address is not stored in it’s scratchpad memory or anywhere else. It is hardcoded into the logic in the device, which enables the device to determine if it should reply to your requests.

addr is an array of 8 bytes defined in your program. when you pass the address of this array to the ds.search( ) function, this array can be both an input and an output to the function.

when you call ds.search( ), the function starts looking for devices. it looks for device 0, then device 1, then device 2, until it gets to device 2 to the power of 64. Whenever it finds a device the responds to it, it stops looking and puts the address where it found a response into your addr array.

Then you can print it.

Then you ask the device to start measuring the temperature.

The you ask the device to send you the temperature, and you print.

And then loop( ) starts again, and it calls ds.search( ), and ds.search is smart enough to start looking for another device, starting with the possible address which is 1 more than the last device it found. In this way, it can find multiple devices in your system, one after the other. It will find one device for each iteration of loop( ).

When it eventually gets to possible address 2 to the power of 64, it goes back and starts looking from device address 0 again.

Ok listen here , you have addr as an array of 8 bytes defined. This array initially has nothing inside do we agree on that point ?
then it starts the search routine with if ds.search(addr) = 0 in more clear terms, ds.search(addr) is pointing where? addr is an array and it’s got no values defined inside as you can see from the variable intialization below

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;
  }

Then here , to print the serial unique code right? It goes through an iteration but how do you instruct to read on the sensor that serial number in hex ? where is it . Cause here there’s an interation going from 0 to 8 which I supposed was the scratchpad byte registers. And I didn’t understand why ADDR (array had these values inside how is this possible?)
Can you explain that to me . Thanks

  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);

To literally check all possible 64 bit combinations would take quite a long time. There is actually some shortcuts it makes in that process, which you don’t have to worry about.

This array initially has nothing inside do we agree on that point ?

No. I don't think that is guaranteed. It would seem that this code assumes it is zero.

Keep in mind, the ds object can keep its own internal variables, which means it can remember its status between one call from your program, to the next call from your program.

michinyon:
To literally check all possible 64 bit combinations would take quite a long time. There is actually some shortcuts it makes in that process, which you don’t have to worry about.

Again this piece of code .

Serial.print(“ROM =”);
** for( i = 0; i < 8; i++) {**
** Serial.write(’ ');**
__ Serial.print(addr*, HEX)[/b]__
it’s printing the sensor serial number. And i’m not understanding why it’s reading it from ADDR array as it’s initialized with no value at all.
__
you’re not answering me my point… I apreciatte all your help but you’re not clarifying that to me. I know ds.search(addr) cycles until there are no devices. but I also don’t understand how it’s used to check there’s only 1 device or more like used in this code …*__
if ( !ds.search(addr)) {
** Serial.println(“No more addresses.”);**
** Serial.println();**
** ds.reset_search();
_ delay(250);
return;
}**_

ds is an object of class OneWire, and has it’s own internal variables.

For example, when you initialise it, it remembers that you want to use pin 10, and it records that in its internal state, so you don’t have to keep telling it again.

Now when you search for devices, starting at address 0, and then 1, and you look and look and look, and you find device 0xABCDABCD 64 bit code, then the next time you call ds.search( ), you want to start looking for devices with addresses higher than that. Now there are two ways you could possibly start looking further in the right place. Either the ds object remembers where the last address it found was. Or, it relies on the value which is still sitting in the addr array, the second time you call it. Since ds is an object, either of those methods might work. You could examine the source code of the OneWire::search( ) function to find out. Or, you could clear the value of addr, and see if the second call to search( ) reveals your second device, or the first one again.

michinyon:

This array initially has nothing inside do we agree on that point ?

No. I don’t think that is guaranteed. It would seem that this code assumes it is zero.

Keep in mind, the ds object can keep its own internal variables, which means it can remember its status between one call from your program, to the next call from your program.

SEE that’s what I meant it’s assuming it is zero ADDR and if it’s zero how on earth could this piece of code throw the unique serial number , from this code I understand that it’s cycling iterating within the ADDR array from byte 0 to 8 and printing the values. How on earth does it know ADDR contains the value of the serial number?

Serial.print(“ROM =”);
for( i = 0; i < 8; i++) {
Serial.write(’ ');
Serial.print(addr*, HEX);*

Again this piece of code .

Serial.print(“ROM =”);
for( i = 0; i < 8; i++) {
Serial.write(’ ');
Serial.print(addr, HEX)

it’s printing the sensor serial number. And i’m not understanding why it’s reading it from ADDR array as it’s initialized with no value at all.

I am answering your questions one at a time, and you are asking new ones faster than I can type.

When you call the ds.search( addr ), the parameter of the function is the address of your 8 byte array. Using this address, the ds.search( ) function can do both of these things. It can read the values already in addr. And it can also put values into addr.

As I described before, it starts sending out messages on the one-wire, trying all addresses, until it finds one that responds. When it finds an address that responds, it puts that address into the addr array. the func tion returns to you a true value, so you know it found something. You then print the 8 bytes of that array. Although the contents of the array are initially undefined, when the ds.search( ) function returns a true value to you, then the ds.search( ) function has put the address from which it got a response, into that addr array.

In C/C++, a pointer function argument ( which an array name also is ), creates a situation where that variable can be both an input and an output from the function.

SEE that’s what I meant it’s assuming it is zero

I doesn’t necessarily have to assume it is zero. the ds object you created, is capable of counting how many times it’s various functions, including search( ), have been called. If it is called the first time after you create the object, it is capable of knowing to start searching the one-wire bus, for any devices which may be there, starting from address zero, regardless of what the initial value of addr{ } may or may not be.

From the code, it is quite clear that addr is an output variable from ds.search( ). You use the value in the array, after the function has been called.

It is possible that it is also an input, and also possible it isn’t. Without consulting the actual code, or at least the header file, for the OneWire class of which ds is an instance, it is hard to tell if addr[ } is used an an input. It would be quite possible to implement the class, either way.

michinyon:

Again this piece of code .

Serial.print(“ROM =”);
for( i = 0; i < 8; i++) {
Serial.write(’ ');
Serial.print(addr, HEX)

it’s printing the sensor serial number. And i’m not understanding why it’s reading it from ADDR array as it’s initialized with no value at all.

I am answering your questions one at a time, and you are asking new ones faster than I can type.

When you call the ds.search( addr ), the parameter of the function is the address of your 8 byte array. Using this address, the ds.search( ) function can do both of these things. It can read the values already in addr. And it can also put values into addr.

As I described before, it starts sending out messages on the one-wire, trying all addresses, until it finds one that responds. When it finds an address that responds, it puts that address into the addr array. the func tion returns to you a true value, so you know it found something. You then print the 8 bytes of that array. Although the contents of the array are initially undefined, when the ds.search( ) function returns a true value to you, then the ds.search( ) function has put the address from which it got a response, into that addr array.

In C/C++, a pointer function argument ( which an array name also is ), creates a situation where that variable can be both an input and an output from the function.

I see it all makes sense now… so ds.search(addr) , DS.SEARCH function it’s in charge of filling up the addr array with the serial number of the devices it goes searching. that’s how it fills the unique serial number on ADDR array which I didn’t understand how it ended up there. As I thought hell well ADDR has no value at all !! now it all makes sense.
Ds.search it’s a function and ds.search(addr) it’s passing addr array to be filled up with the unique serial numbers. Correct me if i’m wrong.

It would appear from the actual code of OneWire, that addr is only used as an output from the search( ) function, and the input value of it never matters.

If you call search( ) the first time, it will start from the lowest valid possible address.

If you call it subsequent times, it will start searching from the next address after the last one it found.

You can call ds.reset_search( ), if you want to force it to start searching at the beginning of the possible address range again.

michinyon:
It would appear from the actual code of OneWire, that addr is only used as an output from the search( ) function, and the input value of it never matters.

If you call search( ) the first time, it will start from the lowest valid possible address.

If you call it subsequent times, it will start searching from the next address after the last one it found.

You can call ds.reset_search( ), if you want to force it to start searching at the beginning of the possible address range again.

So what about what i said before?