Continue to Site

# Expanding DS18S20 output from 9-bit to 12-bit

Status
Not open for further replies.

#### Mike - K8LH

##### Well-Known Member
Hey guys, could you double check my code for expanding the DS18S20 temperature reading from 9-bits (0.5° resolution) to 12 bits (0.0625° resolution), please? I think I'm doing it the way the DS18S20 Datasheet suggests, but during side-by-side testing with a DS18S20 and a DS18B20, the DS18S20 temperature readings always seem to be low.

Code:
    /*                                                              *
*  expand DS1820 or DS18S20 9-bit temperature value (1/2°      *
*  resolution) to DS18B20 12-bit format (1/16th° resolution).  *
*                                                              */
if(familyid == 0x10)   // if DS1820 or DS18S20
{ rawtemp16.0 = 0;     // clear the 0.5° bit
rawtemp16 <<= 3;     // make room for fraction bits
rawtemp16 |= frac;   // frac = (16 - 'count_remain')
rawtemp16 -= 4;      // subtract 1/4° (per datasheet)
}

If I leave out the last instruction where I'm subtracting 1/4° from the raw temperature value, the DS18S20 temperature readings are right on or never more than 1/10° off between the DS18S20 and the DS18B20.

What do you guys think?

Cheerful regards, Mike

Last edited:

#### Wilksey

##### Member
Hi Mike,

Looking at the memory map for the DS18S20, on page 7, it states that bytes 6 + 7 are what you need to extract to get the data from the scratchpad, Which are Count Remain and Count Per C respectively, as it is zero indexed, your "count remain" is read, but not Count per C, I know it is fixed at 16(10h), does it also assume that Count Remain is fixed at 0Ch? I'm looking at example 3, and it reads in the entire scratchpad.

I must be honest, i'm not a user of boost C, and you have quite a bit of inline assembler going on, I can see you are clearing the 0.5 degC bit, as per the datasheet.

I may be off on the wrong track here, but would this not be better:
Code:
         owrw(OwScratch);       // send "read scratchpad" command
rawtemplo = owrd();    // read temperature lo byte
rawtemphi = owrd();    // read temperature hi byte
countremain = owrd();	// read count remain value
countperc = owrd();	// read the count per deg C
/*                                                              *
*  expand DS1820 or DS18S20 9-bit temperature value (1/2°      *
*  resolution) to DS18B20 12-bit format (1/16th° resolution).  *
*                                                              */
if(familyid == 0x10)   // if DS1820 or DS18S20
{
rawtemp16.0 = 0;     // clear the 0.5° bit
frac = (rawtemp16 - ((rawtemp16/100) * 25));	// reusing the 'frac' variable
temp = (frac+((countperc-countremain)/countperc)); // as per datasheet calcs
}

That's how I would interpret the datasheet.

Forgive me if you are doing the same in a more elegant way, my C is a little rusty!

Regards

Wilksey

Last edited:

#### Mike - K8LH

##### Well-Known Member
Hi Wilksey,

First of all, thank you very much for taking time for a thoughtful reply. Unfortunately, I can't quite figure out what you're doing with that math.

... does it also assume that Count Remain is fixed at 0Ch?
That's a good question. I've always wondered about that 0Ch. All I can say is that I see a constant 10h value for Count_Per_C and I see values of 01h through 10h for Count_Remain.

Basically, what I did was to take the formula in the DS18S20 Datasheet and multiply each term by sixteen in order to end up with the same 12-bit format used by the DS18B20 devices where the integer temperature value represents the Celsius temperature times sixteen (1/16th degree resolution). Please note that I replaced each occurrence of "count_per_c" in the formula with its constant value, 16.

After simplifying the terms, I get;

Unfortunately, the 1/4° subtraction seems to throw off the temperature results as shown in the first post when doing a side-by-side comparison between a DS18S20 and a DS18B20. I'd really like to say I've found a problem with the DS18S20 documentation but I'm just not that confident (over-confident, arrogant, etc.), and that's why I'm looking for a problem with my code.

Cheerful regards, Mike

Last edited:

#### Mr RB

##### Well-Known Member
Mike, I just checked some code from an old project of mine and I'm pretty sure you need to do the subtraction, but maybe your order is incorrect?

Here is the relevant code;
Code:
    // Next we perform a 9 byte sequential read block;
// 0    Temperature_LSB  (just the LSB gives 0xFF = +127.5'C)
// 1    Temperature_MSB (NOTE! MSB only used for -'C values)
// 2    Temp alarm High (User byte 1)
// 3    Temp alarm Low (User byte 2)
// 4    -reserved-
// 5    -reserved-
// 6    Count_remain
// 7    Count_per_C        (dont bother reading the last 2 bytes)
// 8    CRC

