Go Down

Topic: Encoding from Binary Bits to Decimal / Hex (Read 825 times) previous topic - next topic

lasithg

Hi There,
I have data read (via DigitalRead) from 17, 9 PhotoTransistors which are used to calculate a coordinate position. At the moment I directly send the streams (Such as "01111110110000011", "111111000") as a stream of characters via Serial.Print(). however, since I wish to speed up the process, for better performance, I'm thinking on whether to encode the bitstream as a Decimal or Hexacimal number, and send that number as a set of several characters.

In this case, the 9 bit sensor value will vary from 0-512 in decimal and the 17 bit sensor value will vary from 0-131072. However, i cant seem to find a function to convert this. 
In the foll wing reference,
http://arduino.cc/en/Serial/Print

I note that Serial.print(78, BIN) gives "1001110" but what I really need is a function to do the opposite.

Although I do not know whether performing such a conversion in the arduino will itself slow down the process, my intention is to ensure output at a higher data speed via COM.

Thanks in advance,
LasithG

Grumpy_Mike

Quote
I note that Serial.print(78, BIN) gives "1001110" but what I really need is a function to do the opposite.

Anything stored in a variable is already in binary, there is no need to convert it. You do the conversion when you do the print in any other number base.
So gather your bits into a variable and print it out in any form you want.

marco_c

If your intention is to minimise the use of your serial bandwidth, then the best way to send it is as a series of bytes whose bits are on or off as per the pattern.

You have 17+9 bits to send. If these are packet into 8 bit bytes, then you will have to send 26/8=3.25 or 4 bytes. If you are sending the string "010..." as per your example you will be sending 26 bytes.

Computers do not need to 'read' the data like we do, so converting to ASCII characters is very wasteful. What you are actually sending down the line is a byte representing the characters '0' (0x30) and the byte for '1' (0x31), which differ only by one bit, so you are wasting the information contained in the other 7 bits.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

lasithg

Thank you Marco_C and Grumpy_Mike for your suggestions.

Right now, This is how I code it,
..
delay(ReadDelay);
   SensorValue = digitalRead(SensorA); // read the arduino input pin
   Serial.print(SensorValue); //use the result
delay(OutDelay);

for all 26 Sensors.

But I'm thinking of adding them into a linear array (Char or Int) in this case marked ShortSide[ ]

   ShortSide[8] = digitalRead(ChipB); // read the arduino input
...
...
   ShortSide[7] = digitalRead(ChipC); // read the arduino input
...

And finally use Serial.Print(Shortside); to output the stream.

As suggested by Marco_C, what I want to do is to ..but I'm not sure which coding constructs / data types to use.
   


PaulS

Quote
But I'm thinking of adding them into a linear array (Char or Int) in this case marked ShortSide[ ]

Sending one value at a time, or sending an array of values, makes no difference on the amount of data being sent.

If you pack the data into a 4 byte array, using bitWrite(), and send just those 4 bytes, there WILL be a considerable reduction in the amount of data being sent.


Grumpy_Mike

Quote
for all 26 Sensors.

So you can fit it all into a long int
Code: [Select]

long int results;

// then gather the data into the variable
 results = 0;
for(int i =0; i< 26; i++){
results |= (digitalRead(pin[i]) & 0x01) << i;
}

where pin[] is an array defining what pins to use.

The all your results are in a single variable.

Then you can output it as a hex number:-
Code: [Select]
Serial.print(results, HEX);
it will contain up to 6 characters.
If you want it to be in only 4 characters, use:-
Code: [Select]

Serial.write(char(results & 0xff) );
Serial.write(char( (results>>8) & 0xff) );
Serial.write(char( (results>>16) & 0xff) );
Serial.write(char( (results>>24) & 0xff) );

lasithg

Thank you Grumpy Mike!. I think it looks like what I need...just a few queries on the code : I did some referencing on the bit shift operator etc...but just to be sure..

Code: [Select]
results |= (digitalRead(pin[i]) & 0x01) << i;

In this statement, why do you use an AND operator with the pin result and HEX 1 ?

Also in
Code: [Select]
Serial.write(char(results & 0xff) );

you perform a AND operation with Hex FF..

I'm a bit unclear on the reason behind it...

Many Thanks Once again!

majenko


Thank you Grumpy Mike!. I think it looks like what I need...just a few queries on the code : I did some referencing on the bit shift operator etc...but just to be sure..

Code: [Select]
results |= (digitalRead(pin[i]) & 0x01) << i;

In this statement, why do you use an AND operator with the pin result and HEX 1 ?


Belt and braces.  We want either 0x00 or 0x01 for shifting in.  digitalRead should only ever return 0 or 1, but just in case we force it in to the right value range.



Also in
Code: [Select]
Serial.write(char(results & 0xff) );

you perform a AND operation with Hex FF..

I'm a bit unclear on the reason behind it...

That returns just the lower 8 bits of the long value - returning one byte of data.  The next three Serial.print's return the next three bytes of data (shift right, and mask, 3 times).  For the first one you don't need to shift right as it's already in the right alignment.

lasithg

Thank you very much. Now its clear to me!

Go Up