передача числа типа double через Serial.write в Processing

Andrey2020
Offline
Зарегистрирован: 09.07.2020

Добрый день, Форумчане,

Делаю вывод с Arduino на экран ПК через Processing... Графики и всё такое.

И встал вопрос о передаче числа типа double

Проще говоря

double peak = вызов функции

Serial.write(peak);

На стороне Processing кроме этого числа перед этим передаются ещё 128 байт инфы.

Чтобы обеспечить надёжный приём переданного все данные считываются в один массив одной командой

 inBuffer = int( port.readBytes() );

читаю буфер и вижу там 4 байта переданного числа peak.

вопрос - как мне без долгих экспериментов собрать его обратно в double? где там старший а где младший байт итп?

Заранее благодарен 

b707
Offline
Зарегистрирован: 26.05.2017

для начала - в ардуино нет double. точнее double и float одно и то же

можете код процессинга привести полностью?  Что это за строчка такая странная?

inBuffer = int( port.readBytes() );

добавка - эту строчку нашел

 

rkit
Offline
Зарегистрирован: 23.11.2016

Если просто результат, то число нужно передавать в виде читаемой человеком строки.

b707
Offline
Зарегистрирован: 26.05.2017

rkit пишет:

Если просто результат, то число нужно передавать в виде читаемой человеком строки.

либо преобразовывать в целое, например умножением на 100 - а после получения в процессинге делить на 100 обратно

А так чтобы из четырех байт машинного представления float собрать исходное число - в процессинге таких возможностей не вижу

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

rkit пишет:

Если просто результат, то число нужно передавать в виде читаемой человеком строки.

либо преобразовывать в целое, например умножением на 100 - а после получения в процессинге делить на 100 обратно

А так чтобы из четырех байт машинного представления float собрать исходное число - в процессинге таких возможностей не вижу

Почему - простым умножением в float каждый байт умножается на свой множитель кратный 2 и складывается с предыдущим в одно число FLOAT.

МНЕ ЕДИНСТВЕННОЕ ЧТО НЕ ПОНЯТНО И НИ ГДЕ НЕ НАПИСАНО В КАКОМ ПОРЯДКЕ ВЫГРУЖАЕТСЯ число тип double в сериальный порт!!?? 

 

 

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

для начала - в ардуино нет double. точнее double и float одно и то же

можете код процессинга привести полностью?  Что это за строчка такая странная?

inBuffer = int( port.readBytes() );

добавка - эту строчку нашел

 

Что значит нет double,

а это тогда что: http://arduino.ru/Reference/Double

Короче мне нужно понять при выгрузке такого числа в сериальный порт первым идёт старший или младший байт из 4-х???

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

Почему - простым умножением в float каждый байт умножается на свой множитель кратный 2 и складывается с предыдущим в одно число FLOAT.

похоже что вы с лонгом попутали

Andrey2020 пишет:

Что значит нет double, а это тогда что: http://arduino.ru/Reference/Double

а вы по этой ссылке внимательно читайте

Цитата:
Короче мне нужно понять при выгрузке такого числа в сериальный порт первым идёт старший или младший байт из 4-х???

так проверьте, варианта то всего два :)

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

Andrey2020 пишет:

Почему - простым умножением в float каждый байт умножается на свой множитель кратный 2 и складывается с предыдущим в одно число FLOAT.

похоже что вы с лонгом попутали

Andrey2020 пишет:

Что значит нет double, а это тогда что: http://arduino.ru/Reference/Double

а вы по этой ссылке внимательно читайте

Цитата:
Короче мне нужно понять при выгрузке такого числа в сериальный порт первым идёт старший или младший байт из 4-х???

так проверьте, варианта то всего два :)

Ну видимо придётся поэксперементировать...

