String to binary

I am working on a binary keyboard that uses 8 buttons, one button for each bit in the ASCII code. I've set it up to where it reads the button states and turns that into a string of 8 0's and 1's. The problem I am having is converting that string into it's ASCII code and printing to Serial.
For example something like this:

stringOne = "01000001";  // for A

//convert stringOne somehow

Serial.write(B01000001); // prints A to serial

Here is my full code if that helps any. It's not done yet, still working on the conversion issue, but any suggestions for how to optimize my code or any other ideas is also appreciated.

// left hand
const int buttonPin1 = 2; // the number of the button and its pin assignment
const int buttonPin2 = 3;
const int buttonPin3 = 4;
const int buttonPin4 = 5;

// right hand
const int buttonPin5 = 6;
const int buttonPin6 = 7;
const int buttonPin7 = 8;
const int buttonPin8 = 9;


int buttonState1 = 0; 
int buttonState2 = 0;
int buttonState3 = 0;
int buttonState4 = 0;
int buttonState5 = 0;
int buttonState6 = 0;
int buttonState7 = 0;
int buttonState8 = 0;

String stringOne;

void setup()
{
    Serial.begin(9600); // Start a serial connection at 9600 baud
    
    // Sets the pins 2-10 as INPUT
    pinMode(buttonPin1, INPUT);  // button 1
    pinMode(buttonPin2, INPUT);  // button 2
    pinMode(buttonPin3, INPUT);  // button 3
    pinMode(buttonPin4, INPUT);  // button 4
    pinMode(buttonPin5, INPUT);  // button 5
    pinMode(buttonPin6, INPUT);  // button 6
    pinMode(buttonPin7, INPUT);  // button 7
    pinMode(buttonPin8, INPUT);  // button 8
}

void loop()
{
   //Read the state of the buttons
   buttonState1  = digitalRead(buttonPin1);
   buttonState2  = digitalRead(buttonPin2);
   buttonState3  = digitalRead(buttonPin3);
   buttonState4  = digitalRead(buttonPin4);
   buttonState5  = digitalRead(buttonPin5);
   buttonState6  = digitalRead(buttonPin6);
   buttonState7  = digitalRead(buttonPin7);
   buttonState8  = digitalRead(buttonPin8);
   
   
   //Turn button states into a binary string
   stringOne = "";                    //resets the string on each loop
   
   stringOne.concat(buttonState1);    //concats each binary value of the buttons
   stringOne.concat(buttonState2);
   stringOne.concat(buttonState3);
   stringOne.concat(buttonState4);
   stringOne.concat(buttonState5);
   stringOne.concat(buttonState6);
   stringOne.concat(buttonState7);
   stringOne.concat(buttonState8);
   
   
   Serial.write();                    //Send the ASCII character to serial
}

Serial.print(stringOne, BIN);

Guess I overlooked the "//convert stringOne somehow" (emphasis mine) part.

Thanks for the quick response.
I've tried that before, it gives me a "no matching function for call to 'HardwareSerial::print(String&,int)' error.

as there are only 8 buttons, I would do this:

int buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9};
char pinValues[9];
char buttonName;

void setup(){

...
    for (int i = 0; i<8; i++) {
        pinMode(buttonPins[i], INPUT);
    }
...
}

void loop() {

    for (int i = 0; i<8; i++) {
        pinValues[i] = digitalRead(buttonPins[i]);
    }
    pinValues[8] = '\0';

    Serial.print("Binary: ");
    Serial.println(pinValues);
    
    buttonName = (char)atoi(pinValues);
    Serial.print("Key: ");
    Serial.println(buttonName);
}

I would also add a check to only output values when something changes - have left that for you as an exercise :wink:

Thanks aarondc. Your code is definitely a lot cleaner and more efficient. I learned quite a bit looking at your code, only it doesn't work. It compiles and uploads fine but does not print the binary or the characters. It will print an ASCII block thing after the binary only if I hold down the first button. Two blocks if I hold down the first two, three for the first three, etc. Nothing for any combination.
It looks like this for buttons 1-3.

