浮点(双精度)值在带有其他值的字符串中被破坏

问题描述 投票:1回答:1

我正在使用ATMEGA328PB AVR微控制器,并且通过UART发送某些浮点数时一直遇到问题。

我在编译器(avr-gcc)中启用了浮点,并且大多数情况下都可以使用。

例如,此代码:

floatVal = ((double)tempResult / (double)oversample) * 0.000457777;
char outbuffer[255];
sprintf(outbuffer, "%f\n", floatVal);
usart1TXString(outbuffer);

在UART上提供正确的输出:

3.866311

我也想打印出32位int。这也有效:

char outbuffer[255];
sprintf(outbuffer, "%ld\n", transform(combVal));
usart1TXString(outbuffer);

并在UART上提供正确的输出:

117864

(这些输出都是我期望的输出)

当我尝试将这两段代码合并为单个(甚至连续)传输时,会发生问题:

floatVal = ((double)tempResult / (double)oversample) * 0.000457777;
char outbuffer[255];
sprintf(outbuffer, "%f,%ld\n", floatVal, transform(combVal));
usart1TXString(outbuffer);

产生此输出:

584991570000.000000,117864

大数字不会改变,除非我的floatVal值相差很大。

我没有运气就试图将其分解为两种不同的传输方式:

floatVal = ((double)tempResult / (double)oversample) * 0.000457777;
char outbuffer[255];
sprintf(outbuffer, "%f\n", floatVal);
usart1TXString(outbuffer);
char outbuffertwo[255];
sprintf(outbuffertwo, ",%ld\n", transform(combVal));
usart1TXString(outbuffertwo);

产生相同的错误结果。

584991570000.000000,117419

我也尝试使用dtostrf()而不是sprintf():

floatVal = ((double)tempResult / (double)oversample) * 0.000457777;
char outbuffer[255];
dtostrf(floatVal, 6, 4, outbuffer);
usart1TXString(outbuffer);

Works。但是,一旦我尝试添加其他值,它就会再次中断:

floatVal = ((double)tempResult / (double)oversample) * 0.000457777;
char outbuffer[255];
dtostrf(floatVal, 6, 4, outbuffer);
usart1TXString(outbuffer);
char outbuffertwo[255];
sprintf(outbuffertwo, ",%ld\n", transform(combVal));
usart1TXString(outbuffertwo);

返回到来自UART的相同中断值。

我尝试增加缓冲区的大小(即使它应该已经足够大了)。

我不认为这很重要,但以防万一:

'tempResult'是一个无符号的64位int,它是从ADC接收的16位值的累加。

'oversample'是一个16位int,它是指定的过采样量。当前50。

'floatVal'是双精度型。

'combVal'是一个32位int,其中包含24位ADC值,以两位的方式表示赞赏。

transform()是处理两者的补码的函数,如下所示:

int32_t transform(int32_t value)
    {
        if (value > MAX_VALUE)
        {
            value -= MODULO;
        }
        return value;
    }

关于损坏%f的%ld是什么?

编辑:即使我仅用包含正确数字的变量替换了transform(combVal),它仍然会破坏其他值。

floating-point printf atmega avr-gcc
1个回答
0
投票

我发现了问题,这是我说的我认为不重要的其中一件事。具体来说:

'tempResult' is an unsigned 64 bit int that is an accumulation of 16 bit values received from an ADC.

从avr-libc常见问题解答:

float and double are 32 bits (this is the only supported floating point format)

我将问题缩小到这一行:

floatVal = ((double)tempResult / (double)oversample) * 0.000457777;

因为如果我用这个替换它:

floatVal = 3.123456

一切正常。

uint64_t tempResult;更改为uint32_t tempResult;会修复所有问题。我只需要避免过度采样就可以了,一切都会好起来的。

长话短说:滥用8位AVR上的浮点会导致UB,这是UB喜欢做的事情(有时会工作,而会引起很多其他混乱)。

© www.soinside.com 2019 - 2024. All rights reserved.