Конвертирование HEX в BIN

llaabbss
Offline
Зарегистрирован: 28.12.2017

Здравствуйте,

Заранее прошу прощения, если ответы на мои вопросы покажутся очевидными, но помощь мне не помешает ))

У меня есть входящие данные в виде наборов шестнадцатиричных данных. 

Мне нужно разобрать входящие данные на части, преобразовать каждую из этих частей в бинарную форму и дальнейшие манипуляции выполнять уже с битами.

Например, есть такое входящее значение: 8D4840D620.

char receivedChars[] = "8D4840D620"; //char array, поскольку данные приходят из серийного порта

8D4840D620 мне нужно разделить на отдельные части (размер этих частей известен заранее условиями задачи, поэтому длину этих частей угадывать не надо):

8D     4840D6     20

Это я делаю так:

char dc_char[3]; // два реальных байта + 1 завершающий \0
dc_char[0] = receivedChars[0]; // сюда должно попасть 8
dc_char[1] = receivedChars[1]; // сюда должно попасть D
dc_char[2] = "\0";  // сюда должно попасть \0
Теперь с первой частью мне нужно поступить так:

1) превратить ее в бинарную форму, чтобы получилось 10001101;

2) из полученной бинарной формы (10001101) взять первые 5 бит (10001) и превратить их в десятичную форму (должно получиться 17).

Но вот тут начинаются какие-то неясности. 

Когда я пробую вывести в последовательный порт содержимое массива, то получаю вот что:

Serial.println("dc_char: ");
Serial.println(dc_char[0], BIN); // -> 111000 (хотя 8 должна была превратиться в 1000)
Serial.println(dc_char[1], BIN); // -> 1000100 (хотя D должна была превратиться в 1101)
Serial.println(dc_char[2], BIN); // -> 110 (\0 должен был превратиться в 0000)

Ну то есть я не получаю из кусков бинарной формы нужного мне выражения. Как все это правильно сделать? Понимаю, что вопросы задаю от полного невежества, но все же...

​Заранее благодарю за ответы.

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

судя по коду, у тебя

receivedChars[0] = "8D4840D620";

должно быть

 

receivedChars[0] = "8";
receivedChars[1] = "D";
receivedChars[2] = "4";
...

https://www.arduino.cc/en/Reference.StringToCharArray

llaabbss
Offline
Зарегистрирован: 28.12.2017

Нет, тут все нормально:

Serial.println("receivedChars[0]: " + String(receivedChars[0])); // -> 8
Serial.println("receivedChars[1]: " + String(receivedChars[1])); // -> D

 

NickSan
NickSan аватар
Offline
Зарегистрирован: 28.12.2017

Тогда покажи функцию конвертации

llaabbss
Offline
Зарегистрирован: 28.12.2017

Так никакой конвертации и нет, я просто распихиваю исходное значение по массивам, а потом с нужными элементами пытаюсь сделать вывод в серийный порт командой

Serial.println(dc_char[i], BIN);

Я даже проверил и в массив назначения попадают верные значения:

dcChar[0] -> 8
dcChar[1] -> D
dcChar[2] ->  

Но вот с самим преобразованием в бинарную форму 

Serial.println(dc_char[i], BIN);

что-то не то. И не пойму что. Результаты вот такие:

dcChar[0] -> 8 -> 111000 // а должно быть 1000
dcChar[1] -> D -> 1000100 // а должно быть 1101
dcChar[2] ->   -> 110

 

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

llaabbss пишет:

Serial.println(dc_char[0], BIN); // -> 111000 (хотя 8 должна была превратиться в 1000)

Кому это она так задолжала?

там был символ '8' - код его 0x38 или в десятичном 56. В двоичном это бутет как раз 111000 - именно то, что Вы и видите. Всё правильно работает.

Если Вы хотите, чтобы там именно числа сидели, так при присваивании нужно было вычитать '0' для цифр и и вычитать ('A'-10) для букв.

llaabbss
Offline
Зарегистрирован: 28.12.2017

ЕвгенийП,

Для самоконтроля я пользуюсь таким конвертером: https://www.binaryhexconverter.com/hex-to-binary-converter

И именно там я вижу другие значения, не 111000, а 1000 для восьмерки в HEX.

И именно 1000 мне нужна для '8' и 1101 для 'D'.

