DS18B20 with only OneWire library

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, i found an article about using DS18B20 temperature sensor with just OneWire library, the problem is the accuracy is set to 1 degree:

 

#include <OneWire.h>
int16_t dallas(int x,byte start){
    OneWire ds(x);
    byte i;
    byte data[2];
    int16_t result;
    do{
        ds.reset();
        ds.write(0xCC);
        ds.write(0xBE);
        for (int i = 0; i < 2; i++) data[i] = ds.read();
        result=(data[1]<<8) |data[0];
        result>>=4; if (data[1]&128) result |=61440;
        if (data[0]&8) ++result;
        ds.reset();
        ds.write(0xCC);
        ds.write(0x44, 1);
        if (start) delay(1000);
    } while (start--);
    return result;
}
void setup{
  dallas(A0,1);
}
void loop{
  float currentTemp = dallas(A0,0);
}

How can i get accuracy of .5 degree from this?

 

PS: i just copy/pasted above code from the site that i linked above, i don't know what's happening or what code doing what! i'm new to arduino and that is some advanced C++ for me!

Last Edited: Tue. Jul 16, 2019 - 04:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As the article explains the logic of that is very confused - he seems to be obfuscating the implication simply to get it to operate quickly. You have to wonder why. It's not like temperature suddenly deviates from one microsecond to the next. It probably changes at the rate (max) of about 0.1C per minute. So I wouldn't use code just because it can make a "fast" reading.

 

I just googled "DS18B20 Arduino" and a far clear implementation seems to be:

 

http://www.hobbytronics.co.uk/ds18b20-arduino

 

As the print out at the end shows that appears to be making reading accurate to a fraction of a degree. The article indirectly references:

 

https://www.milesburton.com/Dallas_Temperature_Control_Library

 

which in turn leads to:

 

https://github.com/milesburton/Arduino-Temperature-Control-Library

 

In amongst things that includes:

 

https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/DallasTemperature.cpp#L249

 

which appears to give you control  over resolution (ie bit depth).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

As the article explains the logic of that is very confused - he seems to be obfuscating the implication simply to get it to operate quickly. You have to wonder why. It's not like temperature suddenly deviates from one microsecond to the next. It probably changes at the rate (max) of about 0.1C per minute. So I wouldn't use code just because it can make a "fast" reading.

 

I just googled "DS18B20 Arduino" and a far clear implementation seems to be:

 

http://www.hobbytronics.co.uk/ds18b20-arduino

 

As the print out at the end shows that appears to be making reading accurate to a fraction of a degree. The article indirectly references:

 

https://www.milesburton.com/Dallas_Temperature_Control_Library

 

which in turn leads to:

 

https://github.com/milesburton/Arduino-Temperature-Control-Library

 

In amongst things that includes:

 

https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/DallasTemperature.cpp#L249

 

which appears to give you control  over resolution (ie bit depth).

Thanks but i don't wanna use libraries because those interrupt with the timers that i have in my project (slow down the whole process), is there any way to manipulate that piece of code to get .5 degree accuracy?

Last Edited: Tue. Jul 16, 2019 - 04:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Josh1970 wrote:
i don't wanna use libraries because those interrupt with the timers that i have in my project
What, I wonder, does that have to do with the price of rice in China? There's nothing in the code I linked to using interrupts that might interfere with anything timing critical you might have going on.

 

Would you avoid using strcpy() or sprintf() from the C library based on the same argument that "library code should be avoided" ??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Josh1970 wrote:
i don't wanna use libraries because those interrupt with the timers that i have in my project
What, I wonder, does that have to do with the price of rice in China? There's nothing in the code I linked to using interrupts that might interfere with anything timing critical you might have going on.

 

Would you avoid using strcpy() or sprintf() from the C library based on the same argument that "library code should be avoided" ??

 

i commented out my code piece by piece till i found the slow down problem was from the DS18B20 library, after removing that and adding OneWire only DS18B20 sensor code which i posted the slow down problem disappeared.

 

so can you please help me with the question?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Josh1970 wrote:
i don't wanna use libraries because those interrupt with the timers that i have in my project
What, I wonder, does that have to do with the price of rice in China? There's nothing in the code I linked to using interrupts that might interfere with anything timing critical you might have going on.

 

