Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Микроконтроллеры (MCU) и микропроцессоры (MPU) > Как состыковать типы float в контроллере и на ПК.


Автор: Курсант 11.8.2015, 16:53
Всем доброго времени суток!

У меня следующая проблема: я отправляю из микроконтроллера по UART данные в формате float, получаю их на ПК программой, написанной на VC++. Получаю эти 4 байта я в массив байтов, и привожу их к типу float (на самом деле использую union, ну это не принципиально). Проблема в том, что данные, которые видит ПК, не такие, какими их видит контроллер. Т.е. если для контроллера это 27,24324, то для ПК это оказывается 11,534534. Примерно так.
При этом есть ещё одна программа, написанная коллегой на Java, которая также принимает 4 байта, и приводит их к типу float функцией BytesToFloat, или чем-то таким. И программа на Java видит переменные такими, какими их видит контроллер. Но Java выполняется Java-машиной, и как там реализован тип float - не ясно...

Может быть кто-нибудь сталкивался с похожими проблемами, знает в какую сторону копать?

Спасибо за внимание...

Автор: xvr 11.8.2015, 17:17
Копать в сторону совпадения Endianess на МК и ПС, а так же в сторону формата этого самого флоата - совпадают ли они. Если да, то скорее всего это будет IEEE 754, а если не IEEE - то скорее всего не совпадут  smile 


Автор: Курсант 11.8.2015, 21:16
Это я и сам понял smile На контроллере у меня Little-endianess. А на ПК - не знаю. С форматом флоата на контроллер вообще каша, никакой информации в интернете, ничего. На компьютер и то данные разнятся.

Кстати, получается, что учитывая ядро моего контроллера (Cortex-M3, а иногда и Cortex-M0) формат флота контроллера нужно узнавать не в документации на контроллер, а в документации на компилятор?

Автор: ФедосеевПавел 11.8.2015, 22:38
Не знаком с С, просто предполагаю, что float - обобщённый тип данных с плавающей запятой, для корректной работы на ПК желательно указать конкретно single или double, точнее single. А потом уточнить порядок байт.

Автор: Курсант 12.8.2015, 11:31
Цитата(ФедосеевПавел @ 11.8.2015,  22:38)
Не знаком с С, просто предполагаю, что float - обобщённый тип данных с плавающей запятой, для корректной работы на ПК желательно указать конкретно single или double, точнее single. А потом уточнить порядок байт.

Спасибо за ответ. Я не знаком с VB, но если не ошибаюсь, в концепциях VB тип float является обобщённым, и нужно указывать точность - single или double. В языке Си для двойной точности предназначен тип double, а для единичной - float.

Добавлено через 11 минут и 26 секунд
Проблема так и не решилась. Поэтому начну вдаваться в детали. Вот сюда я записываю свои байты:
Код

typedef union {
   float AsFloat;
   uint32_t AsUint32;
   int32_t AsInt32;
   struct {
      unsigned char Byte1;
      unsigned char Byte2;
      unsigned char Byte3;
      unsigned char Byte4;
   }
} DataFieldTypedef;

DataFieldTypedef DataField;
}


Соответственно, я принимаю данные в DataField.Byte1, DataField.Byte2, DataField.Byte3 и DataField.Byte4, а затем вычитываю их как DataField.AsFloat;
При этом принятые значения отличаются примерно в два с половиной раза от тех, которые я отправлял. Т.е. Big-Endian - Little-Endian соответствие соблюдено (я пробовал менять байты местами, получался какой-то мусор вместо тех данных, которые я отправлял).
Из всего вышеизложенного я сделал вывод, что проблема - в формате данных float, а именно в структуре мантиссы и показателя степени, знака и их сдвигов-размеров-положения. Проблема усугубляется тем, что в микроконтроллере я имею soft-float, т.е. тип float ненастоящий, программируется компилятором используя целочисленную арифметику контроллера. И как он там устроен - большой вопрос... Фактически, он устроен отличным от компьютера образом.

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

Автор: xvr 12.8.2015, 13:35
Цитата(Курсант @  11.8.2015,  21:16 Найти цитируемый пост)
На контроллере у меня Little-endianess. А на ПК - не знаю.

Если ПК это PC - то то же LE

Цитата(Курсант @  11.8.2015,  21:16 Найти цитируемый пост)
Кстати, получается, что учитывая ядро моего контроллера (Cortex-M3, а иногда и Cortex-M0) формат флота контроллера нужно узнавать не в документации на контроллер, а в документации на компилятор? 

Угу. Какой компилятор?

Автор: Курсант 12.8.2015, 14:41
Цитата(xvr @ 12.8.2015,  13:35)
Угу. Какой компилятор?

arm-gcc

В ПК и в компиляторе, судя по всему, всё соответствует

Проблема, похоже, в том, что я теряю некоторые биты при приёме через COM-порт. Использую я для этого класс serialPort из VisualC++. Читаю данные в строку с помощью метода serialPort->ReadLine;

Проблема была в методе ReadLine объекта serialPort
Судя по всему метод предназначен для вычитывания текстовых строк из COM-порта. Поэтому нетипичные для текстовых строк байты метод "коверкает".
Когда я стал вычитывать байты методом ReadByte, все данные стали отображаться нормально.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)