temp = OW_Read(&PORTA,2);		// Get temperature LSB
temp_sign = OW_Read(&PORTA,2);	// Get temperature MSB (sign)
j = OW_Read(&PORTA,2);          // AL hi (wasted)
j = OW_Read(&PORTA,2);          // AL lo (wasted)
temp_fine = OW_Read(&PORTA,2);	// Get Count_remain    fine res bits

//------------------------------------------------
// The temperature results are in 3 bytes;
//  temp = temperature in 0.5'C steps ie 0xFF = 127.5'C
//  temp_sign = (0xFF if temp is negative)
//  temp_fine = fine temp resolution bits resolution 1/16'C
//------------------------------------------------
// calc a 16bit temperature in btemp

temp_fine = (16 - temp_fine);   	// get the 4 fine bits
temp_fine = (temp_fine & 0x0F);     // safe, keep just 4 bits

btemp = (temp / 2);		// get whole degrees
btemp = (btemp << 4);	// make room for fine bits
btemp += temp_fine;		// add the 4 fine bits
btemp -= 0x04;			// subtract 0.25'C (as per datasheet formula)

#### Mike - K8LH

##### Well-Known Member
Hi Roman (Mr RB),

Thank you for taking time for a thoughtful reply and thank you for the example code.

In your example, are the temperature LSB and MSB bytes combined to form a 16 bit sign extended value in your temp variable? If that's the case, then it seems I'm performing the same operations and in the same order in my code. The variable names and operations are slightly different but the results should be identical.

Code:
        btemp = (temp / 2);        // get whole degrees
btemp = (btemp << 4);      // make room for fine bits
btemp += temp_fine;        // add the 4 fine bits
btemp -= 0x04;             // subtract 0.25'C (as per datasheet formula)
Code:
    /*                                                              *
*  expand DS1820 or DS18S20 9-bit temperature value (1/2°      *
*  resolution) to DS18B20 12-bit format (1/16th° resolution).  *
*                                                              */
if(familyid == 0x10)   // if DS1820 or DS18S20
{ rawtemp16.0 = 0;     // clear the 0.5° bit
rawtemp16 <<= 3;     // make room for fraction bits
rawtemp16 |= frac;   // frac = (16 - 'count_remain')
rawtemp16 -= 4;      // subtract 1/4° (per datasheet)
}

So, I've been doing it this way for years and it appears to be correct. Could I impose on someone with access to both a DS18S20 and a DS18B20 to do a side-by-side comparison to check the results I got? Basically, after expanding the resolution of the DS18B20 reading, it seems the DS18S20 readings are always approximately 1/4° lower than the DS18B20 readings, which is why I suspect an error in the published DS18S20 formula.

Thanks everyone.

Cheerful regards, Mike

Last edited:

#### Mike - K8LH

##### Well-Known Member
Hey guys. Here's an interesting twist.

I decided to print my frac variable to the screen and the value from the DS18S20 and the DS18B20 seem to track almost perfectly. This is interesting because the frac variable is calculated from the seventh byte in scratchpad ram which is defined as Count_Remain on the DS18S20 and as Reserved on the DS18B20. Apparently though, this byte contains valid Count_Remain data on the DS18B20. The byte simply isn't used on the DS18B20 because the 4 bit fractional data is already included in the 12 bit temperature value. Anyway, here's the display (without subtracting 1/4°);

At this point it seems that (16 - Count_Remain) produces valid 1/16° fractional temperature data which simply needs to be appended to the integer temperature value to produce exactly the same 12 bit temperature reading that you would get with a DS18B20. Subtracting 1/4° actually messes up the temperature value.

Is it possible I've discovered an error in the DS18S20 Datasheet? Those Count_Remain values would seem to suggest that's the case, but, I think I need more sample readings from several more devices before jumping to that conclusion.

Thanks for all the help, Gentlemen.

Cheerful regards, Mike

Last edited:

#### Wilksey

##### Member
Hi Mike,

I have looked at the datasheet again, this is the one I used:
https://datasheets.maxim-ic.com/en/ds/DS18S20.pdf

I didn't take into account the DS18B20, which is maybe where my calculations do not match?

Page 3 of the datasheet give the formula:
Temperature = temp_read - 0.25 + (count_per_c-count_remain)/count_per_c

To replace this with fixed constants you would have:
Temperature = temp_read - 0.25 + (16-count_remain) / 16

From what you have said I get the impression you are making a routine to handle two sensors with slightly different calculations?

If this is the case, what I would do if I wasn't sure is to write the code for just the DS18S20 sensor as per the calculation to check the outcome.

I haven't checked, but do Maxim have any old Dallas app notes for the sensor with some code, even if its for another processor it will be clearer to work out what is going on.

I did do some work on one once, but it was only 9 bit, but I remember having a headache trying to get the thing to work properly!

Wilksey

#### Mike - K8LH

##### Well-Known Member
Hi Mike,

I have looked at the datasheet again, this is the one I used:
https://datasheets.maxim-ic.com/en/ds/DS18S20.pdf

That's the same Datasheet I have.

From what you have said I get the impression you are making a routine to handle two sensors with slightly different calculations?