Would you avoid using strcpy() or sprintf() from the C library based on the same argument that "library code should be avoided" ??

i asked the question here too: https://arduino.stackexchange.co...

and someone answered the question, but when i use the code he provided i get a temperature of above 400 degree, here's how i implanted the provided code:

 

#include <OneWire.h>
int16_t dallas(int x,byte start){
    OneWire ds(x);
    byte i;
    byte data[2];
    int16_t result;
    do{
        ds.reset();
        ds.write(0xCC);
        ds.write(0xBE);
        for (int i = 0; i < 2; i++) data[i] = ds.read();
        result=(data[1]<<8) |data[0];
        int16_t whole_degree = result >> 4;
        if (data[1] & 128) result |= 61440;
        whole_degree + 0.5 * ((data[0] & 0x8) >> 3) + 0.25 * ((data[0] & 0x4) >> 2) + 0.125 * ((data[0] & 0x2) >> 1) + 0.625 * (data[0] & 0x1);
        if (data[0]&8) ++result;
        ds.reset();
        ds.write(0xCC);
        ds.write(0x44, 1);
        if (start) delay(1000);
    } while (start--);
    return result;
}
void setup{
  dallas(A0,1);
}
void loop{
  float currentTemp = dallas(A0,0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Josh1970 wrote:
so can you please help me with the question?
I thought I already did? I pointed you to some seemingly well engineered code which makes it quite clear how to set device resolution. The routine I pointed to at:

 

https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/DallasTemperature.cpp#L249

 

does:

void DallasTemperature::setResolution(uint8_t newResolution) {

	bitResolution = constrain(newResolution, 9, 12);
	DeviceAddress deviceAddress;
	for (int i = 0; i < devices; i++) {
		getAddress(deviceAddress, i);
		setResolution(deviceAddress, bitResolution, true);
	}

}

The implementation of setResolution() immediately follows:

bool DallasTemperature::setResolution(const uint8_t* deviceAddress,
		uint8_t newResolution, bool skipGlobalBitResolutionCalculation) {

	// ensure same behavior as setResolution(uint8_t newResolution)
	newResolution = constrain(newResolution, 9, 12);

	// return when stored value == new value
	if (getResolution(deviceAddress) == newResolution)
		return true;

	ScratchPad scratchPad;
	if (isConnected(deviceAddress, scratchPad)) {

		// DS1820 and DS18S20 have no resolution configuration register
		if (deviceAddress[0] != DS18S20MODEL) {

			switch (newResolution) {
			case 12:
				scratchPad[CONFIGURATION] = TEMP_12_BIT;
				break;
			case 11:
				scratchPad[CONFIGURATION] = TEMP_11_BIT;
				break;
			case 10:
				scratchPad[CONFIGURATION] = TEMP_10_BIT;
				break;
			case 9:
			default:
				scratchPad[CONFIGURATION] = TEMP_9_BIT;
				break;
			}
			writeScratchPad(deviceAddress, scratchPad);

			// without calculation we can always set it to max
			bitResolution = max(bitResolution, newResolution);

			if (!skipGlobalBitResolutionCalculation
					&& (bitResolution > newResolution)) {
				bitResolution = newResolution;
				DeviceAddress deviceAddr;
				for (int i = 0; i < devices; i++) {
					getAddress(deviceAddr, i);
					bitResolution = max(bitResolution,
							getResolution(deviceAddr));
				}
			}
		}
		return true;  // new value set
	}

	return false;

}

I don't intend to dig out the Dallas datasheet myself but it's pretty clear that:

	ScratchPad scratchPad;

defines a "scratchpad" which mimics the registers in the device. The code then makes a choice such as:

scratchPad[CONFIGURATION] = TEMP_10_BIT;

which is clearly updating the "CONFIGURATION" entry in that set. Then the code goes on to:

writeScratchPad(deviceAddress, scratchPad);

One would need to fig further in to this code but it seems very easy to read. For example, elsewhere we find a neatly laid out:

// Scratchpad locations
#define TEMP_LSB        0
#define TEMP_MSB        1
#define HIGH_ALARM_TEMP 2
#define LOW_ALARM_TEMP  3
#define CONFIGURATION   4
#define INTERNAL_BYTE   5
#define COUNT_REMAIN    6
#define COUNT_PER_C     7
#define SCRATCHPAD_CRC  8

revealing that "CONFIGURATION" is the 5th byte in the register array.

 

If pushed still further one might examine:

void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress,
		const uint8_t* scratchPad) {

	_wire->reset();
	_wire->select(deviceAddress);
	_wire->write(WRITESCRATCH);
	_wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
	_wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp

	// DS1820 and DS18S20 have no configuration register
	if (deviceAddress[0] != DS18S20MODEL)
		_wire->write(scratchPad[CONFIGURATION]);

	_wire->reset();

	// save the newly written values to eeprom
	_wire->select(deviceAddress);
	_wire->write(COPYSCRATCH, parasite);
	delay(20); // <--- added 20ms delay to allow 10ms long EEPROM write operation (as specified by datasheet)

    if (parasite) {
		activateExternalPullup();
		delay(10); // 10ms delay
		deactivateExternalPullup();
	}
    _wire->reset();

}

That, clearly, is where the actual byte(s) transfer to the device occurs.

 

EDIT: actually I did go back and look at the datasheet and find:

 

 

So I was able to determine the operation of the device purely by reading this C++ code. As such I would suggest it is fairly high quality C++ code if the operation is so clear from a quick scan of the code.

Last Edited: Tue. Jul 16, 2019 - 05:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I thought I already did?

 

I am very ashamed to say i don't understand all that data you provided, i'm an old man how just wants to get this working without stepping and drowning in C++ world!

 

it's very rude to ask someone to do the coding for you; but if you have the time and it's not a burden can you please just modify the code that is in my very first post so i can just past it here and get this thing working and finished?

I'd do it my self if i could, it's just too advanced for me...

 

i appreciate that you did all those research, thank you.

Last Edited: Tue. Jul 16, 2019 - 05:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As a general rule. You issue a command to a peripheral and then get on with your life.
When the peripheral has completed the task it sets a bit.
Some external devices can interrupt to signal the completion.
Or you just poll the device to check for yourself.
The read operation is trivial.
.
Think about it. Implementing an ADC conversion takes several microseconds. Reading the result is less than a microsecond.
Likewise it takes 1040us for the USART to send one char at 9600 baud.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Josh1970 wrote:
i'm an old man
If the 1970 in your ID is what I think it is then I beat you on that score! ;-)



