Преобразование типов String HEX в INT

dbf-334
Offline
Зарегистрирован: 13.11.2015

Всем привет!

Стоит такая задача... Имеется строка типа String, которая содержит в себе шестнадцатиричное число.

String str="C2";

или

String str="0xC2";

Как теперь можно преобразовать это значение в тип INT или BYTE, есть какое нибудь простое решение? Конвертации вида: str.toInt(); и тому подобные, ни к чему не приводят. Как правило появляется ошибка о несовместимости типов, либо результатом является НОЛЬ. Т.к. буквы не конвертируются напрямую в числа. )))

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

int i = atoi("0xC2");

dbf-334
Offline
Зарегистрирован: 13.11.2015

Andy пишет:

int i = atoi("0xC2");

Спасибо Andy! :) Только конструкция вида:

String str="0xC2";
int i = atoi(str);

не работает.. :( В качестве аргумента функция atoi понимает только тип char. Как перевести тогда String в char?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

int i = atoi(str.c_str());

 

dbf-334
Offline
Зарегистрирован: 13.11.2015

Andy пишет:

int i = atoi(str.c_str());

Эммм... так получаются нули в результате. :(

str.c_str() конвертирует вроде без ошибок, на выходе 0xC2. Не работает само преобразование в int, на выходе всегда ноль.

dbf-334
Offline
Зарегистрирован: 13.11.2015
int i = atoi("0xC2");

Попробовал вывести в порт значение переменной i, на выходе получил ноль. Почему-то сама функция не работает. :(

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

попробуй так

 int i;
 char s[]={"0xС2"};
 sscanf(s, "%x", &i);

 

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

Блин, вчера число на биты раздирали в массив. В школе задание дали, чтоли?

dbf-334
Offline
Зарегистрирован: 13.11.2015

>Andy

Прогресс есть, теперь выводит единицу вместо нуля. ))))

>Евгений

Нет, в школе давно уже не учусь... :) Мне нужно строку формата (dd:c2:be:ef:fe:ed) записать в память мк. Т.е. проверить каждый из шести разрядов адреса на соответствие диапазону значений 00-FF, потом преобразовать это значение в байт и сохранить. Проблема стоит с преобразованием в десятичное число. С обратным преобразованием проблем нет никаких, делается так:

Serial.println( String(EEPROM.read(32), HEX) );

В ячейке памяти хранится один из разрядов в десятичном виде  (тип byte). При выводе ф-я String преобразуеи значение в 16-ричный формат, все работает. Обратно сделать не получается... моск плачет уже. )))

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

dbf-334, а попробуйте использовать EEPROM.get и EEPROM.put с их помощью можно записывать и int и char во встроенной библиотеке eeprom

dbf-334
Offline
Зарегистрирован: 13.11.2015

Valera19701 пишет:

dbf-334, а попробуйте использовать EEPROM.get и EEPROM.put с их помощью можно записывать и int и char во встроенной библиотеке eeprom

Дело в том, что прежде чем записать значение в ячейку памяти, его сначала нужно проверить. Т.е. если пользователь указал значение "0xGR", а оно ну ни как не укладывается в диапазон 00-FF, оно вообще ошибочно. В память я могу его тупо записать, даже без ошибок и оно будет там спокойно лежать. Только это получится смысловая ошибка, что не допустимо! Указанные вами ф-ции работают напрямую с памятью, минуя всякие проверки. С их помощью можно вообще все что угодно записать и считать, даже структуры данных определенные самим разработчиком, только это все не то... :(

Мне нужно преобразовать 16-ричное число в байт. Проверить, что это число байта лежит в диапазоне 0-255 и записать этот готовый байт уже в ячейку памяти. Тупо не могу просто преобразовать HEX->DEC.

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

dbf-334 пишет:

С обратным преобразованием проблем нет никаких, делается так:

Serial.println( String(EEPROM.read(32), HEX) );

Понятно, Вы извращенец, которому некуда девать память :)))) Ну, если так, тогда прямая задача тоже тривиально решается. Почти как писал Andy, только чуток он ошибся. Вот работающий скетч, можете прямо отсюда скопировать и запустить - всё работет:

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }


void setup() {
	Serial.begin(115200);
	char * s = "0xfc";
	int n;
	sscanf(s, "0x%x", &n);
	Serial << "n = " << n << "\n";
}

void loop() {
}

Кстати, только не понял, а нафмга Вы в первом посте писали, что надо чтобы число с 0х начиналось, а теперб пишете, что формат:  (dd:c2:be:ef:fe:ed)? 

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015
Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

ЕвгенийП пишет:

Кстати, только не понял, а нафмга Вы в первом посте писали, что надо чтобы число с 0х начиналось, а теперб пишете, что формат:  (dd:c2:be:ef:fe:ed)? 

похоже на мас адрес сетевой карты:)

dbf-334
Offline
Зарегистрирован: 13.11.2015

Я в итоге так решил проблему, может понадобится кому:

String str = "0xC2";
int i = strtol(str.c_str(),NULL,0);
Serial.println(i);