Binary:[][][]
Key:

Hope this helps. I'll continue to look into it.

   Serial.print(stringOne);                    //Send the ASCII character to serial

I was going to post this but wanted to use atoi.

You may need to add a "0b" to the start of the char buffer? And make it bigger to accomodate.

The other way is like this:

void loop() {
    int asciiValue;
...
    asciiValue = 0;
    for (int i = 0; i<8; i++) {
        pinValues[i] = digitalRead(buttonPins[i]);
        asciiValue = asciiValue + (pinValues[i] >> i);
    }
}

Been a long time since I did bitshifting, so direction and types will be all kinds of messed up. But hopefully the general idea is there.

The below is based on the IDE example code to see various outputs.

// zoomkat 5-28-13 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial test 0021"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(2);  //delay to allow byte to arrive in input buffer
    byte c = Serial.read();
    //char c = Serial.read();
   // print it out in many formats:
   //Serial.println(c);       // print as an ASCII-encoded decimal
   Serial.println(c, DEC);  // print as an ASCII-encoded decimal
   Serial.println(c, HEX);  // print as an ASCII-encoded hexadecimal
   Serial.println(c, OCT);  // print as an ASCII-encoded octal
   Serial.println(c, BIN);  // print as an ASCII-encoded binary
   Serial.println();

    readString += c;
  }

  if (readString.length() >0) {
    Serial.println("Decimal values of bytes sent");
    Serial.println(readString);
    Serial.println("Done!");
    Serial.println();
    readString="";
  } 
}

Hmm, i tried implementing your code Aarondc and asciiValue seems to only return a 0 or a 1.
Also, I am not sure what you mean about the "0b". Perhaps if you could post a more complete code. Still pretty new to the Arduino and probably in over my head.

Thanks for the post Zoomkat. Not quite what I'm looking for but it may be helpful in the future.

Sometimes (ok, always) it pays to KISS and do baby steps first. Don't try to finish the project. Do the first, smallest piece possible, and then slowly increase the complexity. Get rid of all your pins and reads and everything. Pretend you already have the data, and see if you can output it.

I see a lot of people with little coding experience jumping into the deep end with their projects, trying to finish it in one go. I've been programming a long time and never do that - ever. I always get the basic in/out working, then the processing.

Try this - and don't add anything (ie pin reading) until you get it working.

char ca[] = {'0','1','0','0','0','0','1','1'}
char ca2[] = {' ', ' ', '0','1','0','0','0','0','1','1'}
int i;

void setup() {

Serial.being(9600);

Serial.println(ca);
ca2[0] = '0';
ca2[1] = 'b';
Serial.println(ca2);

i = atoi(ca);
Serial.println((char)i);

i = atoi(ca2);
Serial.println((char)i);
}

void loop{}

Here is one way:

// untested code

void loop()
{
  byte asciiCode;

   //Read the state of the buttons
   buttonState1  = digitalRead(buttonPin1);
   buttonState2  = digitalRead(buttonPin2);
   buttonState3  = digitalRead(buttonPin3);
   buttonState4  = digitalRead(buttonPin4);
   buttonState5  = digitalRead(buttonPin5);
   buttonState6  = digitalRead(buttonPin6);
   buttonState7  = digitalRead(buttonPin7);
   buttonState8  = digitalRead(buttonPin8);

    asciiCode = buttonState1 + (buttonState2 << 1) + (buttonState3 << 2)
     + (buttonState4 << 3) + (buttonState5 << 4) + (buttonState6 << 5)
     + (buttonState7 << 6) + (buttonState8 << 7);

   Serial.write(asciiCode);                    //Send the ASCII character to serial
}

TanHadron:
Here is one way:

// untested code