It's actually a routine to expand the 9-bit temperature value produced by the DS1820 and the DS18S20 to the higher resolution 12-bit format of the DS18B20 so that a single math routine can be used to process 12-bit temperature data. Basically, I'm trying to find a low cost method to support all three DS1820 temperature sensor variants.

The program was actually designed to test and showcase a very efficient 99 word set of low level 1-Wire driver library functions. The routine to convert 9-bit data to 12-bit data is a candidate for inclusion in a separate DS18x20 library.

Cheerful regards, Mike

#### Mr RB

##### Well-Known Member
...
In your example, are the temperature LSB and MSB bytes combined to form a 16 bit sign extended value in your temp variable? If that's the case, then it seems I'm performing the same operations and in the same order in my code. The variable names and operations are slightly different but the results should be identical.

Yep looking at your code I think you're right. My code has been in use for some time and was tested.

...
So, I've been doing it this way for years and it appears to be correct. Could I impose on someone with access to both a DS18S20 and a DS18B20 to do a side-by-side comparison to check the results I got? Basically, after expanding the resolution of the DS18B20 reading, it seems the DS18S20 readings are always approximately 1/4° lower than the DS18B20 readings, which is why I suspect an error in the published DS18S20 formula.

That might be the issue! I would not expect two different sensors to read exactly the same temperature, really to test that you need to test 10 or more of each type and that will only hold true for a manufacturing batch.

The way to test the fraction decoding is to implement it and record the results via terminal to a text file, then slowly change the temperature and there should be all 16 steps sequentially within each degree C. If that occurs then the code is correct.

As for calibrating any individual sensor to better than 0.25'C you can just calibrate in software for the individual sensor, by adding or subtracting as many 16ths as needed.

There is a known "state machine glitch" in the 1820 that was supposedly corrected for the 18S20, it is covered in detail in the Dallas PDF "DS1820-report.pdf" of 03/07/00. That glitch causes some error in the count_remain value but from what I understand has only a low chance of occuring on any one measurement.

That paper also discusses a known temperature drift issue with the 1820, which might also be responsible for some of your 0.25'C error?

Anyway if you want better than 0.25'C accuracy you need to calibrate each sensor, the datasheet for the 18S20 lists accuracys as +/- 0.5'C accuracy from -10'C to +85'C.

Last edited:

#### Mike - K8LH

##### Well-Known Member
The way to test the fraction decoding is to implement it and record the results via terminal to a text file, then slowly change the temperature and there should be all 16 steps sequentially within each degree C. If that occurs then the code is correct.

I can actually track all sixteen sequential steps per degree change on screen and it looks great. The 'Count_Remain' values go from 10h to 01h and rollover and my 'frac' variable ranges from 00h to 0Fh.

There is a known "state machine glitch" in the 1820 that was supposedly corrected for the 18S20, it is covered in detail in the Dallas PDF "DS1820-report.pdf" of 03/07/00. That glitch causes some error in the count_remain value but from what I understand has only a low chance of occuring on any one measurement.

I don't have any DS1820 sensors. I'm using DS18S20 and DS18B20 sensors.

That paper also discusses a known temperature drift issue with the 1820, which might also be responsible for some of your 0.25'C error?

Again, I don't have any DS1820 devices, so that shouldn't be the cause of the delta 0.25° I'm seeing. The difference appears to be introduced by subtracting 1/4° from the temperature value.

It's interesting that the DS18S20 and DS18B20 'Count_Remain' values and the integer portion of the temperature values track perfectly with each other, never more than one count (1/16°) off.

I wonder if the Datasheet Author was somehow trying to account for a 1/4° addition to the fractional value which may have been performed inside the device in order to provide a rounded 1/2° value in the 9-bit temperature result? We may never know (lol). Meanwhile, if I find time, I'll try to test additional sensors. Also, if anyone with both DS18S20 and DS18B20 devices on hand would like to volunteer some research time, I'd be happy to write a test program for whatever device you happen to be using.

Cheerful regards, Mike

#### Steve Martin

##### New Member
Mike,

I've done a lot of work with these very sensors. When I first started, I was also getting errors in the 12-bit conversion. After further analysis, I noticed that the count divisor was not equal to 16 as the data sheet indicated it would be. In fact, as the temperature was raised and lowered, the count divisor would increase and decrease in value (not fixed). After modifying my algorithm to divide by the count reported by the device instead of by a fixed value of 16, the results were spot on.

I do have some devices that have a fixed divisor of 16, but unfortunately that is not a given. If you haven't already, verify your divisor to see if that is the source of your problem.

Steve Martin

#### Mike - K8LH

##### Well-Known Member
Thanks for the info' Steve. I will definitely check it out.

Cheerful regards, Mike

Status
Not open for further replies.

Replies
7
Views
192
Replies
0
Views
310
Replies
0
Views
533
Replies
4
Views
1K
Replies
0
Views
415