Как поменять порядок байтов местами

code-optimization byte-order

Предыстория

Я считываю 24-битное значение АЦП в uint32. Используя шину SPI, вот логика:

value = SPI.transfer(0);   // считывание первых 8 бит (MSB first)
value <<= 8;               // сдвиг битов влево
value |= SPI.transfer(0);  // считывание следующих 8 битов
value <<= 8;               // сдвиг битов влево
value |= SPI.transfer(0);  // считывание последних 8 битов

Таким образом, я остаюсь с этим АЦП, читающим:

00000000 11111111 11111111 11111111
         MSB                    LSB

(Пока не обращайте внимания на ведущие нули.)

Теперь я передаю это значение по Ethernet следующим образом:

client.write((const byte*) &value, sizeof(value));

Проблема заключается в следующем:

  • Сначала значение сохраняется в виде MS - бита.
  • client.write() сначала передает ему LS-байт.

Я использую NodeRed в качестве TCP - сервера. Итак, на другом конце я получаю следующие данные:

11111111 11111111 11111111 00000000
     LSB          MSB

Я понимаю, что это ожидаемое поведение, но я хотел бы переключить порядок байтов перед отправкой, чтобы он считывался в NodeRed native endianness.


Вопрос

Возможно, мне следует сделать некоторый сдвиг битов в момент чтения АЦП, чтобы учесть тот факт, что client.write() сначала отправляет наименее значимый байт, например:

  byte1 = SPI.transfer(0);
  byte2 = SPI.transfer(0);
  byte3 = SPI.transfer(0);
  response = byte3;
  response <<= 8;
  response = byte2;
  response <<= 8;
  response = byte1;

Является ли это наиболее эффективным способом с точки зрения тактовых циклов?

Обратите внимание, что мой микроконтроллер - Teensy 4.1, и я передаю 10 000 показаний в секунду. Я хотел бы свести тактовые циклы для любых необходимых побитовых операций к минимуму, чтобы как можно меньше влиять на время показаний АЦП.

, 👍2


2 ответа


-1
// reverse wire order:
client.write((const byte*) &value + 3, 1);
client.write((const byte*) &value + 2, 1);
client.write((const byte*) &value + 1, 1);
client.write((const byte*) &value,     1);
,

Просто придираюсь, но... Я бы добавил либо пробелы вокруг"+", либо круглые скобки вокруг "(const byte*) &value". В противном случае это выглядит так, как будто " + " связывается более плотно, чем приведение, что, конечно, не так., @Edgar Bonet


2

Вы можете использовать массив байтов для сохранения сдвигов вообще. Это решение должно быть с наименьшим количеством тактовых циклов и без дополнительного использования памяти.

static byte value[4] = { 0 };

    /* ... */

    /* value[0] is still 0. */
    value[1] = SPI.transfer(0);
    value[2] = SPI.transfer(0);
    value[3] = SPI.transfer(0);

    client.write(value, sizeof value);

Некоторые примечания:

  1. Использование массива позволяет избежать повторной интерпретации 32-битной переменной как байтового массива. Вы читаете байты из SPI, а write() ожидает массив байтов. Это полностью обходит вашу проблему с конечностью.

  2. При вызове write() вам не нужно приводить адрес значения к const byte *, поскольку const является классификатором вызываемой функции. Не разрешается изменять указанные байты.

  3. Статичность массива избавляет вас от необходимости многократно обнулять первый байт. Кстати, достаточно указать первый байт, так как все остальные байты обнуляются автоматически. Однако последние байты будут обновляться при каждой передаче.

  4. sizeof-это оператор, а не функция. Однако довольно часто его используют с типом вместо объекта, и тогда вам нужны круглые скобки из - за синтаксиса. Но лучше использовать соответствующий объект, на самом деле вы это имеете в виду.

,

Вы объяснили это очень хорошо, но просто чтобы подтвердить, как я справляюсь с этой идеей, вы говорите, что вместо того, чтобы использовать функцию in32_t и создавать значение ответа, а затем читать / сдвигать каждый байт в значение, лучше создать массив байтов? Итак, допустим, я храню 100 значений, у меня будет 2D-массив (100 x 3 или что-то еще)? Я уверен, что ответ "да", но я просто хотел полностью понять. Кроме того, что делать, если я хочу привести к плаванию и отправить это значение, а также поменять местами байты? Лучше ли читать в массив, а затем каким-то образом привести 3 val в массиве к поплавку?, @hazymat