Как объединить 4 байта в long ?
- Войдите на сайт для отправки комментариев
Вс, 02/12/2018 - 02:41
Добрый вечер.
есть массив 0x00 0x02 0xDD 0xCE что равно 187854 в десятичном виде
Хочу, НО не могу его засунуть его в long (выбрал long т.к. 4 байта)
Многие советуют "union", но толковой статьи не нашел про это чудо...
Подскажите, как решить проблему…
Или направьте на хорошую статью с примерами… сильно признателен буду :)
http://arduino.ru/forum/programmirovanie/zapis-i-chtenie-eeprom-peremennykh-tipa-float-unsigned-long-long-unsigned-int
Ниже тему нашел про Епром. Насколько я понял у меня задача точно такая же как и при чтении long из флешки.
// чтение long EEPROM_long_read(int addr) { byte raw[4]; for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i); long &num = (long&)raw; // ИСПОЛЬЗУЮ ВОТ ЭТУ СТРОЧКУ return num; } // запись void EEPROM_long_write(int addr, long num) { byte raw[4]; (long&)raw = num; for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]); }Использую вот эту строку
Отправля в Serial получаю отрицательное значение
Учите основы языка Си и не будете побираться по форумам из-за мелочей . Вы потеряли unsigned. http://qaru.site/questions/114081/what-is-the-difference-between-signed-and-unsigned-int
тут два варианта :
либо используя union :
typedef union { uint8_t asArray[4]; long asNum; }long_ut; long_ut number ; //recvBuff - буффер куда были приняты данные //прием данных например : number.asArray = recvBuff; // считывание Serial.print(number.asNum);или "напрямую":
// a recvBuff[] = {0x00,0x02,0xDD,0xCE}; long number ; for(uint8_t i = 0 ; i < 4 ;i++) { number <<= 8; number |= recvBuff[i]; } //тогда итерации будут выглядеть следующим образом (hex format) //1. recvBuff[0] = 0x00 , number = 0x00000000; //2. recvBuff[1] = 0x02 , number = 0x00000002; //3. recvBuff[2] = 0xDD , number = 0x000002DD; //4. recvBuff[3] = 0xCE , number = 0x0002DDCE; //так же нужно учитывать т.н. Enidaness принимающей и отправляющей стороны //Есть 2 типа "BigEndian" , "LittleEndian" .. //разница в том что одни системы отправляют и принимают данные по разному : // Most Significant Byte (MSB) First , а другие наоборот : Last Significant Byte(LSB) First. //от этого зависит в какой последовательности считывать байты из RecvBuff // и помещать в numberпопробую отпишусь
или "напрямую":
// a recvBuff[] = {0x00,0x02,0xDD,0xCE}; long number ; for(uint8_t i = 0 ; i < 4 ;i++) { number <<= 8; number |= recvBuff[i]; } //тогда итерации будут выглядеть следующим образом (hex format) //1. recvBuff[0] = 0x00 , number = 0x00000000; //2. recvBuff[1] = 0x02 , number = 0x00000002; //3. recvBuff[2] = 0xDD , number = 0x000002DD; //4. recvBuff[3] = 0xCE , number = 0x0002DDCE; //так же нужно учитывать т.н. Enidaness принимающей и отправляющей стороны //Есть 2 типа "BigEndian" , "LittleEndian" .. //разница в том что одни системы отправляют и принимают данные по разному : // Most Significant Byte (MSB) First , а другие наоборот : Last Significant Byte(LSB) First. //от этого зависит в какой последовательности считывать байты из RecvBuff // и помещать в numberСПАСИБО ОГРОМНОЕ!!! Все работает.
Метод "напрямую" мне больше подходит. Так проще разобраться в работе кода.
а через адрес начала буфера С не позволяет забрать?
Позволяет.
Позволяет.
А можно поинтересоваться примером?
Если включена строгая поверка типов, получите предупреждение, но ничего страшного.
но будьте аккуратны
#include <stdio.h> #include "stdint.h" int main() { uint32_t number ; uint8_t buffer1[4] = {0xCE,0xDD,0x02,0x00}; uint8_t buffer2[4] = {0x00,0x02,0xDD,0xCE}; number = *((uint32_t*)buffer1); printf("number 1 : %u\n",number); number = *((uint32_t*)buffer2); printf("number 2 : %u\n",number); return 0; } //number 1 : 187854 //number 2 : 3470590464Приведение типа по ссылке мне все равно представляется более наглядным:
uint32_t number ; uint8_t buffer1[4] = {0xCE,0xDD,0x02,0x00}; uint8_t buffer2[4] = {0x00,0x02,0xDD,0xCE}; number = (uint32_t&)buffer1; printf("number 1 : %08X\n", number); number = (uint32_t&)buffer2; printf("number 2 : %08X\n", number);и результат:
number 1 : 0002DDCE
number 2 : CEDD0200
Приведение типа по ссылке мне все равно представляется более наглядным:
uint32_t number ; uint8_t buffer1[4] = {0xCE,0xDD,0x02,0x00}; uint8_t buffer2[4] = {0x00,0x02,0xDD,0xCE}; number = (uint32_t&)buffer1; printf("number 1 : %08X\n", number); number = (uint32_t&)buffer2; printf("number 2 : %08X\n", number);и результат:
number 1 : 0002DDCE
number 2 : CEDD0200
что то я не в дуплю,как это у вас заработало(должно работать) ,в чем запускали ?
было инстресно как это работает,запустил в online компиляторе версия GCC 8.1.0
#include <stdio.h> #include "stdint.h" int main() { uint32_t number ; uint8_t buffer1[4] = {0xCE,0xDD,0x02,0x00}; uint8_t buffer2[4] = {0x00,0x02,0xDD,0xCE}; number = (uint32_t&)buffer1; printf("number 1 : %08X\n", number); number = (uint32_t&)buffer2; printf("number 2 : %08X\n", number); return 0; }результат :
jdoodle.c: In function 'main': jdoodle.c:9:21: error: expected ')' before '&' token number = (uint32_t&)buffer1; ~ ^ ) jdoodle.c:9:12: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] number = (uint32_t&)buffer1; ^ jdoodle.c:11:21: error: expected ')' before '&' token number = (uint32_t&)buffer2; ~ ^ ) jdoodle.c:11:12: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] number = (uint32_t&)buffer2;чядн ?
C++
чядн ?
Скорее всего язык не тот. А вообще, здесь форум по ардуино, вот в ардуино IDE и запускайте, а не где попало :)
Приведение типа по ссылке мне все равно представляется более наглядным:
насчёт наглядности - ХЗ, редко встречаю новичка, знающего о существовании ссылок, и уж совсем редко такого, кто понимает что это такое и чем от указателей отличается.
А то, что короче и как-то законченнее, чем с указателями, таки да, тут согласен.
Не взлетело )))
Похоже в ардуино используется LSB
unsigned long rrr; uint8_t buffer[4] = {0x01,0x02,0x03,0x04}; void setup() { Serial.begin(9600); } void loop() { rrr = *((uint32_t*)buffer); Serial.print(rrr,HEX); delay(5000); }Так расположите байты правильно - взлетит
Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. А удаленный хост будет не той системы... Башку потом сломаешь, пытаясь понять что откуда лезет.
Так расположите байты правильно - взлетит
Да это понятно...
Задача, принимаем данные по последовательному интерфейсу, от младшего байта к старшему, складируем в буфер, далее из буфера извлекаем нужные данные...
Хотелось изящно, ан нет )))
А есть стек в ардуине? Может через стек перевернуть порядок?
Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. А удаленный хост будет не той системы... Башку потом сломаешь, пытаясь понять что откуда лезет.
Так жонглировал, правда на ассемблере (точнее в кодах писал)
Ровно та же проблема встает во весь рост и без приведения типов, т.ч. без уточнения, какой endianness на той стороне, лучше вообще не начинать.
Так кот же спорит... Однако, мне кажется, что пока пишешь код сбора из отдельных байт - хоть немного соображаешь, как оно работает, а через приведение - как-то не наглядно. Зато красиво и и хочется использовать.
Фиг знает, я с этими разноконечностями сталкивался уже достаточно, а все равно никак не запомню, где у них что. Как затруднения, так букварь листать.
Поискал, кстати, ардуино-онлайн, как раз для таких целей, но гугл ничего не находит.
Такие вещи надо однозначно в ПЕСОЧНИЦЕ обозначить
Фиг знает, я с этими разноконечностями сталкивался уже достаточно, а все равно никак не запомню, где у них что. Как затруднения, так букварь листать.
Поискал, кстати, ардуино-онлайн, как раз для таких целей, но гугл ничего не находит.
https://www.tinkercad.com/ , регистрация нужна, правда.
Это я видел. Месяц триала, а потом деньги платить. Не впечатлило.
Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать.
Что да, то да. Есть, конечно, специально для этого функции htons(), htonl(), ntohs(), ntohl(), но как-то не пришлись они мне.
Поискал, кстати, ардуино-онлайн, как раз для таких целей, но гугл ничего не находит.
Редактор и компилятор есть онлайн на arduino.cc, а эмуляция ардуино есть в протеусе (тоже, правда, не бесплатно).
Кстати, о протеусе, натыкался на то, что один и тот же скетч:
1. На живом железном ардуино - OK
2. На голом ATmega328P в протеусе - Ok
3. на ардуино в протеусе - хренушки.
Так что теперь стараюсь в протеусе юзать голые чипы - больше доверия.
Так непонятно, где их применять, если AVR, ARM, PC -- все Little-Endian. Нет смысла конвертировать в сетевой порядок, чтобы на другом конце делать обратное преобразование.
Это чистая условность, как цвета проводов в электропроводке. Никакие электрические характеристики провода от цвета изоляции не зависят, но если Вы обнаруживаете фазу на жёлто-зелёном (пусть даже везде по дому единообразно и всё отлично работает), сразу ясно, что делал любитель, т.к. профессионал не сделает такого от слова никогда.
Не все так просто. В спецификации TCP/IP и Modbus жестко закреплен сетевой порядок передачи. В LIN и USB -- обратный, т.е. Little Endian. В стандарте CAN порядок следования отдан на откуп пользователю. Как ко всему этому подступиться с мерками "стандартизации", совсем непонятно.
Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать.
Что да, то да. Есть, конечно, специально для этого функции htons(), htonl(), ntohs(), ntohl(), но как-то не пришлись они мне.
Да и не компилятся в IDE
Могу отсыпать макросов, если надо.
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) #define ntohs(x) htons(x) #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ ((x)<< 8 & 0x00FF0000UL) | \ ((x)>> 8 & 0x0000FF00UL) | \ ((x)>>24 & 0x000000FFUL) ) #define ntohl(x) htonl(x)Да и не компилятся в IDE
Почему? У меня 1.8.5 - всё компилится. Дайте точный код, что у Вас не компилится, версию IDE и сообщение компилятора.
Так ото ж. Корпоративные интересы берут верх над здравым смыслом. Разные разъёмы в разных министерствах СССР, ни у одного мобильника (до андроида) зарядка к другому не подходит, но всё это не отменяет пользы стандартизации.
Просто так, без инклюдов сетевых примочек не должны компилиться, конечно. Они же во всяких util.h раскиданы.
Могу отсыпать макросов, если надо.
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) #define ntohs(x) htons(x) #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ ((x)<< 8 & 0x00FF0000UL) | \ ((x)>> 8 & 0x0000FF00UL) | \ ((x)>>24 & 0x000000FFUL) ) #define ntohl(x) htonl(x)Благодарю!
А то хотел попарное XOR делать
Да и не компилятся в IDE
Почему? У меня 1.8.5 - всё компилится. Дайте точный код, что у Вас не компилится, версию IDE и сообщение компилятора.
С макросами скомпилировалось! Код.
1.8.7
Arduino: 1.8.7 (Windows 7), Плата:"Arduino Nano, ATmega328P (Old Bootloader)" C:\Users\User\Documents\Arduino\2018\HEX_EEPROM\HEX_EEPROM.ino: In function 'void loop()': HEX_EEPROM:84:26: error: 'ntohl' was not declared in this scope Serial.println(ntohl(ulV),HEX); ^ exit status 1 'ntohl' was not declared in this scope Этот отчёт будет иметь больше информации с включенной опцией Файл -> Настройки -> "Показать подробный вывод во время компиляции"#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) #define ntohs(x) htons(x) #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ ((x)<< 8 & 0x00FF0000UL) | \ ((x)>> 8 & 0x0000FF00UL) | \ ((x)>>24 & 0x000000FFUL) ) #define ntohl(x) htonl(x) #include <EEPROM.h> unsigned long rrr; unsigned long r = 0x01020304; uint8_t buffer[8] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; void setup() { Serial.begin(9600); for (int i = 0; i < 1024;) { if (i <16)Serial.print("00"); if (i >0 && i <256)Serial.print("0"); Serial.print(i,HEX); for (int a = 0; a <16; a++){ Serial.print(" "); if (int b = EEPROM.read(i) <16)Serial.print("0"); Serial.print(EEPROM.read(i),HEX); i++; } Serial.println(); } } void loop() { rrr = *((uint32_t*)buffer); uint32_t ulV = * reinterpret_cast <uint32_t *> (buffer); Serial.println(rrr,HEX); delay(5000); Serial.println(r,HEX); delay(5000); rrr = (uint32_t&)buffer; Serial.println(ntohl(ulV),HEX); delay(5000); }Хорошо ARM-ам. У них порядок следования байтов в 32-битном слове можно менять одной командой REV, а буде этого покажется мало, то с помощью команды RBIT можно и порядок битов поменять. Вобщем, как обычно, всем срочно на голубую пилюлю! :)
дак и Интел умеет swap делать. Што теперь, все на Интел?
есть массив 0x00 0x02 0xDD 0xCE что равно 187854 в десятичном виде
Хочу, НО не могу его засунуть его в long (выбрал long т.к. 4 байта)
Многие советуют "union", но толковой статьи не нашел про это чудо...
про union-ы:
union TBytes { uint32_t Value; uint8_t Bytes[4]; }и всё. Обьявляешь переменную типа TBytes, и обращаешься или к Value или к массиву Bytes.
есть массив 0x00 0x02 0xDD 0xCE что равно 187854 в десятичном виде
Хочу, НО не могу его засунуть его в long (выбрал long т.к. 4 байта)
Многие советуют "union", но толковой статьи не нашел про это чудо...
про union-ы:
union TBytes { uint32_t Value; uint8_t Bytes[4]; }и всё. Обьявляешь переменную типа TBytes, и обращаешься или к Value или к массиву Bytes.
Спасибо огромное. Этот способ очень удобный... вот только не описан для начинающих толком.
ну это, канеш, удобнее, чем черезжопные преобразования со ссылками.
Этот способ оч. хорошо у Кернигана описан, надо пойти в песочницу и в первом сообщении первого поста скачать эту книшку. Без нее С не даст.
Што теперь, все на Интел?
На "Эдисон"!
Какой КиР ? Начинающие не осилили даже сообщения №3 в этой ветке, где данный метод уже излагался. Не читатель, в общем.
Какой КиР ? Начинающие не осилили даже сообщения №3 в этой ветке, где данный метод уже излагался. Не читатель, в общем.
я осилил )))
что за КиР ?!
подскажите, я прочитаю...
Зайди в песочницу, во второе сообщение первой темы, там много полезного.
Зайди в песочницу, во второе сообщение первой темы, там много полезного.
Дед, есть предложение, для пенсионеров оказывать помощь, в расчёте на то, что прочитать то они смогут, понять и применить - на в ряд ли...