void loop()
{
 byte asciiCode;

//Read the state of the buttons
  buttonState1  = digitalRead(buttonPin1);
  buttonState2  = digitalRead(buttonPin2);
  buttonState3  = digitalRead(buttonPin3);
  buttonState4  = digitalRead(buttonPin4);
  buttonState5  = digitalRead(buttonPin5);
  buttonState6  = digitalRead(buttonPin6);
  buttonState7  = digitalRead(buttonPin7);
  buttonState8  = digitalRead(buttonPin8);

asciiCode = buttonState1 + (buttonState2 << 1) + (buttonState3 << 2)
    + (buttonState4 << 3) + (buttonState5 << 4) + (buttonState6 << 5)
    + (buttonState7 << 6) + (buttonState8 << 7);

Serial.write(asciiCode);                    //Send the ASCII character to serial
}

Looks like I did I get my >> and << wrong...

Your code can be rewritten as I wrote above:

  for (int i = 0; i<8; i++) {
        pinValues[i] = digitalRead(buttonPins[i]);
        asciiValue = asciiValue + (pinValues[i] << i);
    }

OR

  for (int i = 0; i<8; i++) {
        asciiValue |= (digitalRead(buttonPins[i]) << i);
}

Or...

void loop()
{
  byte asciiCode;

  asciiCode = (PIND >> 2) | ((PINB & 3) << 6);
  Serial.write(asciiCode);
}

You chose the button pins nicely for doing PINx reading. You could have done it with just PIND if you could have used pins 0-7 instead of 2-9. But that would interfere with Rx and Tx.

Actually, it occurs to me that I did all those bits backwards. You might have to change all the shifted values to be the other way around.

Anyway, is that what you're looking for, or did you really want to convert the String to binary?

  byte asciiCode = 0;

  for (byte i = 0; i < 8; ++i)
    asciiCode = asciiCode * 2 + stringOne.charAt(i) - '0';

@rajahsmokehouse

Sorry for jumping in a bit late, but I think it would be easier to write the binary number by accessing the bits directly of an input buffer bit. No bit shifting needed.

I'd offer something like this: (note, I'm typing this in on my Transformer so it is untested and uncompiled and may have syntax errors and/or typos)

// Single byte input buffer
byte inputByte;

// Array of bytes for keyboard pin numbers
byte inputBits[] {2, 3, 4, 5, 6, 7, 8, 9}; // May need to reverse the order of these if the byte is backwards...

void setup()
{
  Serial.begin(115200); // Change to your favorite baudrate
  for (byte i = 0; i < 8; i++)
  {
    pinMode(inputBits[i], INPUT);
  }
}

void loop()
{
  keyboardInput();
  Serial.print(F("Keyboard input is: 0b")); // Habit I've started putting diagnostic print strings within the F() macro to not waste precious SRAM on diagnostics...
  Serial.println(inputByte,BIN); // let println do the hard work of converting the byte into binary notation ASCII
  delay(100);  // delay for this example so not to spam the SerialMonitor...
}

// Here is the magic. See http://arduino.cc/en/Reference/BitWrite for documentation on bitWrite()
void keyboardInput()
{
  // No need to initialize the inputByte variable to anything because the following loop will positively write something to each and every bit.
  for (int i = 0; i < 8; i++)
  {
    bitWrite(inputByte, i, digitalRead(inputBits[i])); // taking a bit of a shortcut here, hopefully the return of digitalRead() will work here
  }
}

Hope this helps.

Thanks for all of the recent replies.
So far I have had the most luck with TanHadron's code:

// untested code

void loop()
{
  byte asciiCode;

//Read the state of the buttons
  buttonState1  = digitalRead(buttonPin1);
  buttonState2  = digitalRead(buttonPin2);
  buttonState3  = digitalRead(buttonPin3);
  buttonState4  = digitalRead(buttonPin4);
  buttonState5  = digitalRead(buttonPin5);
  buttonState6  = digitalRead(buttonPin6);
  buttonState7  = digitalRead(buttonPin7);
  buttonState8  = digitalRead(buttonPin8);

asciiCode = buttonState1 + (buttonState2 << 1) + (buttonState3 << 2)
    + (buttonState4 << 3) + (buttonState5 << 4) + (buttonState6 << 5)
    + (buttonState7 << 6) + (buttonState8 << 7);

Serial.write(asciiCode);                    //Send the ASCII character to serial
}

