bitRead() и bitWrite() не работают с float

Тема в разделе "Микроконтроллеры AVR", создана пользователем Vitlay, 27 июн 2018.

  1. Vitlay

    Vitlay Нуб

    Уважаемые гуру пожалуйста подскажите.
    Я с ардуино знаком на весьма любительском уровне.
    Я взял скетч из примеров из библиотеки Modbus-Master-Slave-for-Arduino-master.
    В этом примере данные из регистров мдбас слейв устройств считываются в массив
    uint16_t au16data[];
    В Модбас слейв в двух регистрах по 16 бит лежит одно значение float размером 32 бит
    то есть в двух ячейках uint16_t массива у меня сохраняться одно значение float размером 32 бит.
    Я планировал в скетче из двух uint16_t побитово перенести в переменную float 32 бита.
    Примерно так:
    Код (C++):
     uint16_t au16data[16] ;
      float volts  ;
     
      bitWrite(volts, 0, bitRead(au16data [1], 0));
      bitWrite(volts, 1, bitRead(au16data [1], 1));
      bitWrite(volts, 2, bitRead(au16data [1], 2));
      bitWrite(volts, 3, bitRead(au16data [1], 3));
     
      bitWrite(volts, 4, bitRead(au16data [2], 0));
      bitWrite(volts, 5, bitRead(au16data [2], 1));
      bitWrite(volts, 6, bitRead(au16data [2], 2));
      bitWrite(volts, 7, bitRead(au16data [2], 3));  
     
    Но компилятор ругается.
    Код (C++):

    C:\Users\Vitaly\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:112:37: error:   in evaluation of 'operator|=(float, long unsigned int)'
    #define bitSet(value, bit) ((value) |= (1UL << (bit)))
    C:\Users\Vitaly\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:114:52: note: in expansion of macro 'bitSet'
    #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
    C:\Users\Vitaly\AppData\Local\Temp\arduino_modified_sketch_712994\sketch_jun25c.ino:121:5: note: in expansion of macro 'bitWrite'
         bitWrite(volts, 0, bitRead(au16data [1], 0));
    C:\Users\Vitaly\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:113:39: error: invalid operands of types 'float' and 'long unsigned int' to binary 'operator&'
    #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
    C:\Users\Vitaly\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:114:73: note: in expansion of macro 'bitClear'
    #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
    C:\Users\Vitaly\AppData\Local\Temp\arduino_modified_sketch_712994\sketch_jun25c.ino:121:5: note: in expansion of macro 'bitWrite'
         bitWrite(volts, 0, bitRead(au16data [1], 0));
    C:\Users\Vitaly\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:113:39: error:   in evaluation of 'operator&=(float, long unsigned int)'
    #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
    C:\Users\Vitaly\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:114:73: note: in expansion of macro 'bitClear'
    #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
    C:\Users\Vitaly\AppData\Local\Temp\arduino_modified_sketch_712994\sketch_jun25c.ino:121:5: note: in expansion of macro 'bitWrite'
         bitWrite(volts, 0, bitRead(au16data [1], 0));
    Встречал в инете обьяснение этому, но моих знаний не хватило понять это, там все была на СИ++.
    Пожалуйста подскажите, как в моем случае должен выглядеть код.
    Просьба сильно не пинать.
     
  2. DetSimen

    DetSimen Гуру

    bitwrite не работает с плавающей точкой.
    тебе надо использовать union сначала, чтоб конвертировать float в 2 int-а.

    Код (C++):
    union IntConvert {
      int   IntValues[2];
      float FloatValue;
    }
    и потом засовывать int-ы в массив, а забирать оттуда float целиком. И наоборот. И массив и float физически находятся по одному и тому же адресу памяти, разное только обращение к ней.
    Прочитай за union чонить.
     
    Andrey12 и Mitrandir нравится это.
  3. SergeiL

    SergeiL Гуру

    Не, а :)
    Здесь ТС не понимает, что он хочет сделать и что получить на выходе.
    union здесь не поможет, т.к. взвод бита для float это бред... Как он будет вытаскивать float на выходе???
    2-TC: Вы опишите, что вы хотите, может Вам и дадут правильный совет ;)
     
    Последнее редактирование: 27 июн 2018
  4. DIYMan

    DIYMan Гуру

    Про union уже сказали. Ещё один путь - прямое копирование памяти:
    Код (C++):
    uint16_t from[2];
    float to;

    uint8_t* fromRead = (uint8_t*) from;
    uint8_t* toWrite = (uint8_t*) &to;

    memcpy(toWrite,fromRead,4); // копируем 4 байта
    Но! Это не всегда корректно, хотя бы из-за порядка следования байт. И вообще - желание из двух целых скопировать во float - кмк, сигнализирует о том, что ТС не совсем понимает, что нужно. На примере: допустим, в одном uint16_t содержится значение температуры в целых, во втором - в десятитысячных долях. Тогда конвертируется это во float довольно просто:

    Код (C++):
    uint16_t tempWhole = 12;
    uint16_t tempFract = 1234;

    float result = tempWhole;
    result *= 10000.0;
    result += tempFract;
    result /= 10000.0;
     
    DetSimen нравится это.
  5. DIYMan

    DIYMan Гуру

    Вот, для демонстрации безумства первого подхода (прямое копирование) и корректности работы второго - набросал тут: http://cpp.sh/ - небольшую программку:

    Код (C++):
    // Example program
    #include <iostream>
    #include <string>
    #include <cstring>

    int main()
    {
        uint16_t from[2] = {56,1234};
        float to;

        uint8_t* fromRead = (uint8_t*) from;
        uint8_t* toWrite = (uint8_t*) &to;

        memcpy(toWrite,fromRead,4); // копируем 4 байта  
       
      std::cout << to << "\n";
     
      uint16_t tempWhole = 56;
      uint16_t tempFract = 1234;
     
      float result = tempWhole;
      result *= 10000.0;
      result += tempFract;
      result /= 10000.0;
     
      std::cout << result << "\n";
    }
     
    Вывод программы:
     
    DetSimen нравится это.
  6. SergeiL

    SergeiL Гуру

    А были какие-то сомнения ? :)
     
  7. Daniil

    Daniil Гик

    а нельзя ли так:
    Код (C++):
    uint16_t a,b; //2 половинки числа
    uint32_t x; //временная переменная
    float32_t y; //результат
    x=a;
    x=x<<16;
    x=x+b;
    y=(float32_t)x;
    Чую, я не понял задачу.
     
  8. DIYMan

    DIYMan Гуру

    Нет, это для демонстрации ТС ;)
     
  9. DIYMan

    DIYMan Гуру

    Вот код:
    Код (C++):
    // Example program
    #include <iostream>
    #include <string>

    int main()
    {
    uint16_t a = 56,b=1234; //2 половинки числа
    uint32_t x; //временная переменная
    float y; //результат
    x=a;
    x=x<<16;
    x=x+b;
    y=(float)x;
      std::cout << y;

    }
    Тестировал здесь: http://cpp.sh/ Вывод:
    Не очень похоже на 56.1234, не находите? ;)
     
  10. parovoZZ

    parovoZZ Гуру

    На 8-ми битке такое делать нельзя. Да и зачем?
     
  11. DIYMan

    DIYMan Гуру

    В каком месте такое нельзя сделать на восьмибитке? Вывод в поток - дык это не основа алгоритма, это просто демонстрация результатов, не более того. Остальное - вполне валидный код на С++, который ОБЯЗАН компилироваться любым современным компилятором.
     
  12. Vitlay

    Vitlay Нуб

    Огромное спасибо всем откликнувшимся за подсказки, кажется победил:
    Код (C++):
    int16_t au16data[]={17260, 0, 17259, 52429 };// 236.00 and 235.8
    float* ptr_recData;
    uint8_t numPar =0;   // номер параметра из массива
    float volts =0 ;
    int16_t temp[2];


    void setup() {
    Serial.begin(9600);
    ptr_recData = (float*)(&temp[0]) ;  // получаем адрес переменной
    }

    void loop() {

    temp [1] = au16data[(numPar*2)];
    temp [0] = au16data[(numPar*2)+1];
    volts =*ptr_recData;

    Serial.println(temp [0]);
    Serial.println(temp [1]);
    Serial.println(volts,8);

    Serial.println("_");

    ++numPar*2;
    temp [1] = au16data[(numPar*2)];
    temp [0] = au16data[(numPar*2)+1];
    volts =*ptr_recData;

    Serial.println(temp [0]);
    Serial.println(temp [1]);
    Serial.println(volts,8);
    Serial.println("__________");
    delay(2000);
    }
     
  13. parovoZZ

    parovoZZ Гуру

    плавающая запятая для чего? Вывод на дисплей? Можно отдельно выводить целую и отдельно дробную. АЛУ АВР-ок и так убогое, а вы ему ещё и плавающую запятую....
     
  14. DIYMan

    DIYMan Гуру

    Ты болеешь? Я ТС отвечал, и приводил только как ПРИМЕР. Что ТС там делает - хз, и мне пох. Не болей.
     
  15. parovoZZ

    parovoZZ Гуру

    Ну он же у него одни флоаты, да ещё и глобальные зачем-то. Ну ты прав - конкурентов не надо растить - без работы останешься.
    Ыыыы с такими горе программистами конкуренции не будет НИКОГДА. Так что я спокоен)))