Нужен ответ на простенький вопрос.

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

Как поменять местами байты в двухбайтовом слове. Например 0x52FA, а мне нужно 0xFA52

bargundabal
Offline
Зарегистрирован: 08.06.2017
  uint16_t a = 0x52FA;
  Serial.begin(9600);
  Serial.print(a, HEX);
  Serial.print("    ");
  a = (a & 0xFF) << 8 | (a >> 8);  
  Serial.println(a, HEX);

52FA    FA52

Можно и поизящнее скорее всего, но я открыт к критике.

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вариант кода не лучше вышеперечисленого, но все же хорошо знать и его.

  uint16_t a = 0x52FA;
  Serial.begin(9600);
  Serial.print(a, HEX);
  Serial.print("    ");
  byte b[2], d;
  uint16_t &c = (uint16_t &)b;
  c = a;
  d = b[0]; b[0] = b[1]; b[1] = d;
  a = c;
  Serial.println(a, HEX);

 

semaawp
semaawp аватар
Offline
Зарегистрирован: 29.05.2017

Спасибо ответившим)

qwone пишет:

Вариант кода не лучше вышеперечисленого, но все же хорошо знать и его.

Не подскажите, что делает строчка 6 в коде?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вот вам еще код. в ОДНУ строчку.

Думаю, что ЕвгенийП меня поймет, просто выглядит красиво, почти как брейнфак! ;)

Для прикола - сразу с проверочной програмкой.

#include <stdlib.h>


void setup() {
  
Serial.begin(19200);
while (!Serial);
Serial.println("Input HEX number:");
}

void loop() {
byte buf[8]="0000000";
uint32_t a=0;
uint32_t b=0;
byte i=0;



while (Serial.available())
  {
    if (i<7)  buf[i++] = Serial.read();
  }
  if (!i) return;
  
buf[i] = 0;
a = strtol(buf,NULL,16);
b = a;

//=========ATTENTION!!!  BYTES SWAPPING!!! NO EXTRA MEMORY NEEDED!!!===================

*(byte*)&b ^= *((byte*)&b +1) ^= *(byte*)&b ^= *((byte*)&b +1);

//=======END OF BYTES SWAPPING========

Serial.print("I have  read  number:");
Serial.println(a,16);
Serial.print("I have swapped bytes:");
Serial.println(b,16);
Serial.println("==========================");
Serial.println("Input HEX number:");
}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ну и на асмо-затычке для полноты коллекции :)

Функция принимает 16-битную переменную, переворачивает в ней байты, и отдаёт обратно.

uint16_t asm_func(uint16_t value ){
asm volatile (         
"mov __tmp_reg__, %A0" "\n\t"
"mov %A0, %B0"         "\n\t"
"mov %B0, __tmp_reg__" "\n\t"
 : "=r" (value) : "0" (value) );
  return value;
}

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

dimax пишет:

Ну и на асмо-затычке для полноты коллекции :)

а если совместить? без временного регистра на трех XOR? Asm - операция EOR в АВРке.

uint16_t asm_func(uint16_t value ){
asm volatile (         
"eor  %A0, %B0" "\n\t"
"eor  %B0, %A0" "\n\t"
"eor  %A0, %B0" "\n\t"
 : "=r" (value) : "0" (value) );
  return value;
}

Ничего не выигрываем, те же три такта, но прикольнее.

---------------------------

Ну и проверочная програмка на все способы:

#include <stdlib.h>

uint16_t asm_swap(uint16_t value ){
asm volatile (         
"eor  %A0, %B0" "\n\t"
"eor  %B0, %A0" "\n\t"
"eor  %A0, %B0" "\n\t"
 : "=r" (value) : "0" (value) );
  return value;
}

void setup() {
  
Serial.begin(19200);
while (!Serial);
Serial.println("Input HEX number:");
}