It outputs an ASCII character to the serial although it appears it is out of order. For example it gives the character " ' " for the relative buttons of "01100110" which ideally should be "l". Is it a bit shifting issue?

I'm looking into the other code posted as I can. Getting late.

rajahsmokehouse:
Thanks for all of the recent replies.
So far I have had the most luck with TanHadron's code:

// untested code

void loop()
{
  byte asciiCode;

//Read the state of the buttons
   buttonState1  = digitalRead(buttonPin1);
   buttonState2  = digitalRead(buttonPin2);
   buttonState3  = digitalRead(buttonPin3);
   buttonState4  = digitalRead(buttonPin4);
   buttonState5  = digitalRead(buttonPin5);
   buttonState6  = digitalRead(buttonPin6);
   buttonState7  = digitalRead(buttonPin7);
   buttonState8  = digitalRead(buttonPin8);

asciiCode = buttonState1 + (buttonState2 << 1) + (buttonState3 << 2)
     + (buttonState4 << 3) + (buttonState5 << 4) + (buttonState6 << 5)
     + (buttonState7 << 6) + (buttonState8 << 7);

Serial.write(asciiCode);                    //Send the ASCII character to serial
}

It outputs an ASCII character to the serial although it appears it is out of order. For example it gives the character " ' " for the relative buttons of "01100110" which ideally should be "l". Is it a bit shifting issue?

I'm looking into the other code posted as I can. Getting late.

Yeah, getting late here too. But I'm not sure if this would actually work. AFAIK, digitalRead() returns a boolean value which the compiler handles as a byte. The boolean value FALSE I'm pretty sure is stored as 0b00000000, but I'm not sure how the boolean value TRUE is stored. Is it simply 1 (0b00000001), or is it 255 (as an unsigned char, which is 0b11111111, or -1 as a signed char). The above code would work if TRUE is stored as value 1, but would break for any other non-zero value being stored (all non-zero values evaluate to TRUE).

Also, if my mind isn't falling asleep on me, isn't 0b01100110 equivalent to 0x66? If so, according to an ASCII table I looked up, that should evaluate to the ASCII character 'f'.

Yeah. Like I said I got them turned around. Try this.

    asciiCode = (buttonState1 << 7) + (buttonState2 << 6) + (buttonState3 << 5)
     + (buttonState4 << 4) + (buttonState5 << 3) + (buttonState6 << 2)
     + (buttonState7 <<1) + buttonState8;

TanHadron:
Yeah. Like I said I got them turned around. Try this.

    asciiCode = (buttonState1 << 7) + (buttonState2 << 6) + (buttonState3 << 5)

+ (buttonState4 << 4) + (buttonState5 << 3) + (buttonState6 << 2)
     + (buttonState7 <<1) + buttonState8;

How would 0b01100110 expose this type of error? It's a palindrome, so bit order isn't important. I'm not sure what the expected character (not binary number) is supposed to be a lower-case L (l), or a vertical bar (|) because of the display font. So, let's look at the reverse of both:

  • Lower-case L on the ASCII table is 0x6C, or 0b01101100. The bit reverse (or whatever the correct term is) would be 0b00110110 or 0x36 which is the ASCII character '6'. Not what he got...
  • Vertical bar on the ASCII table is 0x7C, or 0b01111100. The bit reverse would be 0b00111110 or 0x3E which is the ASCII character '>'. Again, not what he got...

So none of the three cases would a simple bit reversal give an apostrophe (which is 0x27 or 0b00100111). The apostrophe's bit reversal would be 0b11100100 or 0xE4, which should be the Greek letter sigma on the extended ASCII chart (the symbol commonly used for arithmetic sums).

Something else must be wrong here...

Thanks TanHadron. That finally did it....Mostly. I can get some characters to output correctly. I think it may be a problem with my protoboard after all of that button mashing last night. Going to check the connections and see if that helps any. At least now I see the answer to my original problem.