Чем-то похоже на решение Евгения, только ф-я другая. ;) Кстати, если в начале числа не ставить префикс "0x", то ф-я возвращает ноль, т.е. перестает работать. Обязательно нужен префикс, как идентификатор 16-ричного числа.

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

Valera19701 пишет:

похоже на мас адрес сетевой карты:)

И что?  Это повод сначала присобачивать к нему 0х а птом геройски с ним бороться? :)

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

dbf-334 пишет:

Я в итоге так решил проблему, может понадобится кому:

String str = "0xC2";
int i = strtol(str.c_str(),NULL,0);
Serial.println(i);

Не, ну точно " Вы извращенец, которому некуда девать память" :))))

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

ЕвгенийП пишет:

Valera19701 пишет:

похоже на мас адрес сетевой карты:)

И что?  Это повод сначала присобачивать к нему 0х а птом геройски с ним бороться? :)

ну не я же присобачил :)

dbf-334
Offline
Зарегистрирован: 13.11.2015

ЕвгенийП пишет:

Понятно, Вы извращенец, которому некуда девать память :))))

Совсем только немного... зато так интереснее. ))))))

 

dbf-334
Offline
Зарегистрирован: 13.11.2015

Всем спасибо! :)

sav liana
Offline
Зарегистрирован: 28.11.2016

И все таки не понял... как преобразовать строку, например, "1B" в десятичное целое число 27?

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

sav liana пишет:

И все таки не понял... как преобразовать строку, например, "1B" в десятичное целое число 27?

Есть over9000 способов. Перечитайте тему, там же готовые куски кода.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

sav liana пишет:

И все таки не понял... как преобразовать строку, например, "1B" в десятичное целое число 27?

Самое главное - понять, что компьютер НЕ РАБОТАЕТ с десятичными числами. Сразу после осознания этого факта будет понятно и остальное.

sav liana
Offline
Зарегистрирован: 28.11.2016

Короче, было два затыка: 1.Надо было преобразовать Строку в массив; 2. Поставить +1 в MyStr.length()+1

Преобразуем 1D в десятичное число 29.

String bb = "41 05 1D ";
String MyStr = "-";
char myStr[10];
int x;

void setup() {
  Serial.begin(9600);
}

void loop() {  
  MyStr = bb.substring(6,8);
  MyStr.toCharArray(myStr, MyStr.length()+1);
  sscanf( myStr , "%x" , &x); 
  Serial.println(x); 
  delay(1000);    
}

 

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

sav liana,

молодец, что разобрались, но не останавливайтесь. То, как Вы сделали - самоубийственно по памяти. Вы использовали сразу два убийцы памяти - класс String и sscanf. Обе эти возможности откушивают "мам не горюй". Т.е. String и sscanf - просто огромные пушки для такой воробьиной задачи.

Задачу можно решить намного более дешёвыми средствами. Покопайтесь в сторону того, что 

1. Если из любого из символов символа '0' - '9' вычесть символ '0', то получится соответсвующее число. Например,

char c0 = '0', c1='5';
int n = c0 - '0';   // n стало равным 0
n = c1 - '0';        // n - стало равным 5

2. Точно также, если  из любого из символов символа 'A' - 'F' вычесть ('A' - 10), то получится соответсвующее число. Например:

char c0 = 'A', c1='E';
int n = c0 - ('A'-10);   // n стало равным 10
n = c1 - ('A'-10);        // n - стало равным 14

Теперь остаётся только организовать поразрядный цикл.

Ппоробуйте сделать такое преобразование без String и без sscanf, поковыряйтесь, если совсем не получится, я Вам помогу.

sav liana
Offline
Зарегистрирован: 28.11.2016
// преобразование части строки HEX в число Int
String MyStr = "41 05 EF34 ";
char myStr[12] = "-- -- ---- ";

void setup() {
  Serial.begin(9600);
}
// начиная с символа n, м символов
unsigned int HexToInt ( char buf[], byte n, byte m) {
  unsigned int y = 0;
  for (int i=0; i<m; i++)
  {
  if (buf[n+i]-'0' >16) { y = y + ((buf[n+i]-'0' - 7) << 4*(m-1-i)) ;}   
  if (buf[n+i]-'0' <16) { y = y + ((buf[n+i]-'0') << 4*(m-1-i));}
  }  
  return y;
}

// преобразовать 0xEF34 в unsigned int 61236
void loop() {  
  unsigned int x = 0;
  MyStr.toCharArray(myStr, MyStr.length()+1);
  x = HexToInt ( myStr, 6, 4 );  
  Serial.println(x);
  delay(1000);  
}

 

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

Ну, я бы упростил. Сейчас я на работе и под рукой нет ардуины. Могу написать на простом С с printf, если Вам всё равно, а если не всё равно, то завтра на ардуине сделаю. Как?

sav liana
Offline
Зарегистрирован: 28.11.2016

Конечно, важно!!! (и думаю, для многих...)