Покажи, пожалуйста, как делать вычитание '0' для цифр и ('A'-10) для букв.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015
  char one_part[] = "8D";
  char two_part[] = "4840D6";
  char three_part[] = "20";
  char * pEnd;
  unsigned int one_part_int = strtol(one_part, &pEnd, 16);
  unsigned long two_part_long = strtol(two_part, &pEnd, 16);
  unsigned int three_part_int = strtol(three_part, &pEnd, 16);
  Serial.println(one_part_int, BIN);
  Serial.println(two_part_long, BIN);
  Serial.println(three_part_int, BIN);
  one_part_int >>= 3;
  Serial.println(one_part_int, DEC);

 

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

llaabbss пишет:

Покажи, пожалуйста, как делать вычитание '0' для цифр и ('A'-10) для букв.

Мы уже на ты?

Вот у Вас написано

dc_char[0] = receivedChars[0]; // сюда должно попасть 8

Так вот туда ни хрена не 8 попадает, а '8'. Чтобы туда попадала именно 8, надо писать

dc_char[0] = receivedChars[0] - '0'; // сюда должно попасть 8

Вот тогда там будет 8.

Если же в receivedChars[0] сидит не знак цифры, а знак от 'A" до 'F', то вычитать надо не '0', как я написал, а ('A' - 10). Тогда в случае A там окажется 10, в случае B - там окажется 11 и т.п.

Т.е. строку dc_char[0] = receivedChars[0] - '0'; надо переписать так, чтобы "если в  receivedChars[0] цифра - вычиталось '0', а если символ 'A'-'F', то чтобы вычиталось ('A'-10).

Но это уже сами. Для цифр я Вам написал, а на общий случй сами доработайте.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Penni,

Спасибо, теперь я вижу значения, которые мне нужны. Постараюсь понять ваш пример ))
Спасибо!

P.S. Понял, отличная универсальная функция!

llaabbss
Offline
Зарегистрирован: 28.12.2017

Цитата:

Мы уже на ты?

Простите, пожалуйста )) Оплошал я )))

dc_char[1] = receivedChars[1] - ('A'-10);

 

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

llaabbss пишет:

dc_char[1] = receivedChars[1] - ('A'-10);

Ну, нет, здесь Вы уже как бы знаете, что там буква. А откуда? Надо проверить что там и соотвественно себя вести.

Нужно что-то вроде

dc_char[1] = receivedChars[1] - ((receivedChars[1] > '9') ? ('A'-10) : '0');

Только здесь не проверяется, что в строке именн цифры и буквы от 'A' до 'F'. Считается, что так и есть.

 

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

llaabbss, а чем вообще вызвана надобность класть входящие данные в char?

llaabbss
Offline
Зарегистрирован: 28.12.2017

dimax

Такая необходимость возникла вследствие того, что данные поступают по серийному порту и для дальнейших преобразований в бинарную форму удобнее всего оказалось сделать через char.

Если есть идеи как сделать проще - буду благодарен ))

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

Конечно есть. Если она передаются в двоичном виде, то так и принимать. А если и передаются в текстовом, то переделать передачц и передавать в двоичном.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Друзья,

А вот еще вопрос: если у меня есть бинарное значение в виде 11101000, как мне "убрать" первые 4 бита?
Чтобы осталось только 1000? Что-то типа отрезать. Но в данном случае нужно обнулять.

Я так понимаю, что это сделать нужно при помощи bitClear(), bitWrite(). Или есть еще более красивое решение?

__Alexander
Offline
Зарегистрирован: 24.10.2012

x= 11101000 & 0x0F;

llaabbss
Offline
Зарегистрирован: 28.12.2017

__Alexander

Спасибо за идею, а если есть 12 бит, как поступить аналогичным образом с произвольным количеством первых бит?

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

llaabbss, может вы уже достаточно готовы что бы таки изучить битовые операции? :)  У меня в своё время ушло полдня. А пользы -на всю оставшуюся жизнь.

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

dimax пишет:

может вы уже достаточно готовы 

Боюсь, что нет. Ибо Вы должны подсказать. Иначе, зачем форум?

llaabbss
Offline
Зарегистрирован: 28.12.2017

Ребята, спасибо!
За ссылку вообще отдельное спасибо! Я пытался найти вменяемые статьи даже на английском. Уже полез в учебники по С.
Так что всех благодарю, обязательно все прочту.

Поздравляю всех с наступающими праздниками ))

P.S. Шикарная ссылка. Сразу нашел ответ на свой вопрос:

data0 & (~((1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11))); //Обнуляем 6 любых бита (в данном случае 6 подряд)

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
data0 & 0xFFC0 // видно это не кошерно смотрится

 

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

qwone пишет:

data0 & 0xFFC0 // видно это не кошерно смотрится

