magicianiam
magicianiam

Reputation: 1579

C equation returns different value than my calculated value

I have this equation in solving the temperature from a temperature sensor.

variables are:

unsigned char AD_DATA; values is usually 100- 110;
int TEMP;

the original equation:

TEMP = 50 - (AD_DATA * 175) / 1000;

I changed that to:

TEMP = 500 - (AD_DATA * 1750) / 1000;

the reason for this is because TEMP is an integer, and thus on the first equation when it is calculated that there is a decimal it will be automatically rounded, so i changed it so that decimal will be included in the number.

The reason why I am not using float is because in the MCU I am using, whenever I declare a float variable inside the ISR(interrupt service routine) it will return an error thus I needed to be creative in using only INT, double will also return an error.

Now using an AD_DATA value of 100

the 1st equation will result to: 32.5, but since its an int it is now 33.

the 2nd equation should output 325, but in my output is 521

I need to include the decimal in my display thus it is really important for it to be included in the equation.

My ISR routine:

__interrupt void ADC_int(void){
IO_ADCSH.bit.INT = 0;
AD_DATA = IO_ADCRLH.DATA8;
TEMP = 500 - (AD_DATA * 1750) / 1000;
}

MCU specs

int 2bytes
long 4bytes
unsigned char 1byte

Upvotes: 2

Views: 121

Answers (2)

anatolyg
anatolyg

Reputation: 28241

As a quick hack, you can replace (AD_DATA * 1750) / 1000 by (AD_DATA * 7) / 4.

For more ideas, read below.


Note that by changing

TEMP = 50 - (AD_DATA * 175) / 1000;

to

TEMP = 500 - (AD_DATA * 1750) / 1000;

you changed the meaning of the TEMP variable. Assuming it means "temperature" (doesn't really matter), it meant "temperature in degrees", and now it means "temperature in units of 1/10 degree". However, why did you multiply by 10? Just for convenience, I guess - you are not obliged to use powers of 10 for your units. You can use any other number, provided you remember what it was, and treat the result TEMP accordingly (e.g. divide it by 10 when printing it out). So the best number to use is 40: it eliminates a division (or rather, postpones it to later lines of code) and so avoids a loss of precision.

TEMP_MULTIPLIED_BY_40 = 2000 - AD_DATA * 7;

Upvotes: 5

dvhh
dvhh

Reputation: 4750

My first guess according to the information you gave, is that the register length is 16bits causing the operand to overflow when you multiply AD_DATA by 1000.

the largest value a int could hold is 32762 (from the top of my head , more like 0x7FFF), even unsigned it is insufficient to hold AD_DATA*1000 ( wich in you case would be 18*1000=18000 ), the value will be truncated to 16bits, giving a negative number in the process.

you can fix that by specifying the length of your operator in your expression and casting AD_DATA to a 32bit word.

Upvotes: 3

Related Questions