void loop() {
byte buf[8]="0000000";
uint32_t a=0;
uint32_t b=0;
uint32_t c=0;
byte i=0;



while (Serial.available())
  {
    if (i<7)  buf[i++] = Serial.read();
  }
  if (!i) return;
  
buf[i] = 0;
a = strtol(buf,NULL,16);
b = a;

//=========ATTENTION!!!  BYTES SWAPPING!!! NO EXTRA MEMORY NEEDED!!!===================

*(byte*)&b ^= *((byte*)&b +1) ^= *(byte*)&b ^= *((byte*)&b +1);

//=======END OF BYTES SWAPPING========

c = asm_swap((uint16_t)b);

Serial.print("I  have  read  number:");
Serial.println(a,16);
Serial.print("I have  swapped bytes:");
Serial.println(b,16);
Serial.print("swapped back with asm:");
Serial.println(c,16);
Serial.println("==========================");
Serial.println("Input HEX number:");
}

 

bargundabal
Offline
Зарегистрирован: 08.06.2017

На асме оказалось на 10 байт толще, чем мой вариант) (на самом деле нет)

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

*(byte*)&b ^= *((byte*)&b +1) ^= *(byte*)&b ^= *((byte*)&b +1);

 

Для ТСа - изучай битовые операции - это самое низкоуровневое взаимодействие, следовательно малая ресурсоемкость.

454 байта общий вес


void setup() {
  uint16_t a = 0x52FA;
  asm_func(a);
}

void loop() {

}

uint16_t asm_func(uint16_t value ) {
  asm volatile (
    "eor  %A0, %B0" "\n\t"
    "eor  %B0, %A0" "\n\t"
    "eor  %A0, %B0" "\n\t"
    : "=r" (value) : "0" (value) );
  return value;
}

444 байта

void setup() {
  uint16_t a = 0x52FA;
  a = (a & 0xFF) << 8 | (a >> 8);
}

void loop() {

}

Аналогично 444 байта:

void setup() {
  uint16_t a = 0x52FA;
  asm (
    "mov __tmp_reg__, %A0" "\n\t"
    "mov %A0, %B0"         "\n\t"
    "mov %B0, __tmp_reg__" "\n\t"
    : "=r" (a) : "0" (a) );
}

void loop() {

}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

bargundabal, это потому, что асм-код в функцию завёрнут. Если голяком вставать то меньше будет)

bargundabal
Offline
Зарегистрирован: 08.06.2017

dimax

Неа, 454 байта.

void setup() {
  uint16_t a = 0x52FA;

  asm volatile (
    "mov __tmp_reg__, %A0" "\n\t"
    "mov %A0, %B0"         "\n\t"
    "mov %B0, __tmp_reg__" "\n\t"
    : "=r" (a) : "0" (a) );
}

void loop() {

}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

bargundabal, нужно ещё слово "volatile" убрать. Оно создаёт дополнительный код..

bargundabal
Offline
Зарегистрирован: 08.06.2017

Действительно, теперь ровно как моя одна строчка - 444 байта.

Я просто в асме не шарю, поэтому не попробовал, но если честно - асм, как по мне, явно проиграет четырем битовым операциям в одну строку как по читабельности, так и по времени на выдумывание. Хотя последнее зависит от навыка.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Угу теже 444 байта

void setup() {
  int A = 0x52FA;
  byte *p = (byte *)&A  ;
  byte b = *p; *p = p[1]; p[1] = b;
}

 

bargundabal
Offline
Зарегистрирован: 08.06.2017

Тоже 444 байта. Надо пробовать без стандартных конструкций, либо как-то иначе, но почему-то мне кажется, что все варианты компилятор в итоге причесывает к одному знаменателю.

void setup() {

}

void loop() {

}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

