ATmega8u2, DS18b20 problem negative temperature(please help)

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

HI
I am using ATmega8u2 with C language and need some help.
I am a beginner with C language. I don't know why when get temperature in negative decimals go down instead of up (now I am back: /) and when get temperature digit in negative starting at -1.75 :S
Can who help me please
I added the attached program.

I think it's the problem here:

	digit=temperature[0]>>4;
	digit|=temperature[1]<<4;
	//Store decimal digits
	decimal=temperature[0]&0xf;;
	decimal*=THERM_DECIMAL_STEPS_12BIT;

[/code]

Attachment(s): 

WWW.FLASH-ELECTRONICS.SI

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

I am not really able to read your code - the actual conversion from ADC value - I guess that's in temperature[0] and [1] which are unsigned char type?
Not sure why you are dividing & multiplying by 8 using shift - it's a common missconception that optimisation like that makes code easier to read. Optimise after debugging.

As for your question, without knowing what the constant in

Quote:

decimal*=THERM_DECIMAL_STEPS_12BIT;

is, and why line1&2 seem to be throwing away half of your precision anyway.
Why not do something like:
float tempCelsius = temperature[0] + (temperature[1]*256);
tempCelsius *= CONVERSION; // CONVERSION from ADC to celcius

As a beginner you normally want to take the simple approach, using the float type probably requires you add the math library to your project and, it will limit you to not using a micro with limited flash, but will make your life easier untill you get to the level needed for fancy logic. I love the AVR tools, thay are just so scaleable to your task.

Hope that helps (HTH)

Conrad Braam - www.softcircuitry.blogspot.com - www.plcsimulator.org
Always start off poorly, that way when you finally figure it out, you can get a few surprise hits in.

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

HI, first thanks for helping me.
i help with this http://www.teslabs.com/openplaye...

I do not understand how this change

void therm_read_temperature(char *buffer)
{
	// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
	uint8_t temperature[2];
	int8_t digit;
	uint16_t decimal;
	//Reset, skip ROM and start temperature conversion
	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_CONVERTTEMP);
	//Wait until conversion is complete
	while(!therm_read_bit());
	//Reset, skip ROM and send command to read Scratchpad
	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_RSCRATCHPAD);
	//Read Scratchpad (only 2 first bytes)
	temperature[0]=therm_read_byte();
	temperature[1]=therm_read_byte();
	therm_reset();
	//Store temperature integer digits and decimal digits
	digit=temperature[0]>>4;
	digit|=temperature[1]<<4;
	float tempCelsius = temperature[0] + (temperature[1]*256); 
	tempCelsius *= THERM_CMD_CONVERTTEMP; // CONVERSION from ADC to celcius 
	//Store decimal digits
	decimal=temperature[0]&0xf;;
	decimal*=THERM_DECIMAL_STEPS_12BIT;
	//Format temperature into a string [+XXX.XXXX C]
	sprintf(buffer, "%+d.%02u", digit, decimal);
}

WWW.FLASH-ELECTRONICS.SI

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

All right - ok when using sample code, you probably want to check that you are reading the device values back via the protocol as expected. This sensor is not easy to talk to, and if your clock is not accurate, you could missread the data. I would write this:

sprintf(buffer, "%d :%u", temperature[0], temperature[1]);

Write down the values, and then whip out my calculator, and do the math, while looking at the weather report. If you get the expected value not, swap replacement sensor, check power supply, and then warm the sensor by blowing on it close by, and redo.

Conrad Braam - www.softcircuitry.blogspot.com - www.plcsimulator.org
Always start off poorly, that way when you finally figure it out, you can get a few surprise hits in.

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

Welcome on AVR forum.

First of all I can see you use usb82. That is great. However it seems you use a DFU bootloader (with FLIP).
Inserting floats means that you will run out of flash in no time (you have already used 96%, as DFU takes 4kB). There is no need to use floats with DS18B20 just to display the temperature.

temperature[0] and temperature[1] are two bytes containing 12 bit readout. Although it is scaled in Celsius degrees, data format is a little cunning. Put fractional part(bit 0:3 of temperature[0]) into one 16-bit variable (to multiply it by 625), and full centigrade part into 8-bit variable.

My suggestion is you should get original pdf of DS18B20 and there is a table with relationship between these two bytes and actual temperature. Buy some ice-creams and get to work!

And do not use floats on a 4k device!

No RSTDISBL, no fun!

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

Thanks Brutte on pointing out the use of a mega8, I missed that, I had/have no idea what a DFU bootloader was. And there I was promoting using 'float' as a debugging tool without first checking what the project scope was.
I shall buy an ice cream myself and a few Dallas Sensor chips :-) Good luck luka 1995