видимо, потому что это неправильно. Пух, читай внимательно!!!

llaabbss
Offline
Зарегистрирован: 28.12.2017

Ребята, нужна ваша помощь еще раз ))

Где я могу найти информацию какой длины HEX данных какая из Ардуин может конвертировать в бинарную форму?

Вопрос связан с тем, что когда у меня есть HEX данные, например, C382D690C8AC, то при попытке посмотреть его эквивалент в бинарной форме через серийный порт на УНО я получаю 1111111111111111111111111111111. Это безусловно неправильно. Мне пришлось делить исходный HEX на две части, чтобы правильно его обработать (в этом случае я вижу корректное отображение в строке последовательного порта).

Связано ли появление 1111111111111111111111111111111 с тем, что у Ардуино УНО просто нет мощностей для конвертации такой длины HEX данных, либо это ограничение последовательного порта (а в оперативке содержится верное значение  в бинарной форме)?

И справится ли с этой строкой ESP-07 лучше, чем Ардуино?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
Идет экзамен.
Профессор: На борту самолета 500 кирпичей. Один кирпич выпал из самолета. Сколько на борту осталось кирпичей?
Студент: Ну, это легко! 499!
Профессор: Правильно. Следующий вопрос. Как положить слона в холодильник за 3 шага? 
Студент: 1. Открыть холодильник, 2. Положить туда слона. 3. Закрыть холодильник! 
Профессор: Дальше. Как положить оленя в холодильник за четыре шага ?
Студент: 1. Открыть холодильник. 2. Вытащить слона. 3. Положить оленя. 4. Закрыть холодильник!
Профессор: Отлично! Следующий вопрос. У царя зверей льва, день рождения ! Пришли все животные, кроме одного. Почему?
Студент: Потому, что олень все еще в холодильнике!
Профессор: Великолепно ! Далее. Может ли бабуля пройти через болото с крокодилами? 
Студент: Конечно может! Ведь все крокодилы на дне рождения « левы» !
Профессор: Хорошо! А теперь последний вопрос. Бабуля прошла через пустое болото, но все равно умерла! Что с ней случилось? 
Студент: Э — э э! Она утонула? Профессор: А вот и нет! На нее упал кирпич, который выпал из самолета ! НА « ПЕРЕСДАЧУ»!

Это к вам llaabbss  У вас данные в виде char строки в которой HEX. Напишите функцию конвертацию из char строки в которой HEX в char строку в которой BIN. И не парьте форумчанам голову.

llaabbss
Offline
Зарегистрирован: 28.12.2017

То есть как бы все логично, но я где-то тупонул? :)

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

llaabbss пишет:

То есть как бы все логично, но я где-то тупонул? :)

А теперь вопрос на засыпку. Какие типы стандартные типы переменных используются в Ардуине и их размерность.

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

llaabbss пишет:

какой длины HEX данных какая из Ардуин может конвертировать в бинарную форму?

Практически любой

llaabbss пишет:

Связано ли появление 1111111111111111111111111111111 с тем, что у Ардуино УНО просто нет мощностей для конвертации такой длины HEX данных, 

Мощностей не хватает не у УНО, а у программиста.

llaabbss пишет:
И справится ли с этой строкой ESP-07 лучше, чем Ардуино?
Смотря с каким программистом. Если с тем же, то нет.

 

llaabbss
Offline
Зарегистрирован: 28.12.2017

Ну, да, да, 32 бита максимум для long, unsigned long и float. 

C382D690C8AC - это 48 бит. Поэтому приходится делить на части.

Отсюда и втрой вывод: ESP на ардуиновском IDE будет испытывать те же проблемы. Разве что использовать другое IDE, у которого возможностей больше.

Спасибо за то, что ткнули в очевидные ответы ))

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

llaabbss пишет:

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

Да, нет же. Надо использовать не другое IDE, а другого программиста.

Если уж Вам так жмёт long, почему не использовать long long? Или просто из строки в строку конвертировать.

В общем надо прокачивать программиста, а не IDE.

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

llaabbss пишет:
Отсюда и втрой вывод: ESP на ардуиновском IDE будет испытывать те же проблемы. Разве что использовать другое IDE, у которого возможностей больше.
А ведь чел даже не задумался о том, что в АВР нет сопроцессора который умеет считать float и long long. Да и регистров такой размерности у нее нет. Но ведь считает блин.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Это так что ли должно выглядеть?

long long i = strtol(data, &pEnd, 16);

 

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

llaabbss пишет:

Это так что ли должно выглядеть?

long long i = strtol(data, &pEnd, 16);

