Преобразование 32-битного дополнения до 2 в десятичное число

У меня есть данные, поступающие от микросхемы измерения энергии V9261F ( ссылка на техническое описание ), которая отправляет данные через UART на мой микроконтроллер Arduino. Когда я читаю регистр 0x0119, я читаю активную мощность, измеренную микросхемой. Но проблема в том, что эта обратная связь находится в 32-битном дополнении до 2, и я не могу ее расшифровать.

UART-связь

Начиная с 4-го байта в потоке идут байты данных, в которых хранятся измеряемые переменные (см. техпаспорт стр. 56 - 57). Для чтения регистра 0x0119 это должно быть в байтах данных 10 - 11 - 12 и 13 (D1) соответственно 0x55, 0xE7, 0x0E и для байта данных 13 0x00.

Таким образом, обратная связь для активной мощности всех объединенных байтов, которые у меня есть, равна 0x000EE755 -> вычесть 1 (для 1 дополнения) = 0x000EE754 -> инвертировать его, чтобы он стал десятичным числом = 0xFFF118AB (4293990571 dec). Но это безумно большое число должно представлять только активную мощность 6,2 Вт.

Что я делаю не так с преобразованием из дополнения 2 в десятичное число? Как это должно представлять 6,2 Вт?

Ответы (3)

Я думаю, вы неправильно понимаете, что означает «дополнение 2». Положительное дополнительное число до 2 идентично положительному двоичному числу (старший значащий бит должен быть равен нулю) . Итак, для 8 бит у нас есть от 0x00 (ноль) до 0x7F (127). Числа меньше нуля идут от 0xFF (-1) до 0x80 (-128). Чтобы сделать отрицательное число положительным, чтобы вы могли отображать его как знак минус перед положительным числом, вы можете вычислить дополнение до 2, как показано выше. Обратите внимание на особый случай 0x80.

Таким образом, с 0x000EE754 у вас есть положительное десятичное число 976724. Между этим и 6,2 6,3478E-6 есть коэффициент масштабирования.

Вероятно, вы хотите преобразовать число в число с плавающей запятой и выполнить вычисления с плавающей запятой. Он уже в 32-битном целочисленном формате со знаком.

Дополнение до двух — это формат для описания отрицательных чисел . Применяется, когда число отрицательное. Ваши расчеты не имеют никакого смысла. https://en.wikipedia.org/wiki/Two%27s_complement

Согласно RTFM, формат данных устройства представляет собой 32-битный двоичный код с прямым порядком байтов. Так что, учитывая, что ваш MCU имеет обратный порядок байтов (как в случае с AVR), вам не нужно ничего конвертировать. Просто сохраните результат в файле int32_t.

Формат данных для UART - сначала LSB, и инструмент, который сделал картинку, кажется, знает об этом. Итак, если у вас есть какие-то данные, такие как 55e70e00, то это фактически считанные данные. Поскольку это прямой порядок байтов, он соответствует шестнадцатеричному 0x000ee755, десятичному 976725. Это значение, которое вы должны получить после чтения из регистра rx UART. Если это число имеет смысл, я понятия не имею.

Дополнение до 2 не имеет значения, так как в этом случае число положительное. Отрицательное число будет иметь двоичную 1 в старшем разряде.

Хорошо, спасибо, что прояснили это. Я проверю, не используется ли коэффициент масштабирования при выполнении измерений с несколькими нагрузками. Довольно странно, что в даташитах ничего не указано от коэффициента масштабирования.
Утверждение «Дополнение до двух — это формат для описания отрицательных чисел». не точно. Формат «дополнение до двух» описывает все числа, а не только отрицательные. Это просто становится более интересным для отрицательных чисел.
Скорее, дополнение до двух — это соглашение о знаках для представления целых чисел .

Мне нравится думать о числах с дополнением до двух, когда я думаю о том, что происходит с младшими битами двоичного числа при вычитании. Если нижние 4 бита x равны 0000, а нижние четыре бита y равны 0001, то нижние четыре бита xy будут равны 1111 независимо от того, какие биты находятся над ними. Это можно легко обобщить для любого конкретного количества битов (вычитание числа, младшие биты которого выражают значение 1, из числа, младшие биты которого выражают значение 0, даст число, все младшие биты которого установлены). Поскольку это будет работать для любого количества битов, можно дополнительно сказать, что вычитание единицы из нуля даст число с бесконечным набором битов.

На практике хранение бесконечного числа битов нецелесообразно. Однако для любого N>=1 все числа в диапазоне от -(2^N) до (2^N)-1, однако все биты слева от N-го бита (считая влево) будут иметь то же значение, что и сам N-й бит, и поэтому его не нужно сохранять. Таким образом, при использовании 8-битных значений с дополнением до двух значение -1 не «на самом деле» 10000000, а вместо этого [бесконечное количество единиц 1 с] 0000000, а значение 127 не равно 01111111, а [бесконечное количество единиц 0s]1111111. Просмотр вещей таким образом прояснит, как должны работать преобразования между различными размерами значений.

Например, преобразование 8-битного значения в 16-битное просто повлечет за собой копирование части бесконечной строки из единиц или нулей, в то время как преобразование 16-битного значения в диапазоне от -128 до 127 в 8-битное повлечет за собой удаление некоторых дубликатов. биты. Если 16-битное число находится за пределами этого диапазона, преобразование его в 8-битное даст значение, которое получится в результате копирования наиболее значимого оставшегося бита.

PS - применение формулы суммирования мощностей 1+2+4+8... дает -1. Это может показаться бессмысленным, но идеально соответствует тому, как работает математика с дополнением до двух. Для любого значения N, если все нижние N битов числа установлены, добавление 1 даст число, у которого все нижние N битов пусты. Единственное число, для которого нижние N битов будут свободны для всех значений N, — это ноль, и единственное число, которое даст 0 при добавлении к нему 1, — это, конечно, -1.