преобразование unsigned long > byte (4 штуки) и обратно
- Войдите на сайт для отправки комментариев
Сб, 24/11/2012 - 15:38
Появилась задачка - надо unsigned long сохранить в EEPROM.
Естественно, потом надо будет читать из EEPROM и собирать данные назад в unsigned long.
Подскажите, как сделать?
правильно ли я понимаю, что собрать можно так:
unsigned long value = (data[3] << 24) +(data[2] << 16) +(data[1] << 8) +data[0];
а как разобрать?
Пока не получается.
Поискал по форуму, нашел похожую задачу (там int разбирали на байты). "Разбор" получился красивый, а вот мое предположение по "сборке" - не сработало.
unsigned long val = 1587632040; unsigned long value; void setup() { Serial.begin(9600); Serial.print("val "); Serial.println(val, DEC); byte *x = (byte *)&val; for (int i=0; i<4; i++) { Serial.println(x[i], DEC); } unsigned long value = (x[3] << 24) +(x[2] << 16) +(x[1] << 8) +x[0]; Serial.print("val "); Serial.println(value, DEC); } void loop() { }Где ошибка?
На вашем месте я сначала бы изменил формат вывода:
unsigned long val = 1587632040; unsigned long value; void setup() { Serial.begin(9600); Serial.print("val "); Serial.print(val, DEC); Serial.print(" "); Serial.println(val, HEX); byte *x = (byte *)&val; for (int i=0; i<4; i++) { Serial.print(x[i], DEC); Serial.print(" "); Serial.println(x[i], HEX); } unsigned long value = (x[3] << 24) +(x[2] << 16) +(x[1] << 8) +x[0]; Serial.print("val "); Serial.print(value, DEC); Serial.print(" "); Serial.println(value, HEX); }После чего мне сразу бы бросилось в глаза, что преобразование выполняется в общем-то правильно, но только для двух младших байтов:
val 1587632040 5EA157A8
168 A8
87 57
161 A1
94 5E
val 22440 57A8
После этого мне не оставалось бы ничего иного, как вспомнить, что обработка данных в микроконтроллерах AVR заточена под переменные размером в слово, т.е. два байта, т.е. (для математических действий) тип int. А, стало быть, компилятору необходимо явно указать, что работать будем не со словами а с двойными словами (тип unsigned long). А для этого необходимо выполнить кастинг (по-русски "приведение типа") участвующих в выражении переменных. Вот так (строка 16 в моем варианте):
После этого я прогнал бы скетч снова и получил вот такой вывод:
val 1587632040 5EA157A8
168 A8
87 57
161 A1
94 5E
val 1587632040 5EA157A8
"Почему в двух правых слагаемых нет этого чертового кастинга?" спросите вы. Да потому что там мы оперируем информацией в пределах слова, стало быть, явное приведение типов не является необходимым. А делать лишнюю работу нам естественно лень...
Можно еще воспользоваться такой интересной штукой, как Union
union mytype { long l; byte b[4]; }Тогда к переменной этого типа можно будт обращаться целиком через l или к каждому байту через b
Спасибо, оба варианта завелись. Второй вариант особенно понравился - красиво получилось!
union IRcommand { unsigned long l; byte b[4]; } val; void setup(){ val.l=1587632040; Serial.begin(9600); Serial.print("val "); Serial.print(val.l, DEC); Serial.print(" "); Serial.println(val.l, HEX); byte *x = (byte *)&val; for (int i=0; i<4; i++) { Serial.print(val.b[i], DEC); Serial.print(" "); Serial.println(val.b[i], HEX); } } void loop(){ }Время доброе. Будьте добры, если не трудно разеснить выделинные действия?
unsigned long value = ((unsigned long)x[3] << 24) +((unsigned long)x[2] << 16) +(x[1] << 8) +x[0];
Зарание спасибо
Выделенные действия - результат выкрутасов HTML-редакторов и копипасты. В детстве все эти "<<" имели вид "<<". В своем посте - поправил.
Или вы имели в виду иное?
доброго времени суток.
собрал скетч по теме
union IRcommand { unsigned long l; byte b[4]; } val; void setup(){ // val.l=1131134310; // - хорошо // val.l=1587632040; // - хорошо val.l=1111134310; // странно както сборка получается Serial.begin(9600); Serial.print("val "); Serial.print(val.l, DEC); Serial.print(" "); Serial.println(val.l, HEX); byte *x = (byte *)&val; for (int i=0; i<4; i++) { Serial.print(val.b[i], DEC); Serial.print(" "); Serial.println(val.b[i], HEX); } unsigned long value = ((unsigned long)x[3] << 24) +((unsigned long)x[2] << 16) +(x[1] << 8) +x[0]; Serial.println("------------------"); Serial.print("value "); Serial.print(value, DEC); Serial.print(" "); Serial.println(value, HEX); } void loop(){ }с значениями val 1587632040 и 1587632040 собрать обратно число получается хорошо но с значение 1111134310 выводит
Подсажите пожалуйста где я ошибся.
Спасибо
У вас "каша-малаша" получилась. Вы зарбираете передавая ссылку на объединение (бред полный), а собираете сдвигами.
void setup(){ Serial.begin(9600); byte val_1[4]; unsigned long &value_1 = (unsigned long&)val_1; value_1 = 1111134310; Serial.println(value_1, DEC); byte val_2[4]; memcpy(val_2, val_1, 4); // присваиваем массив val_1 массиву val_2 unsigned long &value_2 = (unsigned long&)val_2; Serial.println(value_2, DEC); }Тоже интересовал этот вопрос вот тут нашёл понятный для мне ответ http://playground.arduino.cc/Code/EEPROMReadWriteLong . Суть аналогична разложить на 4 байта , записать в епром , считать и собрать эти 4 байта обратно.
Тут https://www.arduino.cc/en/Reference/Bitshift наглядно объяснняют как это работает =)
Появилась задачка - надо unsigned long сохранить в EEPROM.
Естественно, потом надо будет читать из EEPROM и собирать данные назад в unsigned long.
Подскажите, как сделать?
Решил не создавать лишнюю тему, т.к. задача очень подобная.
Есть float, надо преобразовать в 4 байта.
float temper;
byte sendbuf[4];
temper = sensor.getTempC();
memcpy(&temper, &sendbuf[0], sizeof(float));
В результате операции в массиве sendbuf все нули, хотя в temper есть нормальное число.
Что не так?
У тебя источник и премник данных местами перепутаны в параметрах. Сначала адрес " куда", потом "откуда"
Serial.begin(9600); unsigned long k = 1000000; byte* pk = (byte*)&k; //разобрали на байты for(int i=0; i<sizeof(k); i++) { Serial.print(pk[i]);Serial.print(" "); } Serial.println(""); unsigned long nk = *(unsigned long*)pk;//Собрали байты воедино Serial.println(nk);Ну так, шаблон наваяй, вместо того, чтоб некрофилией занимаца. А еще лучше - лямбда-шаблон.
Нельзя. Наебнется на куче платформ. Или порядок байтов будет неправильный.
Ну, на всех ардуинах этот код пишу при записи во внешний EEPROM по I2C, все работает, мне хватает, просто написал, может кому понадобиться.
Нормально. Компилил в линь_х64, тока буте на чар заменил. 8 байт длина лонга в х64. Какая хер разница, ежли пихать в еепром и оттуда же вытаскивать? Всё всё-равно останецца на своих местах.
EEPROM.put() поддерживает даже структуры