So anyway, when I look at the code you have doing things like:

        ds.reset();
        ds.write(0xCC);
        ds.write(0x44, 1);

I wondered what that was doing. As it happens most of what you need to know is given in this one page in the datasheet:

There is the CC and 44 that are already used in your code.

 

From that other code I analysed I can see that changing the bit depth involves writing the config register and the text above shows that you can read the "scratchpad" with a BE command and write it with a 4E. So using code close to what you already have it looks like you'd want to send Be, then read further bytes that get you what's in the scrathcpad. Then you could issue 4E then send three bytes - two unchanged then the modified value for "configuration".

 

HOWEVER the datasheet says the device defaults to the max 12 bit mode anyway - so all this could be a wild goose chase.

 

What leads you to believe the thing is only reading to an accuracy of 1C anyway? That sounds like it might simply be a float to integer truncation or something??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

What leads you to believe the thing is only reading to an accuracy of 1C anyway? That sounds like it might simply be a float to integer truncation or something??

 

Honestly i have no idea, i'm totally lost!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The OPs Dallas function returns an integer, which he converts to float, so his result will always be an integer value. The Dallas function needs to return a float with the required resolution.
Jim

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
stack gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can read the (thermometer) ADC with less bits of resolution.    e.g. faster

 

This is all fairly unimportant.   There is no urgency to read temperatures very often (unless you are monitoring a nuclear explosion)

In which case you would not choose DS18B20.

 

You just need to trigger a new conversion periodically.

And read the result when you know it has completed.    There is no point in ever sitting in a wait-loop.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

You can read the (thermometer) ADC with less bits of resolution.    e.g. faster

 

This is all fairly unimportant.   There is no urgency to read temperatures very often (unless you are monitoring a nuclear explosion)

In which case you would not choose DS18B20.

 

You just need to trigger a new conversion periodically.

And read the result when you know it has completed.    There is no point in ever sitting in a wait-loop.

 

