Hi! Please consider the following code:
unsigned int beta;
unsigned int theta;
unsigned int m = 4;
unsigned int c = 986;
unsigned int Rpre = 49900;
unsigned int getUAnalog(unsigned char channel) // to get the PT1000 Signal
{
unsigned int result;
unsigned int f_temp;
//select channel and initiate conversion
ADCSC1 |= (channel & 0b11111);
//wait until conversion is complete
while(!ADCSC1_COCO);
f_temp = ADCRH;
f_temp <<= 8;
f_temp += ADCRL;
beta = (((f_temp) / (4096*28))*1000); // warning: possible loss of data.
theta = ((((beta)*(Rpre))/(1-beta))*1000);
result = (theta-c)/(m);
return result;
}
I am using MC9S08DZ60 (http://www.freescale.com/files/microcontrollers/doc/data_sheet/MC9S08DZ60.pdf) with PT1000-Temperature Sensor on CodeWarrior version 5.9.0 . This function is meant to calculate the temp and return "result". But the "beta" and "theta" values remain 0. No Change.
Also i get the warning as C2705: Possible Loss of Data. The value of "result" is not right. PLease help as i dont have clue of what going wrong!!
Thanks in advance!
Have you considered that 4096 x 28 = 114688 is larger than will fit in an integer which for the S08 will be 16 bit?
Breaking down your first line of maths (I added the spaces to make it more readable)
beta = ( ( (f_temp) / (4096*28) ) *1000 )
beta = (f_temp/114688) * 1000; // do the multiplication and get rid of some excess parentheses
Note that you are forcing the compiler to do the division before the multiplication x1000. f_temp by definition is no larger than a 65536. Which means that f_temp/(4096*28) is always < 1. You are performing integer maths so this intermediate value should always result in 0. I think this is why you are getting a warning.
If this is really what you want to do, some of your intermediate variables should be uint32 (unsigned long)
Hi,
The f_temp variable is of integer type.
From your code I think that the f_temp variable could assume values between 0 and 65535 (16 bits), when the (f_temp) / (4096*28) = f_temp / 114.688 is executed the temporary result is between 0 and 1, and being of integer type it is reported as 0.
You should write beta = (((float)(f_temp) / (4096*28))*1000);
Teckna
Thanks teckna! the problem is i cant use float. Codewarrior version doesnt have float lib by default even after including the same it gives me a Link ERROR.
Would multiplying the whole value of "beta" with 1000 help with the answer?
Hi,
Then you should write beta = (f_temp*1000) / (4096*28);
Teckna
Thanks TEKNA!
That doesnt help either. Before you said it, i tried the same.
I tried to use bit shift operators to compute the multiplication and division but i get the warning and error stating unsigned int changed to unsigned char. Is there a better way to use bit shift operators?
Hi
It seems very strange.
The value of beta depends on f_temp:
if f_temp>=115 then beta>0, if f_temp<115 then beta=0, have you verified it?
Also you can try:
beta = f_temp*1000;
beta /= (4096*28);
Teckna
THanks tekna!
Now even i cant think... because what you suggested should logically work; IT DOES NOT! the value of f_temp is coming from the ADC which is always greater than 115.
Hi Sheetansh,
Another thing:
The problem is of the value of beta or in the one of theta?
If f_temp is between 115 and 229 then beta should be 1; in this condition when the statement theta = ((((beta)*(Rpre))/(1-beta))*1000); is executed, the value of 1-beta is 0 (at the denominator): this is a problem.
If f_temp>=230 then should be beta>2 and then (1-beta)<0.
Maybe it should be theta = ((((beta)*(Rpre))*1000)/(1000-beta));
Teckna
Thanks tekna!
the fact is that the compiler doesnt raise any flag for the value of theta. It raises flag only for the value of beta(ie possible loss data). I tried as you suggested still the same.
ALso do you think its possible to perform the same equation using bitshift operator?
Further to my response below, maybe you should try something like:
beta = (unsigned int)((f_temp * 1000uL) / (4096uL*28)); |
better still, to avoid too much truncation:
#define DIVISOR (4096uL * 28)
beta = (unsigned int)((f_temp * 1000uL + DIVISOR/2) / DIVISOR );
You will not get much, if any benefit by trying to use shift operators, since the only real potential is the 4096. But since this needs to be multiplied by 28 anyway, you will need to handle this division regardless.
Hello,
That warning typically indicates that you are assigning a value larger than the destination can hold.
E.g. assigning something like 0x1234 to a 1 byte variable.
I quickly tried your code with CodeWarrior for MCU10.3 and I do not get such a warning, and the code looks ok. It looks like you are using an earlier version of the compiler/tool chain?
Not sure, but this could have been a bug with the optimizer. As a wild guess: could you use the -Ont option to see if this makes a difference?
Thanks Erich, for your reply.
Tool chain version is 6.0;didnt think about it! Also i am relatively new to codewarrior so when you say "-Ont"... i am as lost as ever.
I hope you reply!
-Ont is a compiler option to disable the 'Tree Optimizer'. This optimizer performs optimizations on the logical structure of the program. Looking at the warning and the code, I was thinking that it might have been caused by such an optimization.
You could use the -Ont as command line option, or set it up in the preference panel.
Thanks again erich!
I will try setting up the "-ONT" option to disable the tree optimizer.
I just realised, when i had setup up the project using the wizard, i had not selected the floating point option(IEEE32). Is there a procedure to do the same in the middle of the project??
Yes, this is possible. Basically what you need to do is to change the library used (there is a readme text file on this inside the library folder), plus changing the compiler option.
But if you are rather a new user, it might be easier for you to create a new project with the wizard and either inspect the library/compiler option used, or to use that new project and copy your sources into it.