Conrad Braam - www.softcircuitry.blogspot.com - www.plcsimulator.org
Always start off poorly, that way when you finally figure it out, you can get a few surprise hits in.

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

Quote:
And there I was promoting using 'float'

Now I noticed it was your suggestion.. That is not a problem because it would simply not compile (out of program memory).

These DS sensors are really wonderful, but they need a sophisticated code to check for run-time errors..

Another difficulty is testing them for negative values in the summer. Hopefully they are not scaled in Fahrenheit degrees!

No RSTDISBL, no fun!

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

AVR Memory Usage
----------------
Device: atmega8u2

Program: 3910 bytes (47.7% Full)
(.text + .data + .bootloader)

i am using atmega8u2 because i dont have programmer, i am programming atmega8u2 with usb (DFU bootloader).
I am a beginner in programming. :(

WWW.FLASH-ELECTRONICS.SI

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

Quote:

AVR Memory Usage
----------------
Device: atmega8u2

Program: 3910 bytes (47.7% Full)
(.text + .data + .bootloader)


But Brutte's point was that you don't get the entire 8K for your use because the DFU bootloader is consuming 4K or the 8K available so your 3910 bytes is just 186 bytes from filling the space you have available.

You may want to explore LUFA and see if any of Dean's bootloaders for the USB AVRs could fit in 2K which would leave 6K of the 8U2 for your use. However to load such a bootloader into the chip would require an ISP programmer and, if you had one of those, you wouldn't need to use a bootloader and USB to program the chip so you could then use all 8K.

Presumably you are using 8U2 because your ultimate application itself will use USB? I guess you will use LUFA for this too? Be warned that the USb support itself could occupy several K of the chip.

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

Up it's a program just for sensors (2x (DS18b20) maxim samples)...
and I think that I will no longer put up on atmega8u2 (4K 50%).
Only problem is that the negative temperature is not working and I don't know how to fix this :S

i insert the video for see
http://www.flash-electronics.si/...
this its problem when get temperature in negative...
bye from slovenia

WWW.FLASH-ELECTRONICS.SI

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

to get the DS18B20 temp using the MSB and LSB

temp(in Celsius) =
(-1*((8&MSB)>>3))*(
(64*((4&MSB)>>2))+
(32*((2&MSB)>>1))+
(16*(1&MSB))+
(8*((128&LSB)>>7))+
(4*((64&LSB)>>6))+
(2*((32&LSB)>>5))+
(1*((16&LSB)>>4))+
(0.5*((8&LSB)>>3))+
(0.25*((4&LSB)>>2))+
(0.125*((2&LSB)>>1))+
(0.0625*(1&LSB)))

that should give you the direct Celsius reading from the MSB/LSB bytes. You can take out the last four to get the integer part only (to avoid using float).

Last Edited: Tue. Jun 14, 2011 - 10:56 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how to use this in code?

WWW.FLASH-ELECTRONICS.SI

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

thats is just one long addition multiplied to the negative sign

temperature[0] I believe is your MSB and temperature[1] is your LSB

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

it does not work.
I think this is wrong?

	//Store temperature integer digits and decimal digits
	digit=temperature[0]>>4;
	digit|=temperature[1]<<4;
	//Store decimal digits
	decimal=temperature[0]&0xf;;
	decimal*=THERM_DECIMAL_STEPS_12BIT;
	//Format temperature into a string [+XXX.XXXX C]
	sprintf(buffer, "%+d.%02u", digit, decimal);

has anyone ever been played with these sensors?

WWW.FLASH-ELECTRONICS.SI

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

test

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

try substitute temperature[0] to MSB and temperature[1] to LSB and do the one operation i gave you.

I those sensors in one of my project

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
void therm_read_temperature(char *buffer)
{
	// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
	uint8_t temperature[2];
	int8_t digit;
	uint16_t decimal;
//////////

	//Reset, skip ROM and start temperature conversion
	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_CONVERTTEMP);
	//Wait until conversion is complete
	while(!therm_read_bit());
	//Reset, skip ROM and send command to read Scratchpad
	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_RSCRATCHPAD);
	//Read Scratchpad (only 2 first bytes)
	temperature[0]=therm_read_byte();
	temperature[1]=therm_read_byte();
	therm_reset();
	//Store temperature integer digits and decimal digits
