简体   繁体   中英

Equation seems to be outputting wrong value in embedded C (stm32)

Hope you're having a nice day.

I'm encountering a weird issue on my side. I am working on embedded C code on an STM32 F103 C8T6 micro controller on a custom BMS PCB, but I am having some issue with the code that calculates the actual temperature from the thermistor ADC value.

Through excel, we have determined that the equation we need to use to calculate the temperature in Celsius from the ADC value is: y = -0.5022x^5 + 6.665x^4 - 35.123x^3 + 92.559x^2 - 144.22x + 166.76 .

So, in my code I have the following lines, with temp[i] being the raw ADC value and realTemp[i] being the converted value:

realTemp[i] = (double)(temp[i] / 10000);
realTemp[i] = -0.5022 * realTemp[i]*realTemp[i]*realTemp[i]*realTemp[i]*realTemp[i] + 6.665 * realTemp[i]*realTemp[i]*realTemp[i]*realTemp[i] - 35.123 * realTemp[i]*realTemp[i]*realTemp[i] + 92.559 * realTemp[i]*realTemp[i] - 144.22 * realTemp[i] + 166.76;

I am not using the pow function from math.h as it has given us issues in the past.

The values we are getting in our temp[i] variable are the following: 35480, 35496, 35393, 35480. When using these values with our function in excel, we are getting the correct output, between 25.3 and 25.5 Celsius, however the C code listed above is outputting 36 in the realTemp array. I am not sure about the decimal values, but I don't care about them because the value is typecast to a uint16 a few lines later to be transmitted over a CAN bus.

Use floating point division, not integer division.

// Integer division ------v-------------v       
// realTemp[i] = (double)(temp[i] / 10000);
realTemp[i] = temp[i] / 10000.0;

As others have said, you are doing integer division then casting the result to a double - you need to do the division itself as a double .

Your code will be big and very slow on the micro-controller in question. This might not be an issue, assuming that temperature values don't usually change very often, so slow code could be fine for you.

You also need to be careful with high-degree polynomials - they can easily be unstable, especially if you try to extrapolate them to very high or low temperatures. This is a particularly risky if you decide to make the code faster by switching to a float .

A better method of this kind of thing is usually a lookup table (which can be big but is simpler to implement), or with a linear spline (which has smaller footprint but a bit more complex to implement).

The answer by Chux is correct, I just wanted to explain more why this works.

temp[i] is uint16 , therefore the formula temp[i] / 10000 is integer division, and result will be the floor of (temp[i] / 10000) . Thus, the final conversion to double is performed on a value which is floored already.

By converting 10000 to 10000.0 , it means that the division of an integer with a float/double will perform floating division. By this, the result will be similar to what you expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM