Как объединить 4 байта в long ?

svi
Offline
Зарегистрирован: 19.10.2017

Добрый вечер.

есть массив 0x00 0x02 0xDD 0xCE что равно 187854 в десятичном виде

Хочу, НО не могу его засунуть его в long (выбрал long т.к. 4 байта)

Многие советуют "union", но толковой статьи не нашел про это чудо...

Подскажите, как решить проблему…

Или направьте на хорошую статью с примерами… сильно признателен буду :)

 

svi
Offline
Зарегистрирован: 19.10.2017

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]);
}

Использую вот эту строку

long &num = (long&)raw; // ИСПОЛЬЗУЮ ВОТ ЭТУ СТРОЧКУ

Отправля в Serial получаю отрицательное значение

 

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

Учите основы языка Си и не будете побираться по форумам из-за мелочей . Вы потеряли unsignedhttp://qaru.site/questions/114081/what-is-the-difference-between-signed-and-unsigned-int

mixail844
Offline
Зарегистрирован: 30.04.2012

тут два варианта : 

либо используя union :

typedef union 
{
uint8_t asArray[4];
long asNum;
}long_ut;

long_ut number ; 

//recvBuff - буффер куда были приняты данные

//прием данных например :
number.asArray = recvBuff;

// считывание 

Serial.print(number.asNum);

или "напрямую": 

//здесь используються битовые операторы "<<"(сдвиг влево) и "|" (побитовое "и" )
// в каждой итерации for происходит следующее :
// переменная number сдвигаеться влево на 8 бит и затем "помещение" одного байта из recvBuff в переменную number 
// допустим изначально number = 0x0 ; 
// 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

 

svi
Offline
Зарегистрирован: 19.10.2017

попробую отпишусь

svi
Offline
Зарегистрирован: 19.10.2017

mixail844 пишет:

или "напрямую": 

//здесь используються битовые операторы "<<"(сдвиг влево) и "|" (побитовое "и" )
// в каждой итерации for происходит следующее :
// переменная number сдвигаеться влево на 8 бит и затем "помещение" одного байта из recvBuff в переменную number 
// допустим изначально number = 0x0 ; 
// 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

СПАСИБО ОГРОМНОЕ!!! Все работает.

Метод "напрямую" мне больше подходит. Так проще разобраться в работе кода.

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

а через адрес начала буфера С не позволяет забрать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Позволяет.

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

ЕвгенийП пишет:

Позволяет.


А можно поинтересоваться примером?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
uint8_t bufer[4];
//......
uint32_t ulV = * reinterpret_cast <uint32_t *> (bufer);

Если включена строгая поверка типов, получите предупреждение, но ничего страшного.

mixail844
Offline
Зарегистрирован: 30.04.2012

но будьте аккуратны 

#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   

 

a5021
Offline
Зарегистрирован: 07.07.2013

Приведение типа по ссылке мне все равно представляется более наглядным:

    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

 

 

 
mixail844
Offline
Зарегистрирован: 30.04.2012

a5021 пишет:

Приведение типа по ссылке мне все равно представляется более наглядным:

    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;

чядн ?

a5021
Offline
Зарегистрирован: 07.07.2013

C++

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mixail844 пишет:

чядн ?

Скорее всего язык не тот. А вообще, здесь форум по ардуино, вот в ардуино IDE и запускайте, а не где попало :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

a5021 пишет:

Приведение типа по ссылке мне все равно представляется более наглядным:

 

насчёт наглядности - ХЗ, редко встречаю новичка, знающего о существовании ссылок, и уж совсем редко такого, кто понимает что это такое и чем от указателей отличается.

А то, что короче и как-то законченнее, чем с указателями, таки да, тут согласен.

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

Не взлетело )))
Похоже в ардуино используется 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);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так расположите байты правильно - взлетит

sadman41
Offline
Зарегистрирован: 19.10.2016

Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. А удаленный хост будет не той системы... Башку потом сломаешь, пытаясь понять что откуда лезет.

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

ЕвгенийП пишет:

Так расположите байты правильно - взлетит


Да это понятно...
Задача, принимаем данные по последовательному интерфейсу, от младшего байта к старшему, складируем в буфер, далее из буфера извлекаем нужные данные...
Хотелось изящно, ан нет )))
А есть стек в ардуине? Может через стек перевернуть порядок?

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

