0

我想使用 PIC18F14K50 的 ADC 外设计算电压。结果范围在 0-1023(10 位)之间。所以我用了这个简单的计算:

uint16_t voltage = ADC_Result * 5000 / 1023;

但是,结果是不正确的。我猜发生了算术溢出。我尝试了许多括号的组合,改变元素的顺序等
。最好的结果是 4088,ADC_Result而使用下面的代码是 1023;这离5000还差得很远。

uint16_t voltage = ADC_Result * (5000 / 1023);

我应该怎么做才能在上述计算中获得更好的结果?请不要建议浮点,因为它们会在 MCU 中造成灾难!他们使用大量资源而没有任何实际利益。

4

3 回答 3

2

您可以使用更广泛的类型进行中间乘法,例如:

uint16_t voltage = (uint32_t)ADC_Result * 5000 / 1023;

编辑

如果除以 1023 太慢,您可以通过将 5000 / 1023 更改为 5005 / 1024 来获得大致相等的转换,这可以使用快速位移进行除法:

uint16_t voltage = (uint32_t)ADC_Result * 5005 >> 10;

注意 1023 * 5005 / 1024 ≃ 5000.1123

于 2020-06-19T16:05:44.870 回答
0

我应该怎么做才能在上述计算中获得更好的结果?

OP 的代码溢出 1`6 位数学。


要获得正确和四舍五入的结果,请使用更广泛的数学和偏移量。

// uint16_t voltage = ADC_Result * 5000 / 1023;
uint16_t voltage = (ADC_Result * 5000LU + 1024u/2) / 1024u;
// or
#include <stdint.h>
...
uint16_t voltage = (ADC_Result * UINT32_C(5000) + 1024u/2) / 1024u;

Lin5000LU至少提供 32 位数学运算。

用于U可能更简单/更快的数学和更简单的舍入ADC_Result不是负数。

+ 1024/2影响最接近的舍入而不是截断。

考虑到 A/D 转换器的通常特性,使用 1024 而不是 1023 来进行正确缩放。附带好处:更快的除法,因为 1024 是 2 的幂。

于 2020-06-20T01:14:39.203 回答
0

您应该为此计算使用更广泛的整数类型,例如uint32_t.

在您的情况下,1023 * 5000 == 3192(因为实际结果 5115000 不适合),所以这是不正确的。5000 / 1023 == 4,这是整数除法的预期结果。除以ADC_Result1023 将导致相同的行为。

您可以计算它uint32_t,然后检查它是否适合uint16_t

uint32_t result_tmp = ADC_Result * (5000 / 1023);
uint16_t result;

if (result > 0xffff) {
    // this won't fit
} else {
    result = (uint16_t) result_tmp;
}
于 2020-06-19T16:06:01.893 回答