bargundabal, Сразу не сообразил,- но такой код  совершенно бесполезно сравнивать, -компилятор моментом выкинет вашу строчку просто потому, что результат не используется.  К моему фрагменту это тоже относится. Т.е. всё, что вы насчитали - не действительно. Нужно куда-то вывести результат. Причём если вывести неудачно, то компилятор опять же оптимизирует код, и переделает по-своему. Т.е. например если преобразование будет только одноразовое в другую переменную, то компилятор расчитает ещё на этапе компиляции результат и запишет его в другую переменную, а самой строчки преобразования не будет в программе вообще :) Видимо нужно создать программу, где в эту функцию будут передаваться неоднократно! неизвестные байты, например прочитанные из порта. Тогда копилятор будет вынужден целиком задействовать алгоритм.)

 

bargundabal
Offline
Зарегистрирован: 08.06.2017

Протестировал, если ошибся в чем - пиши

Без инвертирования, тестовый образец

//966   байт flash
//9     байт RAM

#define dataPin 5
#define clockPin 6
#define dataPin2 7
#define clockPin2 8
#define bitOrder MSBFIRST


void setup() {
  byte a = shiftIn(dataPin, clockPin, bitOrder);
  byte b = shiftIn(dataPin, clockPin, bitOrder);
  uint16_t ab = (a << 8) | (b);

  shiftOut(dataPin2, clockPin2, bitOrder, (ab >> 8));
  shiftOut(dataPin2, clockPin2, bitOrder, ab);
}

void loop() {}

Инвертирование моим вариантом

//972   байт flash
//9     байт RAM

#define dataPin 5
#define clockPin 6
#define dataPin2 7
#define clockPin2 8
#define bitOrder MSBFIRST

void setup() {
  byte a = shiftIn(dataPin, clockPin, bitOrder);
  byte b = shiftIn(dataPin, clockPin, bitOrder);
  uint16_t ab = (a << 8) | (b);
  ab = (ab & 0xFF) << 8 | (ab >> 8);
  shiftOut(dataPin2, clockPin2, bitOrder, (ab >> 8));
  shiftOut(dataPin2, clockPin2, bitOrder, ab);
}

void loop() {}

ASM

//972   байт flash
//9     байт RAM

#define dataPin 5
#define clockPin 6
#define dataPin2 7
#define clockPin2 8
#define bitOrder MSBFIRST

void setup() {
  byte a = shiftIn(dataPin, clockPin, bitOrder);
  byte b = shiftIn(dataPin, clockPin, bitOrder);
  uint16_t ab = (a << 8) | (b);
  asm (
    "mov __tmp_reg__, %A0" "\n\t"
    "mov %A0, %B0"         "\n\t"
    "mov %B0, __tmp_reg__" "\n\t"
    : "=r" (ab) : "0" (ab) );
  shiftOut(dataPin2, clockPin2, bitOrder, (ab >> 8));
  shiftOut(dataPin2, clockPin2, bitOrder, ab);
}

void loop() {}

Третий вариант удивил

//992   байт flash
//9     байт RAM

#define dataPin 5
#define clockPin 6
#define dataPin2 7
#define clockPin2 8
#define bitOrder MSBFIRST

void setup() {
  byte a = shiftIn(dataPin, clockPin, bitOrder);
  byte b = shiftIn(dataPin, clockPin, bitOrder);
  uint16_t ab = (a << 8) | (b);

  byte *p = (byte *)&ab;
  byte c = *p; *p = p[1]; p[1] = c;

  shiftOut(dataPin2, clockPin2, bitOrder, (ab >> 8));
  shiftOut(dataPin2, clockPin2, bitOrder, ab);
}

void loop() {}

 

Вот теперь есть последовательность в результатах

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну это понятно. В компиляторе встроен анализ на такую ситуацию. А вот по указателям нет такого анализа.

//994   байт flash
//9     байт RAM

#define dataPin 5
#define clockPin 6
#define dataPin2 7
#define clockPin2 8
#define bitOrder MSBFIRST

void setup() {
  byte a = shiftIn(dataPin, clockPin, bitOrder);
  byte b = shiftIn(dataPin, clockPin, bitOrder);
  uint16_t ab = (a << 8) | (b);
  ab = (ab  << 3) | (ab >> 3);
  shiftOut(dataPin2, clockPin2, bitOrder, (ab >> 8));
  shiftOut(dataPin2, clockPin2, bitOrder, ab);
}

