Побитовые операторы и преобразование int в 2 байта и обратно

Мой опыт работы с php, поэтому вход в мир низкоуровневых вещей, таких как char - это байты, которые являются битами, которые являются двоичными значениями и т. Д., Требует некоторого времени, чтобы освоиться.

То, что я пытаюсь сделать здесь, - это отправка некоторых значений с платы Ardunio в openFrameWorks (оба являются c ++).

Что этот скрипт в настоящее время делает (и хорошо работает с одним датчиком, который я мог бы добавить), когда его спрашивают об отправке данных, это:

int value_01 = analogRead(0);  // which outputs between 0-1024

 unsigned char val1;
 unsigned char val2;

//some Complicated bitshift operation           
    val1 = value_01 &0xFF;
    val2 = (value_01 >> 8) &0xFF;  
    
    //send both bytes
    Serial.print(val1, BYTE);
    Serial.print(val2, BYTE);

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

int num = ( (unsigned char)bytesReadString[1] << 8 | (unsigned char)bytesReadString[0] );

Итак, напомним, я пытаюсь получить данные с 4 датчиков (которые, как я предполагаю, будут 8 из этих серийных отпечатков?) И иметь int num_01 - num_04 ... в конце всего этого.

Я предполагаю, что это (как и большинство вещей) может быть довольно легко для человека, имеющего опыт в этих концепциях.


person aKiwi    schedule 13.06.2010    source источник
comment
Из вашего вопроса не совсем понятно, с чем у вас проблемы ... Если приведенный выше код работает, вы можете, как вы говорите, выполнить больше операций Serial.print и получить свои значения из других индексов в bytesReadString на другом конце. Что не работает?   -  person tgdavies    schedule 13.06.2010


Ответы (4)


Напишите функцию для абстрактной отправки данных (я избавился от ваших временных переменных, потому что они не добавляют большого значения):

void send16(int value)
{
    //send both bytes
    Serial.print(value & 0xFF, BYTE);
    Serial.print((value >> 8) & 0xFF, BYTE);
}

Теперь вы можете легко отправлять любые данные, которые захотите:

send16(analogRead(0));
send16(analogRead(1));
...
person R Samuel Klatchko    schedule 13.06.2010
comment
Вау, это неплохо убирает ... Теперь все работает отлично, спасибо, ребята! По сравнению с тем, что у меня было раньше (когда он не работал), я действительно не уверен, почему он не работал (я думаю, что мог отправлять плохие данные, которые меня обманывали) .. Если это результат использования stackoverflow, плохо назад! - person aKiwi; 13.06.2010
comment
@aKiwi: лучший способ поблагодарить автора ответа, который соответствует вашим потребностям, - это отметить ответ как принятый :) - person Aoi Karasu; 13.06.2010
comment
ну интересно, что делать. спасибо, пытался проголосовать за него (видимо, нужна репутация;) - person aKiwi; 14.06.2010

Просто отправьте их по очереди.

Обратите внимание, что драйвер последовательного порта позволяет отправлять по одному байту (8 бит) за раз. Значение от 0 до 1023 включительно (что похоже на то, что вы получаете) умещается в 10 битах. Так что 1 байта недостаточно. 2 байта, то есть 16 бит, достаточно (есть дополнительное пространство, но если скорость передачи не является проблемой, вам не нужно беспокоиться об этом потраченном впустую пространстве).

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

Я предлагаю вам использовать функцию, которую Р. Самуэль Клатчко предложил на отправляющей стороне, и, надеюсь, вы сможете решить, что вам нужно делать на принимающей стороне.

person Artelius    schedule 13.06.2010
comment
Большое спасибо за информацию о серийной стороне вещей, проясняет кое-что в моей голове. Спасибо - person aKiwi; 13.06.2010

   int num = ( (unsigned char)bytesReadString[1] << 8 | 
               (unsigned char)bytesReadString[0] );

Этот код не будет делать то, что вы ожидаете.

Когда вы сдвигаете 8-битный беззнаковый символ, вы теряете лишние биты.

11111111 << 3 == 11111000

11111111 << 8 == 00000000

т.е. любой беззнаковый символ при сдвиге на 8 бит должен быть равен нулю.

Вам нужно что-то вроде этого:

typedef unsigned uint;
typedef unsigned char uchar;

uint num = (static_cast<uint>(static_cast<uchar>(bytesReadString[1])) << 8 ) |
           static_cast<uint>(static_cast<uchar>(bytesReadString[0]));

Вы можете получить такой же результат:

typedef unsigned short ushort;
uint num = *reinterpret_cast<ushort *>(bytesReadString);

Если порядок байтов в порядке. Должен работать на Little Endian (x86 или x64), но не на Big Endian (PPC, Sparc, Alpha и т. Д.)

person Michael J    schedule 13.06.2010

Чтобы немного обобщить код «Отправить» -

void SendBuff(const void *pBuff, size_t nBytes)
{
    const char *p = reinterpret_cast<const char *>(pBuff);
    for (size_t i=0; i<nBytes; i++)
        Serial.print(p[i], BYTE);
}

template <typename T>
void Send(const T &t)
{
    SendBuff(&t, sizeof(T));
}
person Michael J    schedule 13.06.2010