0

My char array is "00000f01" and I want it to be like byte out[4]={0x00,0x00,0x0f,0x01}; I tried the code sent by @ChrisA and thanks to him the Serial.println( b,HEX ); shows exactly what I need but 1st I can not access this output array because when I try to print "out" array it seems empty I also tried this code:

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() {
}   

but it is not working neither. please help me.

4
  • 1
    Indentation. Descriptive variable names. These things help you (any competent, experienced coder wants them, so novices should want them even more), but they are essential if you want others to help you with your code. Anyway, converting hex digit to number seems to be missing, your lambda does not do any conversion... Commented Sep 26, 2019 at 9:59
  • 2
    Your getnumfunction is the culprit. In Ascii, the "value" of the character '0' is decimal 48, not 0. The value of 'f' is 64+6=70, not 15. Your getnum needs to fix this. Commented Sep 26, 2019 at 10:03
  • so can you please help me on this? Commented Sep 26, 2019 at 10:11
  • Why not just use std::sscanf with a conversion of "%2uux%2uux%2uux%2uux"? Is there something we're missing? Commented Sep 26, 2019 at 12:42

2 Answers 2

2

The title of your question leads me to believe there's something missing in either your understanding of char arrays or the way you've asked the question. Often people have difficulty understanding the difference between a hexadecimal character or digit, and the representation of a byte in memory. A quick explanation:

Internally, all memory is just binary. You can choose to represent (ie. display it) it in bits, ASCII, decimal or hexadecimal, but it doesn't change what is stored in memory. On the other hand, since memory is just binary, characters always require a character encoding. That can be unicode or other more exotic encodings, but typically it's just ASCII. So if you want a string of characters, whether they spell out a hexadecimal number or a sentence or random letters, they must be encoded in ASCII.

Now the body of the question can easily be addressed:

AFAIK, there's no way to "capture" the output of Serial.println( b,HEX ) pragmatically, so you need to find another way to do your conversion from hex characters. The getNum() lambda provides the perfect opportunity. At the moment it does nothing, but if you adjust it so the character '0' turns into the number 0, and the character 'f' turns in to the number 15, and so on, you'll be well on your way.

Here's a quick and dirty way to do that:

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() {
}

All I've done is to modify getNum so it returns 0 for '0' and 15 for 'f', and so on in between. It does so by subtracting the value of the character '0' from the characters '0' through '9', or subtracting the value of the character 'a' from the characters 'a' through 'f'. Fortunately, the value of the characters '0' through '9' go up by one at a time, as do the characters from 'a' to 'f'. Note this will fall over if you input 'F' or something, but it'll do for the example you show.

When I run the above code on a Uno, I get this output:

0
00
1
00
2
0F
3
01

which seems to be what you want.

Epilogue

To demonstrate how print functions in C++ can lead you astray as to the actual value of thing you're printing, consider the cout version:

If I compile and run the following code in 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++;
    }
}

I get this output:

00000f01 

appearing to show that the conversion from hex characters has occurred. But this is only because cout ignores std::hex and treats b as a char to be printed in ASCII. Because the string "00000f01" has '0' as the first char in each pair, which happens to have a hex value (0x30) with zero lower nybble value, the (getNum( *idx++ ) << 4) happens to do nothing. So b will contain the original second char in each pair, which when printed in ASCII looks like a hex string.

Sign up to request clarification or add additional context in comments.

4 Comments

this is true the code might work but it just prints the number i need this byte array to be sent using serial port.
i want the line arer[co]=b; to store the byte b in arer arrey number co but after the loop executed i have nothing in arer arrey
arer is fine. It has the same contents as out. You could use for(byte b : arer){ Serial.println( b,HEX ); } loop to print out the contents and see for yourself. Your commented line which contains arer[4] will not work because there is no 4th index in a length 4 array.
Oooh, I see, it's a fluke - I was silly and expected <<std::hex<<b to print an integer in hex. It doesn't - it ignores the std::hex bit and just prints a char as ASCII. It just so happens that all the first characters in the hex byte pair are 0 which happens to have a zero value lower nybble. So (getNum( *idx++ ) << 4) happens to give 0. If I change it to std::hex << (unsigned int)b I see that no magic conversion is going on.
0

I'm not sure what you mean by "... with out changing to ASCII or any thing else" so maybe I'm misunderstanding your question.

Anyway, below is some simple code to convert the hex-string to an array of unsigned.

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;
  }
}

Output:

192
43
15
1

If you change the printing to

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

the output will be:

0xc0
0x2b
0xf
0x1

5 Comments

i want the data in byte array for your input to be :0xc0,0x2b,0x0f,0x01 not their ASCII code!
@HamedPourgholy That makes no sense... you can't store it like that in an integer array. It's really just a matter of how you print it
here is what i want i have an rfid module that i want to store 00000f01 in its block and this module just receives byte array as its input so i have to store this string as byte array as 0x00,0x00,0x0f,0x01 and send it using serial port. in arduino
thanks for your code but what is the byte array that i can use it in this code? sorry im a beginner in programming
@HamedPourgholy Seems that you are misunderstanding what the byte array is. It is just a sequence of numbers. For instance one number could be 15 (decimal) which is the same as 0x0f (hexadecimal) and the same as 17 (octal) and the same as 00001111 (binary). How you display the value has nothing to do with the way it's stored inside the computer. Your serial device expects a number - it doesn't expect something like "0x0f".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.