David.

 

i did changed the bit resolution of dallas temperature library:

  sensors.begin()
  sensors.setResolution(9);

but it's still slow down the processing.

Last Edited: Tue. Jul 16, 2019 - 06:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

  I found a DS18b20 attached to a 10-meter/yard long twisted-trio length of wire-wrap AWG30 recently and so added it as an indoor/outdoor thermometer to my DFplayer MP3 Arduino protoboard.

  I used the "standard" Adafruit  OneWire.h library, which seems to work OK.   In the examples section of the library, the programs have a 750 to 1000 mS delay statement that prevents reading the device to many times a second.  Could this be what is causing the delays that you see when changing the configuration?

 

Whatever you are doing that requires 0.5-1 degree repeatablely-measurable accuracy really shouldn't be done with a 30-cent temperature sensor like the 18B20.  And what are you using for a temperature measurement reference standard?  A few years ago, our lab bought four different manufacturer's $100+ "precision temperature devices".  The measured temperatures varied by as much as 5 degrees Fahr between the devices.  Sure they all tracked precise changes in temperature accurately, but there were four different measured room temperatures.  And no way to calibrate any of the units.

 

These sensors are meant to be used in a chain-wired bus with many devices attached to the same V+_gnd_data wire set, say for example on various sections of a Diesel engine.  For that reason, they are designed to transmit their data very fast.  I can't see how reading or configuring a DS18x20 could affect or influence reading or using the Arduino timers.   Arduino only uses Timer0 for the millis(() function, and that just updates a 32-bit long value 1000 times a second.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:

These sensors are meant to be used in a chain-wired bus with many devices attached to the same V+_gnd_data wire set, say for example on various sections of a Diesel engine.  For that reason, they are designed to transmit their data very fast.  I can't see how reading or configuring a DS18x20 could affect or influence reading or using the Arduino timers.   Arduino only uses Timer0 for the millis(() function, and that just updates a 32-bit long value 1000 times a second.

 

check out this link: https://arduino.stackexchange.co...

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Josh1970 wrote:

... the problem is the accuracy is set to 1 degree:

 

From the source code in Post#1:

result>>=4; 

The above line is limiting the resolution to 1 degree.

 

Try the following: (not tested)

 

#include <OneWire.h>
float dallas(int x,byte start){
    OneWire ds(x);
    byte i;
    byte data[2];
    uint16_t result;
    byte sign = 0;  // 0=positive, 1=negative
    do{
        sign = 0;
        ds.reset();
        ds.write(0xCC);
        ds.write(0xBE);
        for (int i = 0; i < 2; i++) data[i] = ds.read();
        result=(data[1]<<8) | data[0];
        if (result & 0x8000) {                  
          result = ~result + 1; //2's complement
          sign = 1; // temperature is negative   
        }                                       
        celsius = (float)result / 16.0;          
        if (sign == 1) celsius = -celsius;      
        ds.reset();
        ds.write(0xCC);
        ds.write(0x44, 1);
        if (start) delay(1000);
    } while (start--);
    return celsius;
}
void setup{
  dallas(A0,1);
}
void loop{
  float currentTemp = dallas(A0,0);
}

 

Edit - added sign=0 and if(sign) ...

Last Edited: Tue. Jul 16, 2019 - 08:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Let me offer an analogy.

 

Your granny is very fond of you.    She will knit a pair of socks for you.

 

You can either sit outside her front door and wait for the socks to be ready.

Or you just call in the next and every day for a fresh pair of socks.

 

Your granny is happy.   You have got on with your important life.   And your feet are warm and comfy.

 

Yes,   you can take the doorstep approach.    Your granny will not produce any more socks.     It wastes your time and probably annoys your granny if she has to answer her doorbell every second.

 

This is exactly how your PC manages to "run" several programs at once.    All the individual grannies manage disk drives, keyboards, screens, modems, ...

Each granny phones you when she is ready (interrupt).   Or you call in after she has had enough time to finish the socks (polling).

 

David.

Last Edited: Tue. Jul 16, 2019 - 08:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you guys have such a nice community here and the replys were very informative and helpful, i managed to solve the problem with the help of a friend. thanks everyone specially clawson.

Last Edited: Tue. Jul 16, 2019 - 08:46 PM