sadman41 пишет:

Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. А удаленный хост будет не той системы... Башку потом сломаешь, пытаясь понять что откуда лезет.

Так жонглировал, правда на ассемблере (точнее в кодах писал)

a5021
Offline
Зарегистрирован: 07.07.2013

sadman41 пишет:
Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. А удаленный хост будет не той системы... Башку потом сломаешь, пытаясь понять что откуда лезет.

Ровно та же проблема встает во весь рост и без приведения типов, т.ч. без уточнения, какой endianness на той стороне, лучше вообще не начинать.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

a5021
Offline
Зарегистрирован: 07.07.2013

Фиг знает, я с этими разноконечностями сталкивался уже достаточно, а все равно никак не запомню, где у них что. Как затруднения, так букварь листать.

Цитата:
здесь форум по ардуино, вот в ардуино IDE и запускайте, а не где попало :)

Поискал, кстати,  ардуино-онлайн, как раз для таких целей, но гугл ничего не находит.

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

Такие вещи надо однозначно в ПЕСОЧНИЦЕ обозначить
 

 

sadman41
Offline
Зарегистрирован: 19.10.2016

a5021 пишет:

Фиг знает, я с этими разноконечностями сталкивался уже достаточно, а все равно никак не запомню, где у них что. Как затруднения, так букварь листать.

Цитата:
здесь форум по ардуино, вот в ардуино IDE и запускайте, а не где попало :)

Поискал, кстати,  ардуино-онлайн, как раз для таких целей, но гугл ничего не находит.

https://www.tinkercad.com/ , регистрация нужна, правда.

a5021
Offline
Зарегистрирован: 07.07.2013

Это я видел. Месяц триала, а потом деньги платить. Не впечатлило.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:

Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. 

Что да, то да. Есть, конечно, специально для этого функции htons(), htonl(), ntohs(), ntohl(), но как-то не пришлись они мне.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

a5021 пишет:

Поискал, кстати,  ардуино-онлайн, как раз для таких целей, но гугл ничего не находит.

Редактор и компилятор есть онлайн на arduino.cc, а эмуляция ардуино есть в протеусе (тоже, правда, не бесплатно).

Кстати, о протеусе, натыкался на то, что один и тот же скетч:

1. На живом железном ардуино - OK
2. На голом ATmega328P в протеусе - Ok
3. на ардуино в протеусе - хренушки.

Так что теперь стараюсь в протеусе юзать голые чипы - больше доверия.

a5021
Offline
Зарегистрирован: 07.07.2013

ЕвгенийП пишет:
Что да, то да. Есть, конечно, специально для этого функции htons(), htonl(), ntohs(), ntohl(), но как-то не пришлись они мне.

Так непонятно, где их применять, если AVR, ARM, PC -- все Little-Endian. Нет смысла конвертировать в сетевой порядок, чтобы на другом конце делать обратное преобразование.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

a5021 пишет:
Нет смысла конвертировать в сетевой порядок, чтобы на другом конце делать обратное преобразование.
Смысл в стандартизации. Типа "по каналу связи идёт всегда так, а не иначе". А уж после получения или перед отправкой, делай что хочешь. Тогда каждый будет знать что ему делать, а не гадать, "что там, на той стороне".

Это чистая условность, как цвета проводов в электропроводке. Никакие электрические характеристики провода от цвета изоляции не зависят, но если Вы обнаруживаете фазу на жёлто-зелёном (пусть даже везде по дому единообразно и всё отлично работает), сразу ясно, что делал любитель, т.к. профессионал не сделает такого от слова никогда.

a5021
Offline
Зарегистрирован: 07.07.2013

ЕвгенийП пишет:
Смысл в стандартизации. Типа "по каналу связи идёт всегда так, а не иначе".

Не все так просто. В спецификации TCP/IP и Modbus жестко закреплен сетевой порядок передачи. В LIN и USB -- обратный, т.е. Little Endian. В стандарте CAN порядок следования отдан на откуп пользователю. Как ко всему этому подступиться с мерками "стандартизации", совсем непонятно.

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

ЕвгенийП пишет:

sadman41 пишет:

Через приведение типов опасно мультибайтовыми переменными жонглировать. Захочется в какой-нить коммуникационный протокол такую изящную экономку запихать. 

Что да, то да. Есть, конечно, специально для этого функции htons(), htonl(), ntohs(), ntohl(), но как-то не пришлись они мне.

