How to split a byte into nibbles ?

I've got a problem that I don't know how to solve.

Given an INT containing -76 DEC (-76 is a dB representation of 40 DEC from this calculation (31.5 - (0.5 * (255 - 40))) )

How do I end up with two HEX bytes:

byte name [11] = 0x37 (0x37 is ASCii 7)
byte name [12] = 0x36 (0x36 is ASCii 6)

I need to change the decimal value from -76 to +76 (or just unsigned), and then split the number into the upper and lower nibbles.

I can multiply -76 by -1 (-76 * -1) to change it to a positive number, but I don't know how to split the number.

I looked at highByte & lowByte, but 76 is a single byte and is completely contained in the lowByte.

I'm sure it's probably quite simple, but I'm struggling to figure it out.

Ian.

Bit shifting and masking

76 % 10 gives you six
76 / 10 gives you seven assuming the 76 is in an int

Look up what 76&15 would do, also (76&240)>>4
Or try it.

Sorry, just to clarify :blush:

-76 was an example. This value can be anywhere between -96 and +3dB (representing decimal values from 0 to 198).

-10 would require:

byte name [11] = 0x31 (0x31 is ASCii 1)
byte name [12] = 0x30 (0x30 is ASCii 0)

-9 would require:

byte name [11] = 0x30 (0x30 is ASCii 0)
byte name [12] = 0x39 (0x39 is ASCii 9)

+3 would require:

byte name [11] = 0x30 (0x30 is ASCii 0)
byte name [12] = 0x33 (0x33 is ASCii 3)

76 % 10 gives you six
76 / 10 gives you seven assuming the 76 is in an int

This works fine down to 11 :slight_smile:

ad2049q:
Look up what 76&15 would do, also (76&240)>>4
Or try it.

76&15 appears to give 12
(76&240)>>4 appears to give 4

ian332isport:

76 % 10 gives you six
76 / 10 gives you seven assuming the 76 is in an int

This works fine down to 11 :slight_smile:

Wrong. It works for all numbers between 0 and 99 inclusive.

ian332isport:

ad2049q:
Look up what 76&15 would do, also (76&240)>>4
Or try it.

76&15 appears to give 12
(76&240)>>4 appears to give 4

I think the person answering thought you meant base 16 (hex) and not base 10 (decimal). Actually, you asked about extracting nibbles, so this is the right answer.

ian332isport:
Sorry, just to clarify :blush:

-76 was an example. This value can be anywhere between -96 and +3dB (representing decimal values from 0 to 198).

So the term nibble was incorrect. 76 decimal has an upper nibble of 4 decimal and a lower nibble of 12 decimal, not 7 and 6 respectively like you stated.

-10 would require:

byte name [11] = 0x31 (0x31 is ASCii 1)
byte name [12] = 0x30 (0x30 is ASCii 0)

I think you're using the wrong terminology. You're not trying to extract nibbles, you're trying to convert a number into its ASCII representation.

This works fine down to 11 :slight_smile:

Works fine from 0 to 99.

ian332isport:

ad2049q:
Look up what 76&15 would do, also (76&240)>>4
Or try it.

76&15 appears to give 12
(76&240)>>4 appears to give 4

Which is the lower and upper nibbles of 76 decimal, like your original question asked for.

You've got a problem if your values are signed.
I'd first check the sign bit, then take the absolute value of the byte.

AWOL:
You've got a problem if your values are signed.
I'd first check the sign bit, then take the absolute value of the byte.

Yep, I can never remember if the C modulus rounds to zero or negative infinity. On a positive dividend it makes no difference but with a negative dividend they give different results. You also have to know if the sign of the result is the dividend's or the divisor's. Certain C standards do not specify which.

So, do as he says and take the "abs".

Arrch:

ian332isport:

ad2049q:
Look up what 76&15 would do, also (76&240)>>4
Or try it.