temperature(in Celsius) = 
(-1*((8&temperature[0])>>3))*( 
(64*((4&temperature[0])>>2))+ 
(32*((2&temperature[0])>>1))+ 
(16*(1&temperature[0]))+ 
(8*((128&temperature[0])>>7))+ 
(4*((64&temperature[0])>>6))+ 
(2*((32&temperature[0])>>5))+ 
(1*((16&temperature[0])>>4))+ 
(0.5*((8&temperature[0])>>3))+ 
(0.25*((4&temperature[0])>>2))+ 
(0.125*((2&temperature[0])>>1))+ 
(0.0625*(1&temperature[0]))) 
	//Format temperature into a string [+XXX.XXXX C]
	sprintf(buffer, "%+d.%02u", digit, decimal);
}
../therm_ds18b20.c:103: error: 'in' undeclared (first use in this function)
../therm_ds18b20.c:103: error: (Each undeclared identifier is reported only once
../therm_ds18b20.c:103: error: for each function it appears in.)
../therm_ds18b20.c:103: error: expected ')' before 'Celsius'
../therm_ds18b20.c:103: error: called object 'temperature' is not a function
../therm_ds18b20.c:117: error: expected ';' before 'sprintf'
../therm_ds18b20.c:85: warning: unused variable 'decimal'
../therm_ds18b20.c:84: warning: unused variable 'digit'
make: *** [therm_ds18b20.o] Error 1
Build failed with 6 errors and 2 warnings...

WWW.FLASH-ELECTRONICS.SI

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

dude, its not a straight copy paste, you gotta make sure you declare the variables and put the right semicolon

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

temp_temp = (-1*((8&temperature[0])>>3))*(
(64*((4&temperature[0])>>2))+
(32*((2&temperature[0])>>1))+
(16*(1&temperature[0]))+
(8*((128&temperature[1])>>7))+
(4*((64&temperature[1])>>6))+
(2*((32&temperature[1])>>5))+
(1*((16&temperature[1])>>4))+
(0.5*((8&temperature[1])>>3))+
(0.25*((4&temperature[1])>>2))+
(0.125*((2&temperature[1])>>1))+
(0.0625*(1&temperature[1])));

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

i get error for this line (0.0625*(1&temperature[1])));

../therm_ds18b20.c:114: error: incompatible types in assignment
make: *** [therm_ds18b20.o] Error 1
Build failed with 1 errors and 0 warnings...

WWW.FLASH-ELECTRONICS.SI

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

int temp_temp;

temp_temp =
(64*((4&temperature[0])>>2))+
(32*((2&temperature[0])>>1))+
(16*((1&temperature[0])>>0))+
(8*((128&temperature[1])>>7))+
(4*((64&temperature[1])>>6))+
(2*((32&temperature[1])>>5))+
(1*((16&temperature[1])>>4));

try that instead to get just the integer part

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

that code work, now is calibrated to +0.00 * C !,
"just not working sensor, the temperature does not change"

WWW.FLASH-ELECTRONICS.SI

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

void therm_read_temperature(char *buffer)
{
// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
uint8_t temperature[2];
int8_t digit;
uint16_t decimal;
//////////

//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete
while(!therm_read_bit());
//Reset, skip ROM and send command to read Scratchpad
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_RSCRATCHPAD);
//Read Scratchpad (only 2 first bytes)
temperature[0]=therm_read_byte();
temperature[1]=therm_read_byte();
therm_reset();
//Store temperature integer digits and decimal digits
int temperature_temperature;

temperature_temperature =
(64*((4&temperature[0])>>2))+
(32*((2&temperature[0])>>1))+
(16*((1&temperature[0])>>0))+
(8*((128&temperature[1])>>7))+
(4*((64&temperature[1])>>6))+
(2*((32&temperature[1])>>5))+
(1*((16&temperature[1])>>4));

//Format temperature into a string [+XXX.XXXX C]
sprintf(buffer, "%+d.%02u", digit, decimal);
}

WWW.FLASH-ELECTRONICS.SI

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

WWW.FLASH-ELECTRONICS.SI

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
temp=(high<<8) | low;
temperature=(int16_t)(((int32_t)temp*100)/16);
temperature_int=temperature/100;
temperature_frac=abs(temperature % 100);
printf("%3d.%02d",temperature_int,temperature_frac);
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
(((int32_t)temp*100)/16);

Isn't it loosing precision on division?
When temp=0x0001(which means +0.0625*C), it would output:

uint16_t(0x00000064/0x10)=0x0006

No RSTDISBL, no fun!

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

i don't know how to using this code

WWW.FLASH-ELECTRONICS.SI

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

Quote:
Isn't it loosing precision on division?

Precision of two decimals... more is even more fake precision.

If you really want more, just use 1000 instead of 100, and adjust the division/mod to use 1000 too.

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

can you try print out the value of temperature[0] and temperature[1] right after the last therm_reset() call? That way we can see if its giving the right value

sprintf(buffer, "%+d.%02u", digit, decimal);

And change this code to print the value of temperature_temperature instead

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

sprintf(buffer, "%+d.%02u", temperature_temperature);

WWW.FLASH-ELECTRONICS.SI