собрать unsigned long из Serial.read();

rene
Offline
Зарегистрирован: 21.01.2014

Доброго времени суток!

Есть входящий поток данных , мне необходимо "поймать" 4 первых байта и собрать в unsigned long

например так:

byte i = 0:
unsigned long *ptrVar;
while (Serial.available()) {
	if (i < 4) ptrVar[i] = Serial.read();
	i ++;	
}
Serial.println(*ptrVar);

В итоге получаю 10, хотя при чтении идут сплошные  нули. Что делаю не так?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Надо объявить массив символов char arr[4] заполнить его данными из порта и после этого смотреть на него как на unsigned long. Либо полученные данные сразу класть в unsigned long переменную со сдвигом.

rene
Offline
Зарегистрирован: 21.01.2014

Andy пишет:

Надо объявить массив символов char arr[4] заполнить его данными из порта и после этого смотреть на него как на unsigned long. Либо полученные данные сразу класть в unsigned long переменную со сдвигом.

Ну с первым понятно, хотелось бы второй вариант, можете поподробнее?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

типа такого:

unsigned long ul=0;
for (i=0; i<4; i++) ul |= Serial.read() << (i*8);

 

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

Andy пишет:

типа такого:

unsigned long ul=0;
for (i=0; i<4; i++) ul |= Serial.read() << (i*8);

А Вы это пробовали, прежде, чем человеку предлагать? Оно ж в таком виде не работает ни фига.

rene
Offline
Зарегистрирован: 21.01.2014

Да, действительно не работает, вот например:

void setup() {
  Serial.begin(9600);
  char a[4]= {0,1,0,0};
  unsigned long ptrVar;
  for (byte i = 0; i < 4; i ++) {
    ptrVar |= a[i] << (i*8);
  }
  Serial.println(ptrVar);
}

void loop() {
}

Вроде как 256 должно быть, а получаю 1310785793
 

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

rene пишет:
Да, действительно не работает, вот например:

Вроде как 256 должно быть, а получаю 1310785793

Ну, во-первых, Вы забыли проинициализировать ptrVar.

Во-вторых, для корректности эксперимента Вам следует в строке 3 вместо char a[4] использовать int a[4], т.к. метод read() возвращает именно int.

Но работать всё равно не будет.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Переопределить тип переменным не судьба? ptrVar |= (long)a[i] << (i*8);

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

Andy пишет:

Переопределить тип переменным не судьба? ptrVar |= (long)a[i] << (i*8);

Не знаю, Вам виднее судьба Вам или не судьба. Видимо, не судьба, раз дали начинающему коллеге неработающий код.

Да и сейчас signed с unsigned в одну кучу свалили, что тоже не самая лучшая практика.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Из чего следует что я что-то с чем-то свалил в одну кучу? Я так понимаю на этом возражения закончились....

rene
Offline
Зарегистрирован: 21.01.2014

Почитал о регистровом сдвиге, наваял такой код:

void setup() {
  Serial.begin(9600);
  byte a[4] = {1, 0, 0, 0};
  unsigned long ptrVar = 0;
  for (byte i = 0; i < 4; i ++) {
    ptrVar <<= 8;
    ptrVar += a[i];
  }
  Serial.println(ptrVar);
}

void loop() {
}

Работает, только задом на перед, младшие байты попадают на место старших. Как это сделать правильно?

Код ptrVar |= (long)a[i] << (i*8); я не совсем понимаю, это получается мы сдвигаем биты элемента массива a[i], а потом проводим логическую операцию ИЛИ этого сдвинутого элемента и переменной ptrVar?

И по поводу приведения char в long, разве так можно? Мы же так код символа получим вместо самого числа?

 

rene
Offline
Зарегистрирован: 21.01.2014

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

Ну, во-первых, Вы забыли проинициализировать ptrVar.

Во-вторых, для корректности эксперимента Вам следует в строке 3 вместо char a[4] использовать int a[4], т.к. метод read() возвращает именно int.

Да, увидел свою ошибку, спасибо!

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

Andy пишет:

Из чего следует что я что-то с чем-то свалил в одну кучу? Я так понимаю на этом возражения закончились....

prtVar какого типа? А в правой части Вы к какому приводите? Вот из этого и следует. что свалили в одну кучу.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

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

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

rene пишет:
Почитал о регистровом сдвиге, наваял такой код:

rene, хорошо, что разобрались, но с точки зрения эффективности и по памяти, и по времени, лучше всё-таки использовать другой способ о котором Вам говорили. Там не нужно ничего никуда сдвигать, само всё ложится.

Вот смотрите:

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

typedef union {
	unsigned long ulValue;
	unsigned char ucValue[sizeof(ulValue)];
} ULongByBytes;

void setup() {
	Serial.begin(115200);
	ULongByBytes val;
	val.ucValue[0] = 0;
	val.ucValue[1] = 1;
	val.ucValue[2] = 0;
	val.ucValue[3] = 0;
	Serial << "Long Value = " << val.ulValue << '\n';
}

void loop () {}

Здесь мы присваиваем значения байтам, а потом печатаем получившийся unsigned long. Никаких сдвигов и вообще никаких дополнительных действий.

rene пишет:

И по поводу приведения char в long, разве так можно? Мы же так код символа получим вместо самого числа?

При преобразованиях вида (<тип>)<переменная> на самом деле НИЧЕГО не преобразовывается и ничего не меняется. Просто впредь компилятор считает это новым типом. А реально в памяти остаётся ровно то, что было до этого - ничего не меняется никак.

rene пишет:

Код ptrVar |= (long)a[i] << (i*8); я не совсем понимаю, это получается мы сдвигаем биты элемента массива a[i], а потом проводим логическую операцию ИЛИ этого сдвинутого элемента и переменной ptrVar?

1. заводим long и в младший байт помещаем значение a[i] (более грамотно здесь делать не long, а unsigned long)
2. этот long сдвигаем влево на i*8 битов
3. Переменной 
ptrVar присваиваем результат операции ИЛИ между её старым значением и нашим long, получившимся после сдвига.

 

rene
Offline
Зарегистрирован: 21.01.2014

Спасибо за помощь!