Вытянуть из байта полубайт или сложить полубайты
- Войдите на сайт для отправки комментариев
Задача такая. Имеем сообщение допустим из 4 байт : 0x02 0x10 0xB3 0x3A
Опытным путем выяснил, что в него забита проверка контрольной суммы. Контрольной суммой является правый полубайт (как правильно младший?) последнего байта, т.е. полубайт "A"
этот "A" должен быть равен последнему правому полубайту (младшему) результата выражения: полубайт E минус сумма всех предыдущих полубайт, т.е. Е - (0+2+1+0+B+3+3)=E-14=FFFFFFFFFFFFFFFA, вот он младший полубайт "А" - совпадает.
Попробовал через bitRead и Write сделать, вроде получилось, но насколько это коряво? Научите, если это не сложно, попроще через битовые сдвиги и т.д. На примере быстрее пойму.
Вот как я сделал. Создадим массив - сообщение с ошибкой (ложной контрольной суммой). Младший полубайт последнего байта вместо "А" сделаем "0" byte Message[4] = {0x02, 0x10, 0xB3, 0x30};
потом подсчитаем CRC и переправим в массиве как должно быть.
byte Message[4] = {0x02, 0x10, 0xB3, 0x30}; byte A,B; byte CRC = 0; void setup() { Serial.begin (9600); // распечатаем сначала сообщение как было, с ошибкой for (int i=0; i<4; i++) {Serial.print (Message[i], HEX); Serial.print (" ");} Serial.println (""); // сосчитаем контрольную сумму полубайт первых трёх байт массива, //используя переменные А и B для промежуточных расчетов for (int n=0; n<3; n++){ for (int i=4; i<8; i++) bitWrite(A, i-4, bitRead(Message[n],i)) ; for (int i=0; i<4; i++) bitWrite(B, i, bitRead(Message[n],i)) ; CRC = CRC + A+B; } // сосчитаем и приплюсуем старший полубайт последнего четвертого байта массива for (int i=4; i<8; i++) bitWrite(A, i-4, bitRead(Message[3],i)) ; CRC = CRC + A; // сосчитаем контрольную сумму по правилу с вычитом из 0x0E, //используя переменную B для промежуточных расчетов B = 0x0E - CRC; // забьем в младший полубайт последнего байта массива правильную контрольную сумму for (int i=0; i<4; i++) bitWrite (Message[3], i, bitRead(B,i)); // распечатаем массив с правильной контрольной суммой for (int i=0; i<4; i++) {Serial.print (Message[i], HEX); Serial.print (" ");} Serial.println (""); } void loop() {}
Извлечь из байта (a) старший полубайт - (a & 0xF0)>>4
младший соответсвенно a & 0x0F
sadman41 - в первом случае сдвиг потеряли
Кстати. старший проще так: x>>4
А младший еще можно так: (x<<4)>>4
спасибо!
sadman41 - в первом случае сдвиг потеряли
Кстати. старший проще так: x>>4
А младший еще можно так: (x<<4)>>4
Откровенно говоря - я и не пытался ничего сдвинуть, просто намекнул на то, как нибблы выделить.
А вообще - с этими сдвигами осторожней нужно быть, а то забудешься или описку допустишь, двинешь знаковый тип, потом сидишь и башку чешешь:
Работает. А подскажите еще как записать извлеченный полубайт, в младший полубайт другого байта, не затронув биты его старшего полубайта? т.е. то что у меня эта строка делает
Так же, как и выделили - с помощью битовых операций: https://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B1%D0%B8%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%B8
На бумажке напишите числа столбиком в двоичной форме и подберите такие операции, при котором будут затрагиваться только нужные биты.
оператором "|"
вопрос, а сильно стремно делать через цикл фор? Есть ли негатив в том методе, который применил я? Т.е. в моём случае я понял, МК по одному биту всё выполняет. А при сдвигах - за раз все 4 бита. Через цикл for сильно медленнее будет? Если нет, то мне так гораздо понятнее программу писать.
Т.е. в моём случае я понял, МК по одному биту всё выполняет. А при сдвигах - за раз все 4 бита. Через цикл for сильно медленнее будет? Если нет, то мне так гораздо понятнее программу писать.
Думаю, что разница будет в сотни раз. В вашем случае мало того что биты по одному - так еще и через высокоуровневые функции библиотеки.
Другой вопрос - важна ли для вашего случая эта разница. В кухонном таймере разница между 10мкс и 1 мс незаметна, а при управлении боеголовкой - критична :)
в байте "B" подсчитана контрольная сумма. Вытягиваем из неё младший ниббл.
A = B & 0x0F;
и вот правильно ли я записываю ниббл "А" в младший ниббл Message[3] ?
Message[3] = Message[3]|A;
по результатам вроде работает. Всем спасибо. Вот итоговый скетч
думаю важна . Тут работа с CAN шиной и если медлить, то сообщения будут пропускаться и вообще там много чем ещё МК будет занят . Благодарю за оптимизацию.
проверил на устройстве эта строка видимо не работает
Message[3] = Message[3]|A;
в байте "B" подсчитана контрольная сумма. Вытягиваем из неё младший ниббл.
A = B & 0x0F;
и вот правильно ли я записываю ниббл "А" в младший ниббл Message[3] ?
Message[3] = Message[3]|A;
Я бы перед записью для уверенности почистил бы младший полубайт Message[3]:
Message[3] = (Message[3] & 0xF0) |A;
Это даже не для уверенности, а насущная необходимость...
MaksVV, Давайте рассмотрим две ситуации с одним нибблом. В каком случае результат операции OR не будет равен ожидаемому (перенос ниббла) ?
b707, красавчик ! с чисткой ниббла заработало! Круть.
Это даже не для уверенности, а насущная необходимость...
MaksVV, Давайте рассмотрим две ситуации с одним нибблом. В каком случае результат операции OR не будет равен ожидаемому (перенос ниббла) ?
да, именно так
Это даже не для уверенности, а насущная необходимость...
Я предполагал, что младшие разряды могут быть почищены заранее...
Респект друзья за ликбез