Да и не компилятся в IDE

sadman41
Offline
Зарегистрирован: 19.10.2016

Могу отсыпать макросов, если надо.

#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)

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

Да и не компилятся в IDE

Почему? У меня 1.8.5 - всё компилится. Дайте точный код, что у Вас не компилится, версию IDE и сообщение компилятора.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

a5021 пишет:
В спецификации TCP/IP и Modbus жестко закреплен сетевой порядок передачи. В LIN и USB -- обратный, т.е. Little Endian. В стандарте CAN порядок следования отдан на откуп пользователю. Как ко всему этому подступиться с мерками "стандартизации", совсем непонятно.

Так ото ж. Корпоративные интересы берут верх над здравым смыслом. Разные разъёмы в разных министерствах СССР, ни у одного мобильника (до андроида) зарядка к другому не подходит, но всё это не отменяет пользы стандартизации.

sadman41
Offline
Зарегистрирован: 19.10.2016

Просто так, без инклюдов сетевых примочек не должны компилиться, конечно. Они же во всяких util.h раскиданы.

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

sadman41 пишет:

Могу отсыпать макросов, если надо.

#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 делать

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

ЕвгенийП пишет:

ua6em пишет:

Да и не компилятся в 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);
}

 

a5021
Offline
Зарегистрирован: 07.07.2013

Хорошо ARM-ам. У них порядок следования байтов в 32-битном слове можно менять одной командой REV, а буде этого покажется мало, то с помощью команды RBIT можно и порядок битов поменять. Вобщем, как обычно, всем срочно на голубую пилюлю! :)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

дак и Интел умеет swap делать.  Што теперь, все на Интел?  

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

svi пишет:

есть массив 0x00 0x02 0xDD 0xCE что равно 187854 в десятичном виде

Хочу, НО не могу его засунуть его в long (выбрал long т.к. 4 байта)

Многие советуют "union", но толковой статьи не нашел про это чудо...

про union-ы: 

union TBytes {

  uint32_t Value;

  uint8_t Bytes[4];

}

и всё.  Обьявляешь переменную типа TBytes, и обращаешься или к Value или к массиву Bytes.

TBytes MyVar;

MyVar.Value = 187854;

uint8_t lobyte = MyVar.Bytes[0];

 

svi
Offline
Зарегистрирован: 19.10.2017

DetSimen пишет:

svi пишет:

есть массив 0x00 0x02 0xDD 0xCE что равно 187854 в десятичном виде

Хочу, НО не могу его засунуть его в long (выбрал long т.к. 4 байта)

Многие советуют "union", но толковой статьи не нашел про это чудо...

про union-ы: 

union TBytes {

  uint32_t Value;

  uint8_t Bytes[4];

}

и всё.  Обьявляешь переменную типа TBytes, и обращаешься или к Value или к массиву Bytes.

TBytes MyVar;

MyVar.Value = 187854;

uint8_t lobyte = MyVar.Bytes[0];

 

Спасибо огромное. Этот способ очень удобный... вот только не описан для начинающих толком.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ну это, канеш, удобнее, чем черезжопные преобразования со ссылками. 

Этот способ оч. хорошо у Кернигана описан, надо пойти в песочницу и в первом сообщении первого поста скачать эту книшку.  Без нее С не даст. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

Што теперь, все на Интел?  

На "Эдисон"!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

svi пишет:
вот только не описан для начинающих толком.
Почему? Описан в КиР, просто начинающие "не читают толком".

a5021
Offline
Зарегистрирован: 07.07.2013

Какой КиР ? Начинающие не осилили даже сообщения №3 в этой ветке, где данный метод уже излагался. Не читатель, в общем.

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

a5021 пишет:

Какой КиР ? Начинающие не осилили даже сообщения №3 в этой ветке, где данный метод уже излагался. Не читатель, в общем.

я осилил )))

svi
Offline
Зарегистрирован: 19.10.2017

что за КиР ?! 

подскажите, я прочитаю...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Зайди в песочницу, во второе сообщение первой темы, там много полезного. 

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

DetSimen пишет:

Зайди в песочницу, во второе сообщение первой темы, там много полезного. 


Дед, есть предложение, для пенсионеров оказывать помощь, в расчёте на то, что прочитать то они смогут, понять и применить - на в ряд ли...