Read BCD and convert to int

Hi All,

I'm building an 8-bit computer and want to use an arduino for the display output. I have found a fantastic library for driving multiplexed 7 segment LED displays which is working well. My idea is to place the Arduino behind a bus transceiver, so when the output is enabled, the binary data from the 8 bit bus will go into the arduino, which will convert it to an int, then display it on the 7 segment LED displays.

I'm using an arduino nano for this. The LED display is already up and running with no issue, so ignore that for the time being. My issue is the conversion of the binary data to decimal.

Pins 2-9 are plugged in to the bus, which I am reading like so:

byte bcdInputPins {2, 3, 4, 5, 6, 7, 8, 9};

then I have a method to read the data:

int readInput(){
Serial.println("--------------");
String rawbinaryString;

for (int i = 0; i <= sizeof(bcdInputPins) -1; i++) {
rawbinaryString += String(digitalRead(bcdInputPins[i]));
}

//reverse string
Serial.println("Raw binary string = " + rawbinaryString);

char s[8];
rawbinaryString.toCharArray(s, 8);

int result = readBinaryString(s);
Serial.println("int result from string: " +String(result));

return 1;
}

this is giving me the following output, which is correct

Raw binary string = 00100000

I'm passing this result to a method I found on this forum, to convert it to an int:

int readBinaryString(char* s) {
int value = 0;
for (int i=0; i< strlen(s)+1; i++) // for every character in the string strlen(s) returns the length of a char array
{
value *= 2; // double the result so far
if (s[i] == '1') value++; //add 1 if needed
}
return value;
}

The problem here, is that method is returning 32. I know that is actually the correct value, but I need it to return 4. I know that it's the leading 0's that are causing the issue, as 4 in binary is 100.

Is there a smarter way to do this?

To clarify a bit further, my bus has to be a fixed width of 8, so on my bus I have the following convention:

0 = 00000000
1 = 10000000
2 = 01000000
3 = 11000000
4 = 00100000
5 = 10100000

and so on....

is there a tidier way of converting this to an int?

Hello
You may arrange an array to do the transformation.

It looks like your bit sequence is reversed. If you were to reverse the order of the pins in bcdInputPins, I think your code would work.

PS: normally binary is represented with the MSB first, so
1 = 00000001
2 = 00000010
etc

I don't think strlen(s)+1 is correct here,
the last value of i will be strlen(s), which is the index of the terminating zero character.

Try this:

int result = 0;
for (byte i = 0; i < sizeof(bcdInputPins); i++) {
  bitSet(result, i, digitalRead(bcdInputPins[i]));
}
Serial.print("int result from string: ");
Serial.println(result);

Another variant to get the result

byte bcdInputPins[] = { 2, 3, 4, 5, 6, 7, 8, 9 };

byte readValue() {
  byte result = 0;
  byte mask = 1;
  for (int i = 0; i < sizeof(bcdInputPins); i++, mask <<= 1) {
    if (digitalRead(bcdInputPins[i]) == HIGH) {
      result |= mask;
    }
  }
  return result;
}

This has really helped!! its so close to working now.

the only issue is it's ignoring the last byte, which I believe is a problem in the readBinaryString method.

this is how it is behaving now:
00000001 = 0
00000010 = 2
00000100 = 4

That is caused by the bad index, as I pointed out already.

Yeah, fully agree with you, I'm just experimenting with that now. I've tried:

for (int i=0; i< 8; i++)

but still no luck so far.

@OP
1. You are collecting binary bits from the DPins of the following array; where, DPin-2 is for the LSBit and DPin-9 is for the MSBit

byte bcdInputPins[ ] = {2, 3, 4, 5, 6, 7, 8, 9};

2. Assume that you have the following bit pattern at the DPins of Step-1.

byte inputBits = 0b01011000;  //b0, b1, ...b7 = 0, 1, 0, 1,1,0,0,0 ==> 00011010 = 26 decimal

3. Let us execute the following codes to extract 02 and 06 from the bits of Step-2.

byte myBits;
for(int i = 7, j = 0; i >= 0; i--, j++)
{
    bitWrite(myBits, i , digitalRead(bcdInputPins[j]));  //myBits = 00011010 = 26 decimal
}
byte d0 = myBits%10;  //d0 = 06
myBits = myBits/10;
//--------------------
byte d1 = myBits%10;   //d1 = 02
mBits = myBits/10;

4. If you are using SevSeg.h Library to drive multiplexed 7-segment Display Unit, then there is no need of doing such conversion from binray to BCD. The Library handles all the necessary conversions.

You may consult the post of this link: Driving 7-segmnet Display Unit using SevSeg.h Library

Thanks for all the help everyone! I finally have it working. Also thanks to all the super fast replies!

The solution was a combination @markd833 and @Whandall ideas.

Mark had pointed out that my binary was backwards. In my tired attempts on Friday night, I had tried just reversing the string, but that wasn't working. Mark's idea was just to reverse the order of the pins in the array, how I didn't think of this I don't know!

This got it reading all except the last byte, which @Whandall pointed out was because of a pointer error. To get it to read all of the bytes I changed:

rawbinaryString.toCharArray(s, 8)

to

rawbinaryString.toCharArray(s, 9)

for anyone interested, here is the full working code, I haven't tidied up the spacing or added comments yet, but this should help anyone in a similar situation:

#include "SevSeg.h"
SevSeg sevseg; //Instantiate a seven segment object

//byte bcdInputPins {2, 3, 4, 5, 6, 7, 8, 9};
byte bcdInputPins {9, 8, 7, 6, 5, 4, 3, 2};
void setup() {

Serial.begin(9600);

Serial.println("setting up pins and sevseg library");
Serial.println();

byte numDigits = 1;
byte digitPins = {A4, A5, 0, 1};
byte segmentPins = {A3, A2, A1, A0, 13, 12, 11, 10};
bool resistorsOnSegments = false; // 'false' means resistors are on digit pins
byte hardwareConfig = COMMON_CATHODE; // See README.md for options
bool updateWithDelays = false; // Default 'false' is Recommended
bool leadingZeros = false; // Use 'true' if you'd like to keep the leading zeros
bool disableDecPoint = false; // Use 'true' if your decimal point doesn't exist or isn't connected. Then, you only need to specify 7 segmentPins

for (int i = 0; i <= sizeof(bcdInputPins)-1; i++) {
pinMode(bcdInputPins[i], INPUT);
}

sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments,
updateWithDelays, leadingZeros, disableDecPoint);
//sevseg.setNumber(1234);

Serial.println("Starting main loop");
}

void loop() {
// put your main code here, to run repeatedly:
//sevseg.setNumber(readInput());
readInput();
sevseg.setNumber(2);
sevseg.refreshDisplay();
}

int readInput(){
Serial.println("--------------");
String rawbinaryString;

for (int i = 0; i <= sizeof(bcdInputPins) -1; i++) {
rawbinaryString += String(digitalRead(bcdInputPins[i]));
}

//reverse string
Serial.println("Raw binary string = " + rawbinaryString);

char s[8];
//reverseString(rawbinaryString).toCharArray(s, 8);
rawbinaryString.toCharArray(s, 9);

int result = readBinaryString(s);
Serial.println("int result from string: " +String(result));

return 1;
}

int readBinaryString(char* s) {
int value = 0;
for (int i=0; i< strlen(s); i++) // for every character in the string strlen(s) returns the length of a char array
{
value *= 2; // double the result so far
if (s[i] == '1') value++; //add 1 if needed
}
return value;
}