tolikaka
Offline
Зарегистрирован: 23.05.2013

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

Немного апну тему.Задача примерно того же плана.

С порта принимаю любое число, не более 6ти разрядов, к примеру 123456. Далее мне нужно:

1)разместить цифры разрядов в следующем порядке 34  56  12,

2) превратить эти пары в 0х34   0х56  0х12 , 

3) сделать инверсию каждой hex пары и отправить на печать в монитор порта

4) отправить то же самое в EEPROM

с 1,3 и 4(процесс отправки) пунктами проблем нет, а вот с пунктом 2 и 4(формат данных) пока ничего не получается 

Вариант unsigned char var= (((char chislo[3] -'0') <<4)+char chislo[4] -'0'))   

                           Serial.print(var, HEX) - выдает в порт все что угодно, только не 0х34. 

Подтолкните плиз, в нужную сторону. Такое чуйство, что где то что-то по выводу в порт мне все карты перемешивает

 

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

Не понял, что "123456" - это три двузначных 16-ричных числа и Вам надо их разделить? А приходят они как строка? Ну так выдерните их sscanf'ом и не забивайте себе мозг.

tolikaka
Offline
Зарегистрирован: 23.05.2013

нет, это любые десятичные с плюсом до 6ти знаков, от 0 до 999999 т.е. уже  long , с вводом из монитора порта

- разбил на разряды, значения разрядов спаровал символами в порядке указанном выше, теперь нужно эти пары из string превратить в hex  потом сделать инверсию и отправить в монитор порта, а так же записать в eeprom

 

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

Не понял Вы ше Вы писали, что они уже шестнадцатиричные их не надо пересчитывать.

Впрочем. дело Ваше, по любому выдергивайте sscanf'ом и не парьтесь. Добавляйте в начало нули и спокойно по две цифры выдёргивайте.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

tolikaka пишет:

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

Немного апну тему.Задача примерно того же плана.

С порта принимаю любое число, не более 6ти разрядов, к примеру 123456. Далее мне нужно:

1)разместить цифры разрядов в следующем порядке 34  56  12,

2) превратить эти пары в 0х34   0х56  0х12 , 

3) сделать инверсию каждой hex пары и отправить на печать в монитор порта

4) отправить то же самое в EEPROM

с 1,3 и 4(процесс отправки) пунктами проблем нет, а вот с пунктом 2 и 4(формат данных) пока ничего не получается 

Вариант unsigned char var= (((char chislo[3] -'0') <<4)+char chislo[4] -'0'))   

                           Serial.print(var, HEX) - выдает в порт все что угодно, только не 0х34. 

Подтолкните плиз, в нужную сторону. Такое чуйство, что где то что-то по выводу в порт мне все карты перемешивает

 

Поправьте индексы 3 и 4 на 2 и 3 соответственно - в С интексация массивов с 0.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Здравствуйте. Искал похожие темы, но не нашел, поэтому обратился сюда.

Есть LCD дисплей. Понадобилось выводить целые числа типа byte по нажатию кнопки, выбирая их из массива. Но столкнулся с проблемой, вначале 1, 10, 50, 100 выводит корректно, но после вывода 100  на дисплее остаются знакоместа(лишние нули). То есть кликая далее вместо 1 выводится 100, 10 - 100, 50 - 500.  

Разбирался здесь http://mypractic.ru/urok-30-tekstovye-stroki-v-arduino-konvertirovanie-dannyx-v-stroki-i-naoborot-klass-string.html#4

Но не помогло преобразование данных в строку, может не там искал

// объявил переменные
byte long_clicks_up = 0;
byte long_clicks_down = 0;
byte mass_string[4] = { 100, 1, 10, 50};  // порядок зависит от логики кода
...
//////////////////////////
// setup
...
//////////////////////////
//  loop
// счетчик кнопки
if(long_clicks_down<3) long_clicks_down++; //увеличивает счетчик кнопки на 1
else long_clicks_down = 0; //если счетчик достиг предела положений то его надо обнулить.
...
// объявил функцию
DoLong(long_clicks_down, 0);
//////////////////////////////////////
void DoLong(int button, boolean doState){ // делать при длином нажатии
if (doState) { lcd.setCursor(2, 0); lcd.print(mass_string[button]); }
else { lcd.setCursor(5, 0); lcd.print(mass_string[button]); }
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Да что ж вы в дебри сразу... напечатайте еще один пробел лишний после числа и всё.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Знаете, где то похожее видел

Это если не ошибаюсь?

// задаем переменную
byte val

...
if (val < 10)  lcd.print(" ");
else if (val < 100)  lcd.print("  ");

 

b707
Offline
Зарегистрирован: 26.05.2017

BuonanotteMasha пишет:

Знаете, где то похожее видел

Это если не ошибаюсь?

А подумать? Какое число короче - 2 или 22?

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Да вы правы, спасибо. Вопрос закрыт

// задаем переменную
byte val

...
if (val < 10)  lcd.print("  ");
else if (val < 100)  lcd.print(" ");