Странно что в описаниях языка про это ничего не сказано... нек. вещи опущены - дагадайся сам... :((

rkit
Offline
Зарегистрирован: 23.11.2016

Andrey2020 пишет:

Странно что в описаниях языка про это ничего не сказано... нек. вещи опущены - дагадайся сам... :((

А зачем кто-то будет описывать несуществующий экзмепляр write?

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

Странно что в описаниях языка про это ничего не сказано... нек. вещи опущены - дагадайся сам... :((

в описании какого языка ищете? - ищите в С++, а не "в ардуино"

sadman41
Offline
Зарегистрирован: 19.10.2016

А мне казалось, что порядок следования байт определяется архитектурой МК.

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

Andrey2020 пишет:

Странно что в описаниях языка про это ничего не сказано... нек. вещи опущены - дагадайся сам... :((

в описании какого языка ищете? - ищите в С++, а не "в ардуино"

Хорошая идея...!

b707
Offline
Зарегистрирован: 26.05.2017

вот, читайте. Может придет понимание, что ваша идея с домножением байт на степени двойки несколько из другой оперы

https://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:
А мне казалось, что порядок следования байт определяется архитектурой МК.

ему для начала стоит понять, что вообще представляет флоат "изнутри", а то он явно его с лонгом путает

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

вот, читайте. Может придет понимание, что ваша идея с домножением байт на степени двойки несколько из другой оперы

https://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB

Круто... не сразу понял что не всё так просто...

Буду думать как собрать обратно.

Но... есть же функции сдвига >>

Всё что нужно обратно водворить на место все 4 байта числа!!!

Andrey2020
Offline
Зарегистрирован: 09.07.2020

Andrey2020 пишет:

b707 пишет:

вот, читайте. Может придет понимание, что ваша идея с домножением байт на степени двойки несколько из другой оперы

https://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2%D0%B5%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB

Кстати

Круто... не сразу понял что не всё так просто...

Буду думать как собрать обратно.

Но... есть же функции сдвига >>

Всё что нужно обратно водворить на место все 4 байта числа!!!

Кстати ссылка не открывается

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

Кстати ссылка не открывается

просто в гугле наберите что-нибудь типа "внутреннее представление float" - таких статей много

rkit
Offline
Зарегистрирован: 23.11.2016

Для слепых повторю

rkit пишет:

несуществующий экзмепляр write

Andrey2020
Offline
Зарегистрирован: 09.07.2020

rkit пишет:

Для слепых повторю

rkit пишет:

несуществующий экзмепляр write

Не понял что это и откуда и где пишет??

Я говорил про Serial.write(число);   http://arduino.ru/Reference/Serial/Write   

см по ссылке

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

Я говорил про Serial.write(число);   http://arduino.ru/Reference/Serial/Write   

см по ссылке

вы бы для начала сами внимательно прочитали то, что по вашей ссылке. Попытайтесь найти в описании хоть что-нибудь про float, а когда не найдете - задумайтесь почему

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

Andrey2020 пишет:

Я говорил про Serial.write(число);   http://arduino.ru/Reference/Serial/Write   

см по ссылке

вы бы для начала сами внимательно прочитали то, что по вашей ссылке. Попытайтесь найти в описании хоть что-нибудь про float, а когда не найдете - задумайтесь почему

Да и я тоже смотрел... только байт или массив.

Но... я проверял ручками - при отправке числа напрмер 51.545 = в буфере принимается 4 байта. первый из которых читается как 51 !!!

тем не менее я нашёл пост про передачу Float: Добрый день! Нужна помощь с получением float через USART. Написал вот такие программки:



С# на ПК. Она отправляет float и принимает это же число от ардуино уно

Код на ардуинке:

Код (C++):

float number = 0;
union
{
  uint32_t asByte;
  float asFloat;
} message_float;
void setup()
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
}
void return_float_number()
{
  uint32_t  s = (message_float.asByte >> 31) ? -1 : 1; // Определяем знак
  uint32_t e = (message_float.asByte >> 23) & 0xFF; // Порядок
  uint32_t m =                          
  e ?
    ( message_float.asByte & 0x7FFFFF ) | 0x800000 :
    ( message_float.asByte & 0x7FFFFF ) << 1;
   number = s * (m*2^ -23)*(2^(e-127));
 
}
void loop()
{
  for(uint8_t start = 0; start < 5; start++)
  {
    uint8_t simvol_read = Serial.read();
    while(simvol_read == -1) {simvol_read = Serial.read();}
    message_float.asByte = simvol_read >> 8;
    //if (simvol_read != -1) {message_float.asByte = simvol_read << 8;}
    if (start == 4)
    {
      return_float_number();
      Serial.println(number);
      //Serial.println(number);
      if (number == 45.5) {digitalWrite(2, HIGH);}
    }
  }
}

Вот то что я получаю(отрывок):
8,035656E-09
4,120368E-11
6,797966E-33
6,825459E-07
5,429218E-31
1,097891E-05
6,409409E-10
4,244787E-05
6,337645E-10
8,035656E-09

а нужно получить обратно свои 45.5

P.S код получился запутанным потому что я много как пробовал. Помогите разобраться

 
 
  • Igor68

    Igor68Гуру

    Доброго времени суток!
    Сам уже давно убежал от C# и им пользуюсь только оформления окон. А работа вся на C/C++ в виде DLL. Именно потому как не разобрался с указателями в C#,но может он это и не умеет. Данные таскаю по ETHERNET, MODBUS ит.п. по правилу (ведь float это uint32_t с точки зрения размещения и передачи)

    Код (C++):

    float x;
    uint32_t y;
    y = (*(uint32_t*)(&x));
     

    Тут мы разместили значение типа float в размерность uint32_t. А это 4 байта. А можно и так:

    Код (C++):

    float x;
    uint8_t y[4];
    memcpy(&y[0], &x, sizeof(float));
     

    В любом случае это подготовлено для передачи - то, что есть y
    Принимаем эти байты и делаем всё обратно:

    Код (C++):

    uint8_t x[4];
    float y;
    y=(*(float*)(&x[0]));
     

    Ну или применив memcpy.
    В шарпе я не стал изучать - овчинка выделки не стоит. Примените к шарпу DLL на Си. И из него вызывайте функцию.
    Это чисто мой подход. Вы как хотите.

 

Andrey2020
Offline
Зарегистрирован: 09.07.2020

b707 пишет:

Andrey2020 пишет:

Я говорил про Serial.write(число);   http://arduino.ru/Reference/Serial/Write   

см по ссылке

вы бы для начала сами внимательно прочитали то, что по вашей ссылке. Попытайтесь найти в описании хоть что-нибудь про float, а когда не найдете - задумайтесь почему

Извините за глупый вопрос - а вот "альтернативные" типы данных например uint32_t 

в сегодняшней версии Arduino IDE работает вообще??

Мне кажется я уже пробовал компилить проги с такими типами и IDE выдавала ошибку типа не знаю что это

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

Извините за глупый вопрос - а вот "альтернативные" типы данных например uint32_t 

в сегодняшней версии Arduino IDE работает вообще??

работают

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

тем не менее я нашёл пост про передачу Float...

Хороший пост нашли.

принцип, что изложен в ответе Igor68, что вы привели - совершенно верный, именно так и стоит действовать. Но я не уверен, может ли Процессинг работать с отдельными байтами, входящими в float

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Andrey2020 пишет:

Мне кажется я уже пробовал компилить проги с такими типами и IDE выдавала ошибку типа не знаю что это

Потому что надо подключить stdint.h

#include <stdint.h>

 

b707
Offline
Зарегистрирован: 26.05.2017

Jeka_M пишет:

Andrey2020 пишет:

Мне кажется я уже пробовал компилить проги с такими типами и IDE выдавала ошибку типа не знаю что это

Потому что надо подключить stdint.h

#include <stdint.h>

 

а у меня и без хидера собирается (если речь про ардуино)

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

b707 пишет:

а у меня и без хидера собирается (если речь про ардуино)

Да, сейчас проверил на 1.8.5 - скомпилировалось без хидера. Хотя раньше вроде подключать приходилось, но может и ошибаюсь.

Green
Offline
Зарегистрирован: 01.10.2015

Хидер - слово неприличное.) Хедер будет точнее.
Вам правильно советуют. Если не нужен огород и достаточно 2х знаков после запятой:
long l_result = ваше double * 100;
l_result передаёте через union и собираете обратно:
double d_result = l_result;
d_result =/ 100;

Andrey2020
Offline
Зарегистрирован: 09.07.2020

Green пишет:

Хидер - слово неприличное.) Хедер будет точнее.
Вам правильно советуют. Если не нужен огород и достаточно 2х знаков после запятой:
long l_result = ваше double * 100;
l_result передаёте через union и собираете обратно:
double d_result = l_result;
d_result =/ 100;

Господа, решил проблему:

во-первых выяснилось что мне надо всего два байта передать:

код на стороне Arduino:

double peak = 5020 //число... до 30 000

unsigned int ppp = peak; преобразовал в два байта
byte peak_L = byte(ppp); младший байт отделил
byte peak_H = ppp >>8; старший байт отделил

передача

Serial.write(peak_L); //вывод младший б
Serial.write(peak_H); //вывод  старший б
 
 
Сторона Processing - приём:
принимается буфер, последние два байта 128 и 129 - те что надо собрать
 peak_L=byte(inBuffer[128]); чтение
  peak_H=byte(inBuffer[129]);
  peak = peak_H<<8; сборка
  peak=peak+peak_L;
  text(peak, X_OFFSET+90, 366); //печать
 
 
кто молодец? - Я молодец!

 

b707
Offline
Зарегистрирован: 26.05.2017

Andrey2020 пишет:

код на стороне Arduino:

double peak = 5020 //число... до 30 000
unsigned int ppp = peak; 

преобразовал в два байта

это вы не "в два байта" преобразовали, а в целое. То есть просто откинули всю дробную часть. И, например. числа 0.1 и 0.001, изначально отличающиеся в 100 раз - после такого "преобразования" станут одинаковыми - равными нулю.

Если вам такое "преобразование" подходит - значит вам изначально никакой float или double был не нужен, не понятно, зачем было себе и другим голову морочить