¿Cómo verificar el valor flotante como valor hexadecimal?

0

Estoy leyendo 4 bytes de EEPROM para hacer un valor flotante.

El eeprom específico que uso (Serie 24Lxx) tiene 0xFF como valor predeterminado.

Entonces, si leo cuatro bytes de 0xFF en la variable float, tendrá 0xFFFFFFFF

Quiero poder verificar la condición anterior.

Sin embargo, declaración, si (floatVariable == 0xFFFFFFFF) {....} no es verdadera, incluso si floatVariable tiene 0xFFFFFFFF en su interior (verificada a través del depurador).

¿Hay alguna manera de que pueda hacer eso?

    
pregunta Steve

2 respuestas

5

En general, cuando observa la representación de bits de los datos en la memoria, solo tiene dos opciones:

  1. Use un puntero a la variable y "miente" en cuanto a lo que apunta:

      

    Tenga en cuenta los comentarios de @erebos 'y @ Lundin a continuación: aunque a menudo vea algo como lo siguiente, NO es estrictamente conforme C. Esa "mentira" podría molestarlo ...

    volatile float f;
    volatile uint32_t *p = (volatile uint32_t *)&f; // Take the address of f and cast it.
    ...
    if (*p!=0xFFFFFFFFu) {
        printf("%f", f);
    } // if
    
  2. Use una estructura union para cambiar su interpretación dependiendo de a qué campo accede:

    typedef union FloatAs32 {
        volatile float f;
        volatile uint32_t i; // "Overlays" other fields in union
    } FloatAs32;
    
    FloatAs32 f;
    ...
    if (f.i!=0xFFFFFFFFu) { // Access 'i' field
        printf("%f", f.f);  // Access 'f' field
    } // if
    

Digo "en general", porque también puede tener la oportunidad de confiar en la codificación del flotador para obtener lo que desea. Necesitaré verificar mis referencias, pero puede ser que puedes probar NaN , que es una representación especial de flotadores para indicar (literalmente) "No es un número" (como sqrt(-1); )

Su prueba if (f==0xFFFFFFFF) intenta comparar el valor interpretado del valor flotante con ese número. Desea comparar con el valor no interpretado .

Editar

Revisé mis fuentes, y tenía razón. Si el campo "Exponente" es todo 1 s, y el campo "Mantisa" es no todo 0 s (que coincide con su caso en general, pero no específicamente todo F s) , entonces el float se interpreta como un NaN . Tenga en cuenta que el bit "Signo" se utiliza para distinguir entre un "Silencio" NaN (se puede propagar a través de cálculos) y un "Señalización" NaN (puede causar excepciones). Afortunadamente, un bit de "Signo" de 1 (como en su caso) es un QNaN .

Eso significa que simplemente puede usar la función isnan(f) y se volverá verdadera para su caso especial, y también para otros casos. ¿Su dispositivo produce un NaN en algún momento? Tal vez para indicar una condición de error? Si es así, no debes usar esta sugerencia. Si no ... esa es tu llamada.

Editar # 2

@dwelch hizo un buen punto en los comentarios sobre el uso de volatile . El compilador podría mantener sus valores en registros en lugar de en la memoria, por lo que ninguno de los ejemplos anteriores hubiera funcionado. Agregar volatile le dice al compilador que siempre lea y escriba los valores en la memoria en lugar de almacenarlos en caché. He modificado mis ejemplos para tener esto en cuenta.

    
respondido por el John Burger
3

prueba super rápida basada en mis comentarios a la respuesta seleccionada. El compilador hizo lo que queríamos / deseamos:

void fdummy ( float );
void dummy ( unsigned int );

union
{
    unsigned int ui;
    float f;
} myun;

void fun ( unsigned int a, float b )
{
    myun.f = b;
    fdummy(myun.f);
    myun.ui = a;
    dummy(myun.ui);
    fdummy(myun.f);
}



00000000 <fun>:
   0:   e92d4070    push    {r4, r5, r6, lr}
   4:   e1a05000    mov r5, r0
   8:   e59f401c    ldr r4, [pc, #28]   ; 2c <fun+0x2c>
   c:   ed840a00    vstr    s0, [r4]
  10:   ebfffffe    bl  0 <fdummy>
  14:   e1a00005    mov r0, r5
  18:   e5845000    str r5, [r4]
  1c:   ebfffffe    bl  0 <dummy>
  20:   ed940a00    vldr    s0, [r4]
  24:   e8bd4070    pop {r4, r5, r6, lr}
  28:   eafffffe    b   0 <fdummy>
  2c:   00000000    andeq   r0, r0, r0

Bueno, esto lo consiguió para optimizar los registros y todavía funcionó como se desea. Copia el unsigned a

void fdummy ( float );
void dummy ( unsigned int );
void fun ( unsigned int a, float b )
{
union
{
    unsigned int ui;
    float f;
} myun;

    myun.f = b;
    fdummy(myun.f);
    myun.ui = a;
    dummy(myun.ui);
    fdummy(myun.f);
}

00000000 <fun>:
   0:   e92d4010    push    {r4, lr}
   4:   e1a04000    mov r4, r0
   8:   ebfffffe    bl  0 <fdummy>
   c:   e1a00004    mov r0, r4
  10:   ebfffffe    bl  0 <dummy>
  14:   ee004a10    vmov    s0, r4
  18:   e8bd4010    pop {r4, lr}
  1c:   eafffffe    b   0 <fdummy>

Uno o dos ejemplos no hacen una prueba, pero los escritores del compilador querían que esto funcionara, incluso si no se utiliza el ram y el gointa y el goout de la unión no coinciden.

    
respondido por el old_timer

Lea otras preguntas en las etiquetas