void loop() {}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

wdrakula пишет:

dimax пишет:

Ну и на асмо-затычке для полноты коллекции :)

а если совместить? без временного регистра на трех XOR? Asm - операция EOR в АВРке.

uint16_t asm_func(uint16_t value ){
asm volatile (         
"eor  %A0, %B0" "\n\t"
"eor  %B0, %A0" "\n\t"
"eor  %A0, %B0" "\n\t"
 : "=r" (value) : "0" (value) );
  return value;
}

Ничего не выигрываем, те же три такта, но прикольнее.

---------------------------

Ну и проверочная програмка на все способы:

#include <stdlib.h>

uint16_t asm_swap(uint16_t value ){
asm volatile (         
"eor  %A0, %B0" "\n\t"
"eor  %B0, %A0" "\n\t"
"eor  %A0, %B0" "\n\t"
 : "=r" (value) : "0" (value) );
  return value;
}

void setup() {
  
Serial.begin(19200);
while (!Serial);
Serial.println("Input HEX number:");
}

void loop() {
byte buf[8]="0000000";
uint32_t a=0;
uint32_t b=0;
uint32_t c=0;
byte i=0;



while (Serial.available())
  {
    if (i<7)  buf[i++] = Serial.read();
  }
  if (!i) return;
  
buf[i] = 0;
a = strtol(buf,NULL,16);
b = a;

//=========ATTENTION!!!  BYTES SWAPPING!!! NO EXTRA MEMORY NEEDED!!!===================

*(byte*)&b ^= *((byte*)&b +1) ^= *(byte*)&b ^= *((byte*)&b +1);

//=======END OF BYTES SWAPPING========

c = asm_swap((uint16_t)b);

Serial.print("I  have  read  number:");
Serial.println(a,16);
Serial.print("I have  swapped bytes:");
Serial.println(b,16);
Serial.print("swapped back with asm:");
Serial.println(c,16);
Serial.println("==========================");
Serial.println("Input HEX number:");
}

 

Красиво! Я тоже благоговею от XOR, но вот такого применения еще не делал

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ua6em пишет:

Красиво! Я тоже благоговею от XOR, но вот такого применения еще не делал

Б..га побойтесь! Это олимпиадная  задачка по программированию. Причем разогревная.

Я такие больше 30 лет назад решал ради драйва....

bargundabal
Offline
Зарегистрирован: 08.06.2017
ab = (ab  << 3) | (ab >> 3);

Вообще не понял, что это должно быть.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

bargundabal пишет:

ab = (ab  << 3) | (ab >> 3);

Вообще не понял, что это должно быть.

Компилятор выискивает компинации <<8  и 8>> и компилирует их иначе , чем если это было другое число. Вот я и показал , что бы было если бы не было этого анализа. Это как заточеные под камни бенчмарки в противостоянии Интел и АМД. Так что использование комбинации >>8 выгоднее, так как компилятор "забъет" на сдвиг и тупо перенесет байт.

bargundabal
Offline
Зарегистрирован: 08.06.2017

Ну сдвиг на байт самый распространенный сдвиг, отсюда и низкая потребность в памяти. Я почти уверен, что этот сдвиг в одну команду идет независимо от направления, а сдвиг на 3 - да, внезапность.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

wdrakula пишет:

ua6em пишет:

Красиво! Я тоже благоговею от XOR, но вот такого применения еще не делал

Б..га побойтесь! Это олимпиадная  задачка по программированию. Причем разогревная.

Я такие больше 30 лет назад решал ради драйва....

Знаешь почему на Кавказе водители ездят не по правилам? Они их не учили!
За последние лет 10 за рулём учебных авто я не видел ни одного джигита, не по мужски это!

)))

но решение всё же красивое, это я об эстетике программирования, если такая есть

bargundabal
Offline
Зарегистрирован: 08.06.2017

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