Странное поведение при побитовой операции

Я пытаюсь написать простую программу, которая записывает выходные данные акселерометра (который сводится к 3 аналоговым входам) на SD-карту.

У меня все заработало нормально (значения отправляются как простые строки), однако я хотел увеличить частоту сбора данных и поэтому попытался отправить данные на SD-карту в двоичном виде, и поэтому я выполняю некоторые побитовые манипуляции.

К сожалению, происходят (как мне кажется) странные вещи. Когда я добавляю простую битовую манипуляцию, данные на SD-карте становятся довольно запутанными. (Мне не удалось обнаружить закономерность, но, похоже, некоторые байты отсутствуют или присутствуют дважды без какой-либо закономерности):

Вот пример рабочей версии:

// Получить необработанные данные акселерометра для каждой оси
unsigned int rawX = analogRead(A0);
unsigned int rawY = analogRead(A1);
unsigned int rawZ = analogRead(A2);

byte b1 = (byte) (rawX>>2);  
byte b2 = (byte) (rawY>>4);
b2 = b2 + (byte) (rawX<<6);
byte b3 = (byte) (rawZ>>6);
b3 = b3 + (byte) (rawY<<4);
byte b4 = (byte) (rawZ);
b4 = (byte)b4*4;
//b4 = (байт)b4<<2;

// получить давление
//temp = BMP180_getTemp();
//плавающий a = 0;
//float a = pressure.altitude(BMP180_getPressure(), baseline);

unsigned long t = millis();

byte writeB[] ={
    b1, 
    b2, 
    (byte) (rawZ>>6), //замена этого на '(byte) ((rawZ>>6)|(0b11110000 & rawY))' вызовет ошибку
//также замена на b3 приводит к ошибке
    b4, 
    (byte) (t>>16), 
    (byte) (t>>8), 
    (byte)t, (byte)0};


dataFile.write(writeB,8);

dataFile.flush();

Как уже упоминалось в комментарии к коду, изменение способа вычисления байтов портит данные на SD-карте. Я пробовал несколько других вариантов, но, похоже, ошибку вызывают следующие операции: | & << >> (хотя я использую некоторые из них для вычисления, например, b2)

Чего я не понимаю, так это как изменение способа расчета байта влияет на выходные данные.

Возможно, я проглядел какую-то простую ошибку, но не могу понять, в чём дело. Буду очень благодарен за любую помощь, так как я работаю над этим уже довольно давно.

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

, 👍1


1 ответ


Лучший ответ:

1

Ваш способ распределения битов между тремя значениями выглядит немного запутанным. Ваш код сохранения битов корректен в том смысле, что вы сохраняете всю необходимую информацию. Байты распределяются следующим образом (H означает старшую часть значения, L — младшую часть значения):

     ____HX_____
b1: | 0000 0000 |
     _LX_ ___HY___
b2: | 00 | 000000 |
     __HZ__ __LY__
b3: | 0000 | 0000 |
     __LZ____
b4: | 000000 | XX |

Это довольно сложный способ разделения пространства. Кроме того, поскольку вы не используете оставшиеся 2 бита b4, вам не нужно выполнять сдвиг.

Когда вы получаете искажённые значения с SD-карты, это сильно зависит от того, как вы считываете байты (вы не показали нам код для этого). В качестве предложения я объясню, как бы я это сделал.


У нас есть 3 значения из analogRead(), каждое из которых содержит 10 бит. Таким образом, всего у нас 30 бит, которые можно передать 4 байтами (или 32 битами). При сложении битов другого значения, думаю, можно использовать оператор + (вопреки моему комментарию), если биты разных значений не перекрываются (что в любом случае должно быть). Лично я предпочитаю использовать побитовый оператор или |, чтобы нагляднее показать, что происходит, и упростить проверку на ошибки выравнивания (которые легко увидеть в двоичном представлении). Делайте, как вам удобно. Я пока буду использовать оператор |.

// Получить необработанные данные акселерометра для каждой оси
unsigned int rawX = analogRead(A0);
unsigned int rawY = analogRead(A1);
unsigned int rawZ = analogRead(A2);

byte b1 = rawX & 0xFF;
byte b2 = rawY & 0xFF;
byte b3 = rawZ & 0xFF;
byte b4 = (rawX & 0x0300) >> 2
          | (rawY & 0x0300) >> 4
          | (rawZ & 0x0300) >> 6;

Нижняя часть значений сохраняется в байтах b1b3. Старшие два бита каждого значения сохраняются с выравниванием по левому краю в байте b4 (& 0x0300 изолирует старшую часть, биты 9 и 10, в значениях).

Вы можете прочитать эти значения следующим образом:

rawX = b1 | (( b4 & 0b11000000) << 2);
rawY = b2 | (( b4 & 0b00110000) << 4);
rawZ = b3 | (( b4 & 0b00001100) << 6);

b1b3 – это начало для наших извлеченных исходных значений. Затем мы добавляем к исходным значениям оставшиеся 2 бита. Для этого сначала изолируем биты из b4 от позиций, которые мы использовали в верхнем коде. Затем мы сдвигаем их влево, пока они не окажутся непосредственно над 8 битами начальных значений.

,