76&15 appears to give 12
(76&240)>>4 appears to give 4

Which is the lower and upper nibbles of 76 decimal, like your original question asked for.

Maybe I've got the terminology wrong.

From 76, I want to split it apart and have a 7 and a 6.

I want to send the number 76 (as an example) over a data bus. It sends each character as HEX bytes equivalent to ASCII characters. To send the 7 I need to send 0x37, and to send the 6 I need to send 0x36. I can't send 76 as one byte, as 76 gives 0x4C which is the letter L.

Ian.

ian332isport:
It sends each character as HEX bytes...

A hex byte? A byte is eight bits and hex is a number base. So, a hex byte is the same as a decimal byte which is the same as an octal byte which is the same as a sexagesimal byte which is the same as .....

I'm really confused to be honest. Are you not just sending bytes or maybe it's binary coded decimal where a number is two nibbles and each nibble is of course a hex digit.

Is the value 76 stored as binary or BCD?

ian332isport:
Maybe I've got the terminology wrong.

From 76, I want to split it apart and have a 7 and a 6.

I want to send the number 76 (as an example) over a data bus. It sends each character as HEX bytes equivalent to ASCII characters. To send the 7 I need to send 0x37, and to send the 6 I need to send 0x36. I can't send 76 as one byte, as 76 gives 0x4C which is the letter L.
Ian.

how about a simple array:

byte asciiDigit [10] = {0x30 , 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}
...
...
  Serial.print(asciiDigit[yourSingleDigitInt]);
...
...

76 is just the number 76 stored as an int. It's actually -76, but lets just forget the sign for now.

int a = 76

It's just the decimal number 76 that represents an audio volume level. It's not binary or BCD. It goes up and down with the volume level.

I'm trying to explain this as clearly as possible. I'm fairly new to this and I apologise if my terminology is a bit off.

This is what I need to send (via serial):

byte SEND_VOL_LEVEL [16] = {0xC8 , 0x0E , 0x80 , 0x23 , 0x42 , 0x32 , 0x56 , 0x6F , 0x6C , 0x20 , 0x00 , 0x00 , 0x64 , 0x42 , 0x00 };

You see the two bytes (represented as HEX) in red. I need to replace those bytes with 0x37 and 0x36 (assuming int a =76 - it varies with the volume level). I can't send the 76 in HEX (4C), as this represents the ASCII letter L. I need to send the 7 and the 6 as separate bytes in HEX.

I'm afraid I can't think of any other way to explain this.

Ian.

right, got it.

use the array I mentioned above to retrieve the ascii value of the digit(s) you want to send.

//declare your arrays:
byte asciiDigit [10] = {0x30 , 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
byte SEND_VOL_LEVEL [16] = {0xC8 , 0x0E , 0x80 , 0x23 , 0x42 , 0x32 , 0x56 , 0x6F , 0x6C , 0x20 , 0x00 , 0x00 , 0x64 , 0x42 , 0x00 };

//calculate your digits here as provided in above examples
int firstDigit = 7;
int secondDigit = 6;

//assign the array new values:
SEND_VOL_LEVEL[11] = asciiDigit[firstDigit]
SEND_VOL_LEVEL[12] = asciiDigit[secondDigit]

//do something with your array

You could just use a sledge hammer to crack a nut and do:

int value = -76;

char ascii[3];
byte data = abs(value);
sprintf("%02d",data);
Serial.print(ascii);

Edit:
Woops, missed the last two posts. Never mind.

In terms of converting to ascii digits, there is no point using a lookup table. Just do something like:

int vol = -76;
//----
vol = abs(vol);
byte tens = vol/10;
byte units = vol%10;
//assign the array new values:
SEND_VOL_LEVEL[11] = tens + '0'; //to convert decimal digits to ascii, just add '0' (0x30);
SEND_VOL_LEVEL[12] = units + '0';

karma++

That is superb. Thanks very much :slight_smile: