简体   繁体   English

方程似乎在嵌入式 C (stm32) 中输出错误值

[英]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.我正在定制 BMS PCB 上的 STM32 F103 C8T6 微控制器上的嵌入式 C 代码,但我对根据热敏电阻 ADC 值计算实际温度的代码有一些问题。

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 .通过excel,我们确定了我们需要使用从ADC值来计算摄氏温度的公式是: 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:因此,在我的代码中,我有以下几行,其中 temp[i] 是原始 ADC 值,realTemp[i] 是转换后的值:

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.我没有使用 math.h 中的 pow 函数,因为它过去给我们带来了问题。

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.我们在 temp[i] 变量中得到的值如下:35480、35496、35393、35480。当在 excel 中将这些值与我们的函数一起使用时,我们得到了正确的输出,介于 25.3 和 25.5 摄氏度之间,但是 C上面列出的代码在 realTemp 数组中输出 36。 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.我不确定十进制值,但我不关心它们,因为该值在几行之后被类型转换为 uint16,以便通过 CAN 总线传输。

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 .正如其他人所说,您正在进行整数除法,然后将结果转换为double - 您需要将除法本身作为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 .如果您决定通过切换到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. Chux 的回答是正确的,我只是想更多地解释一下为什么会这样。

temp[i] is uint16 , therefore the formula temp[i] / 10000 is integer division, and result will be the floor of (temp[i] / 10000) . temp[i]uint16 ,因此公式temp[i] / 10000是整数除法,结果将是(temp[i] / 10000)的底。 Thus, the final conversion to double is performed on a value which is floored already.因此,最终转换为double是在一个已经下限的值上执行的。

By converting 10000 to 10000.0 , it means that the division of an integer with a float/double will perform floating division.通过将10000转换为10000.0 ,这意味着用float/double对整数进行除法将执行浮点除法。 By this, the result will be similar to what you expected.这样,结果将与您的预期相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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