Конечно, нет. Посмотрите какого типа данные возвращает strtol и подумайте.

И это, ... читайте, учитесь, я же Вам говорю, Вам надо прокачать программиста, а не IDE!

И не гонитесь за готовой халявой! Я Вам в постах 5 и 8 показал как это сделать для строки ЛЮБОЙ длины (хоть двести символов). Но там работать надо, и Вы уцепились за халявную функцию strtol, которая делает всё за Вас, да вот беда - она ограничена типом long - халява не прошла.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
void hexToBin(char * destptr, const char * srcptr ) {
  /*здесь вы напишите свой код конвертирования*/
}

 

llaabbss
Offline
Зарегистрирован: 28.12.2017

Ну и последний вопрос (уж простите, но я  вас решил добить :) ).

У меня есть 20 битовое выражение числа типа unsigned int, которое я уже получил:

11001100010000010010

Мне нужно в нем заменить самые старшие биты с номерами 18 и 19.

Я стараюсь это выполнить так:

11001100010000010010 & (~((1<<18)|(1<<19)))

Но ничего не происходит. Так я могу менять биты только до 17 номера, а вот выше - нет.
Где мне хотя бы начать искать решение проблемы? И можно ли каким-то образом резать 32 битные числа по 16 (или по 8) бит, а потом склеивать их обратно без искажения цифры?

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

llaabbss пишет:

Где мне хотя бы начать искать решение проблемы?

В учебниках.

Заменитев Ваше выражении  обе единицы на 1ul, И больше, пока не прочтёте учебник - не обращайтесь.

llaabbss пишет:

И можно ли каким-то образом резать 32 битные числа по 16 (или по 8) бит, а потом склеивать их обратно без искажения цифры?

Можно всё. Если уметь.

llaabbss
Offline
Зарегистрирован: 28.12.2017

О, вы все просто БОГИ программирования!

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

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

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

Еще раз всех с наступающими праздниками и всех благ ))

5N62V
Offline
Зарегистрирован: 25.02.2016

llaabbss пишет:

 И можно ли каким-то образом резать 32 битные числа по 16 (или по 8) бит, а потом склеивать их обратно без искажения цифры?

Да без проблем! Берете 4х байтовую переменную, первые два байта записываете в первую 2х байтовую переменную, вторые два байта - во вторую.  А по 8бит  - так еще проще:

long aaa;

byte *ptr = (byte *)(& aaa);

первый байт  = * ptr;

второй байт = *(ptr +1);

третий байт = *(ptr +2);

четвертый байт = *(ptr +3);

и обратно:

long bbb;

bbb =( *(ptr+3)<<24) | ( *(ptr+2)<<16) | ( *(ptr+1)<<8) | *ptr;

тоже самое , что и bbb = aaa, только по-байтно

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

llaabbss пишет:

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

Какие знакомые отговорки :)

llaabbss пишет:

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

Какие знакомые обещания :)

llaabbss
Offline
Зарегистрирован: 28.12.2017

А это не знакомые слова? )))))))))))))))

llaabbss пишет:

О, вы все просто БОГИ программирования!

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

llaabbss пишет:

А это не знакомые слова? )))))))))))))))

llaabbss пишет:

О, вы все просто БОГИ программирования!

Богов тут нет, знаешь ли. Тут одни титаны :)))

llaabbss
Offline
Зарегистрирован: 28.12.2017

В общем, с Новым годом, боги / титаны / высший разум / другие персонажи всех верований, мифов и легенд )))))))))))))

OreSama
Offline
Зарегистрирован: 29.12.2017

5N62V пишет:

Да без проблем! Берете 4х байтовую переменную, первые два байта записываете в первую 2х байтовую переменную, вторые два байта - во вторую.  А по 8бит  - так еще проще:

long aaa;

byte *ptr = (byte *)(& aaa);

первый байт  = * ptr;

второй байт = *(ptr +1);

третий байт = *(ptr +2);

четвертый байт = *(ptr +3);

Можно ещё классичнее:

byte *ptr = (byte*)&long_number
byte1 = *ptr++;
byte2= *ptr++;
byte3 = *ptr++;
byte4 = *ptr;

или даже так:

byte1 = long_number >> 24;
byte2 = long_number >> 16;
byte3 = long_number >> 8;
byte4 = long_number;

 

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

OreSama пишет:

или даже так:

byte1 = long_number >> 24;
byte2 = long_number >> 16;
byte3 = long_number >> 8;
byte4 = long_number;

Вы уже начали отмечать? Какой часовой пояс?