Convert a nibble to ASCII to byte

Hi!

I am trying to accomplish turning a nibble into it's ASCII character and then turn that character into a byte.

In the example below I turn the byte myByte (0x12) into to nibbles. One becomes 0x1 and the other 0x2. What I want to do then is to turn the nibbles into ASCII characters, 1 and 2, and then back to byte to send these over CAN. So ASCII 1 would be hex value 0x31 and ASCII 2 would be 0x32. It does not have to be hex. It could might aswell be decimal 49 and 50.

Is there a way of doing this? I have searched a lot and have not found what I'm looking for. It might be that I'm not really sure what to search for.

Regards,
Christian

byte myByte = {0x12};
byte myData[2];

void setup() {

  Serial.begin(115200);

  myData[0] = myByte >> 4;
  myData[1] = myByte & 0xf;

  Serial.println(myData[0]);
  Serial.println(myData[1]);


}

void loop() {
  // put your main code here, to run repeatedly:

}

Add 0x30...

You need to use itoa:

char buf[3]; //Two digits + null
itoa(myData[0], buf, 10); //Integer to ASCII, base 10 used
Serial.println(buf); //Prints "1"

westfw:
Add 0x30...

Nope, it can't be that easy. It has to be some sort of monster machine :smiley:
Thank you, for a very fast and super simple solution!

Adding 0x30 will not work for values above 9 :slight_smile:

myData[0] += (myData[0] < 10 ? '0' : 'A');

aahhh…
should be

myData[0] += (myData[0] < 10 ? '0' : ('A'-10));

:-[

Danois90:
Adding 0x30 will not work for values above 9 :slight_smile:

You’re right, but neither does your example seem to do. When making myByte 0xAB, it prints 10 instead of A.

Budvar10:

myData[0] += (myData[0] < 10 ? '0' : 'A');

Neither does this. This seems to have an offset of 10 when the value is over 9. I’d love for you to explain what the code does.

As commented in the code, base 10 was used. You need to change the last parameter of itoa from 10 to 16 in order to use base 16 (hexadecimal).

A method that CAN uses to communicate with 'dumb' peripherals is with BCD (binary coded decimal) in which every nibble represents a decimal number of 0 thru 9. This appears (heavy emphasis) to be what you're trying to accomplish.

As an example, the number 5555 is binary 0001 0101 1011 0011 and would be transmitted thus. BCD however, would represent 5555 as 0101 0101 0101 0101, stripping each digit into a nibble. CAN is actually an old protocol and the use of BCD was to accommodate 0-9 thumbwheel switches.

If all you want to do is break a byte into two nibbles,

union
{
    byte my_byte;
    struct
    {
        byte nibble1:4;
        byte nibble2:4;
    };
}my_union;

Then my_union.my_byte = your hex or decimal value, my_union.nibble1 are the four lsb and my_union.nibble2 are the four msb.

Please, let me understand.
What I understond is: you have a char array that contiens a ASCII message. You want take each element, devide it in the octal or exadecimal digits and print than.
IS IT LIKE THIS?
IF IT IS you can cast each element like a int and use the .print function, witch the right argument about base

DKWatson:
If all you want to do is break a byte into two nibbles,

union

{
   byte my_byte;
   struct
   {
       byte nibble1:4;
       byte nibble2:4;
   };
}my_union;



Then my_union.my_byte = your hex or decimal value, my_union.nibble1 are the four lsb and my_union.nibble2 are the four msb.

The breaking down into two nibbles is already sorted. What I want to to with the nibbles is to convert them into ASCII and then into bytes.
So let's say that one nibble is 0xF. I want to convert this to a byte that contains decimal 70.

Silente:
Please, let me understand.
What I understond is: you have a char array that contiens a ASCII message. You want take each element, devide it in the octal or exadecimal digits and print than.
IS IT LIKE THIS?
IF IT IS you can cast each element like a int and use the .print function, witch the right argument about base

No, you must have misunderstood everything, unless I accidentally added a char array in my example.

So let's say that one nibble is 0xF. I want to convert this to a byte that contains decimal 70.

If the nibble contains 15 (base 10), why would the byte contain 70 (base 10)?

Because 70 is the decimal value of ASCII F, or have I gotten this all wrong?

chrstrvs:
Because 70 is the decimal value of ASCII F, or have I gotten this all wrong?

No.

What IS the problem? If the value in the nibble is between 0 and 9, add '0'. If the value is between 10 and 15, subtract 10 and add 'A'.

Or add '7'

DKWatson:
Or add ‘7’

While the result may be the same, I think the two step process is more logical.

I have not understand a thing:
Why have you to transform a value in more than one that conteins exadecimal digits of the same value? The thing can be usefull only in case to show tje number or pass it. But I think that all the .print function has the ability of doing this change of base by thanselves. So why do you need it?

PaulS:
No.

What IS the problem? If the value in the nibble is between 0 and 9, add '0'. If the value is between 10 and 15, subtract 10 and add 'A'.

THAT was the problem. I didn't know how to accomplish the hex or decimal value corresponding to the ASCII characters of the nibbles. Now I do, and for that I thank all you very much!
I'm sorry that it might be somewhat unclear what I want to accomplish. I know my terminology is way off sometimes, but everything I know about Arduino programming is self taught. The only programming classes I have attended are HTML and PHP some 15 years ago.

chrstrvs:
In the example below I turn the byte myByte (0x12) into to nibbles. One becomes 0x1 and the other 0x2. What I want to do then is to turn the nibbles into ASCII characters, 1 and 2, and then back to byte to send these over CAN. So ASCII 1 would be hex value 0x31 and ASCII 2 would be 0x32. It does not have to be hex. It could might aswell be decimal 49 and 50.

Given :

byte myByte = 0x12;
==> myByte = 0001 0010
0001 (1) ---> 0011 0001 (x31 = 49) ASCII Code of the numeral 1

49 (0x31) ----> 0100 1001 (BCD Format)
//------------------------------

0002 (2) ---> 0011 0010 (0x32 = 50 ADCII Code of numeral 2
50 (0x32) ---> 0101 0000 (BCD Format)

The codes to achieve the above transformations:

byte asciiUpperNibble;
void setup() 
{
  Serial.begin(9600);
  byte myByte = 0x12; //0000 0001, 0000 0010 ; 0x31 (0x32) : 49 (50) : 0100 1001 (0101 0000)
  byte upperNibble = myByte >>4; //(0000)0001 : 1
  byte lowerNibble = myByte & 0x0F; //(0000)0010 : 2
  //--------------------------
  if(upperNibble >9)
  {
    asciiUpperNibble = upperNibble + 0x37; //0x41 - 0x46 (A-F): 65 - 70 : 0110 0101 - 0111 0000
  }
  else
  {
    asciiUpperNibble = upperNibble + 0x30; //0x30 - 0x39 (0-9): 48 - 57 : 0100 1000 - 0101 0111 
  }
  byte inDex0 = asciiUpperNibble % 10;  //(0000) 1001 : 9
  byte inDex1 = asciiUpperNibble / 10;  //(0000) 0100  : 4
  //---------------------
  byte bcdByte = (inDex1 <<4)|inDex0;    //0100 1001 
  Serial.println(bcdByte, HEX);     //shows: 49
  Serial.println(bcdByte, BIN);     //shows: (0)100 1001 ; leading 0 missing; but, it can be printed
  //------------------------------------------  
  /*---- code are similar to above for the lower nibble----
  *----------------------------
   *---------------------------*/
}
void loop() 
{

}