Сохранять массив символов HEX в байтовом массиве, не меняя его на ASCII или что-либо еще - PullRequest
0 голосов
/ 26 сентября 2019

Мой char массив равен "00000f01", и я хочу, чтобы он был похож на byte out[4]={0x00,0x00,0x0f,0x01}; Я попробовал код, отправленный @ChrisA, и благодаря ему Serial.println( b,HEX ); показывает именно то, что мне нужно, но 1-й я не могу получить к нему доступвыходной массив, потому что когда я пытаюсь вывести «out» массив, он кажется пустым, я также пробовал этот код:

void setup() {
    Serial.begin(9600);
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return c ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        Serial.println( co );
        Serial.println( b,HEX ); 
        arer[co]=b;
        co++; 
    }
    //    Serial.print(getNum,HEX); 
    //    Serial.print(out[4],HEX); 
    //    Serial.print(arer[4],HEX); 
    /*
    none of this codes commented above worked*/
}

void loop() {
}   

, но он тоже не работает.пожалуйста, помогите мне.

Ответы [ 2 ]

2 голосов
/ 26 сентября 2019

Название вашего вопроса наводит меня на мысль, что чего-то не хватает ни в вашем понимании массивов char, ни в том, как вы задали вопрос.Часто людям трудно понять разницу между шестнадцатеричным символом или цифрой и представлением байта в памяти.Краткое объяснение:

Внутренне вся память просто двоичная.Вы можете представить (то есть отобразить его) в битах, ASCII, десятичном или шестнадцатеричном формате, но это не изменит то, что хранится в памяти.С другой стороны, поскольку память просто двоичная, символы всегда требуют кодировки символов.Это может быть Unicode или другие более экзотические кодировки, но обычно это просто ASCII.Поэтому, если вам нужна строка символов, независимо от того, пишут ли они шестнадцатеричное число, или предложение, или случайные буквы, они должны быть закодированы в ASCII.

Теперь тело вопроса можно легко решить:

AFAIK, нет способа "захватить" вывод Serial.println( b,HEX ) прагматично, поэтому вам нужно найти другой способ сделать ваше преобразование из шестнадцатеричных символов.getNum() лямбда предоставляет прекрасную возможность.На данный момент он ничего не делает, но если вы настроите его так, чтобы персонаж '0' превратился в число 0, а персонаж 'f' превратился в число 15, и так далее, вы будете в порядке.на вашем пути.

Вот быстрый и грязный способ сделать это:

void setup() {
    Serial.begin(9600);
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return (c <= '9' ? c-'0' : c-'a'+10) ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        Serial.println( co );
        if(b < 0x10)
          Serial.print('0');
        Serial.println( b,HEX ); 
        arer[co]=b;
        co++; 
    }
}

void loop() {
}

Все, что я сделал, это изменил getNum, чтобы он возвращал 0 для '0'и 15 для 'f', и так далее между ними.Это происходит путем вычитания значения символа '0' из символов '0' до '9' или вычитания значения символа 'a' из символов 'a' до 'f'.К счастью, значения символов от '0' до '9' увеличиваются по одному за раз, как и символы от 'a' до 'f'.Обратите внимание, что это упадет, если вы введете 'F' или что-то еще, но оно подойдет для примера, который вы показываете.

Когда я запускаю приведенный выше код на Uno, я получаю такой вывод:

0
00
1
00
2
0F
3
01

, который, кажется, вам нужен.

Эпилог

Чтобы продемонстрировать, как функции печати в C ++ могут сбить вас с пути относительно действительной ценности вещивы печатаете, рассмотрим cout версию:

Если я скомпилирую и запусту следующий код на C ++ 14:

#include <iostream>
#include <iomanip>
#include <string>

typedef unsigned char byte;

int main()
{
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return c ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        std::cout << std::setfill('0') << std::setw(2) << std::hex << b;
        arer[co]=b;
        co++;
    }
}

Я получу такой вывод:

00000f01 

появляется, чтобы показать, что произошло преобразование из шестнадцатеричных символов.Но это только потому, что cout игнорирует std::hex и рассматривает b как символ, который будет напечатан в ASCII.Поскольку строка "00000f01" имеет '0' в качестве первого символа в каждой паре, которая имеет шестнадцатеричное значение (0x30) с нулевым нижним значением nybble, (getNum( *idx++ ) << 4) ничего не делает.Таким образом, b будет содержать оригинальный второй символ в каждой паре, который при печати в ASCII выглядит как шестнадцатеричная строка.

0 голосов
/ 26 сентября 2019

Я не уверен, что вы имеете в виду под "... без изменения ASCII или чего-то еще", поэтому, возможно, я неправильно понимаю ваш вопрос.

В любом случае, ниже приведен простой код для преобразованияшестнадцатеричная строка для массива без знака.

unsigned getVal(char c)
{
  assert(
      (c >= '0' && c <= '9') ||
      (c >= 'a' && c <= 'f') ||
      (c >= 'A' && c <= 'F'));

  if (c - '0' < 10) return c - '0';
  if (c - 'A' < 6) return 10 + c - 'A';
  return 10 + c - 'a';
}

int main()
{
  char arr[] = "c02B0f01";
  unsigned out[4];
  for (auto i = 0; i < 4; ++i)
  {
    out[i] = 16*getVal(arr[2*i]) + getVal(arr[2*i+1]);
  }

  for (auto o : out)
  {
    std::cout << o << std::endl;
  }
}

Вывод:

192
43
15
1

Если вы измените печать на

  for (auto o : out)
  {
    std::cout << "0x" << std::hex << o << std::dec << std::endl;
  }

, вы получите:

0xc0
0x2b
0xf
0x1
...