Trying to test a bit in a string that is a number

I would like to start off by giving all credit for any code or schematics to the original authors and if I don't quote the authors I deeply apologize, it is purely accidental.

I'm new to Arduino, but I've had courses in micro controllers specifically the pic16 and intro to C++ programming. I'm experienced in soldering and working with my hands.

I have a Arduino Uno R3 and I've gone through all the examples in 1. Basics. I'm trying to make a program that takes a int from 0 to 256 converts it to a binary string then outputs it to LED bar. The code I have converts and increments the number into binary which can be seen in serial output, but does not output to the LED bar.

int pin2 = 2;
int pin3 = 3;
int pin4 = 4;
int pin5 = 5;
int pin6 = 6;
int pin7 = 0;
int pin8 = 0;
int pinx = 0;
byte i=0;
String binary;

void setup()
{
Serial.begin(9600);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin7, OUTPUT);
}

void loop()
{
binary=dectobin(i);
Serial.println(binary);
delay(500);

for(int j=0; j<=7; j++)
{
if(binary[j]==1)
{
pinx=j;
digitalWrite(pinx, HIGH);
delay(1000);
}
else
{
pinx=j;
digitalWrite(pinx, LOW);
delay(1000);
}
}

++i;

}

String dectobin(int decNum )
{
String result;
int zeros = 8 - String(decNum,BIN).length();
String myStr;
for (int i=0; i<zeros; i++)
{
myStr = myStr + "0";
}
myStr = myStr + String(decNum,BIN);
return myStr;
}

So you have a String of something like "00011010", yes? In ASCII that would be an array of:

{ 48, 48, 48, 49, 49, 48, 49, 48 }

Then, over a period of 8 seconds (why have a 1 second delay INSIDE your for loop?!) you check each one to see if it is 1 or not. None of those are, or ever will be, 1.

The whole approach is completely wrong.

You do not need a string. You have a value - that value is made up internally of 1 and 0 bits. Just test those bits themselves. Also, store your pin numbers in an array - it's far simpler.

uint8_t pins[] = {0, 1, 2, 3, 4, 5, 6, 7}; 

for (int i = 0; i < 8; i++) {
  if (val & (1<<i)) {
    digitalWrite(pins[i], HIGH);
  } else {
    digitalWrite(pins[i], LOW);
  }
}

Or, exploiting the fact that anything other than 0 is ON for an IO pin:

for (int i = 0; i < 8; i++) {
  digitalWrite(pins[i], val & (1<<i));
}

Also tempting though the String class is for string manipulation it can lead to
memory exhaustion. With only 2k of RAM this often catches people out.

Strings of characters declared as char arrays are usually a safer bet even if
you do need to program more low-level operations.

For representing bits as an array a boolean array would be more logical choice.

Writing to pins 0 and 1, while trying to use Serial on those pins, really isn't a good idea.

If you are looking for a ONE in any kind of "string", you need to look for the character '1' ( which in an ascii/char byte is 49 (hex) or something, and not the actual number 1, which is actually 01 (hex) .

So when i do my for loop checking each array spot for a 1 should I replace the

if(binary[j]==1)

with

if(binary[j]==49) ?

Using the character notation '1' is better (note the single quotes).

But still, using a String is still the wrong approach.

Ok, so i rewrote my function not to use strings. So I kind of brute force did the binary conversion, I don't know if there is a easier way to do it, but all the examples I find use strings. The one thing that is tripping me up is "returning an array" I know I'm suppose to use the pointers of the array, but I keep getting mixed up. Can you guys look at my code and tell me what i need to fix I keep getting incompatible data type errors. Thanks in advance.

int pins[7]={2,3, 4, 5, 6}
int pinx = 0;
byte i=0; //number to increment by that gets converted to binary
int binary[7]; //where the binary number is sotred
int b; //pointer int

void setup()
{
Serial.begin(9600);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin7, OUTPUT);
}

void loop()
{
binary=dectobin(i); // function to call conversian
Serial.println(binary);
delay(500); //delay to see change in serial monitor

for(int j=0; j<=7; j++)
{
if(binary[j]==1)
{
pinx=j;
digitalWrite(pinx, HIGH);
delay(1000);
}
else
{
pinx=j;
digitalWrite(pinx, LOW);
delay(1000);
}
}

++i;

}

int *dectobin(int decNum)
{

int *result;

if (decNum - 128 < 0) //checks left most binary bit
{result[7]=0;} //sets array to zero
else {result[7]=1;} //sets array to one

if (decNum - 64 < 0) //repeat for next spot
{result[6]=0;}
else {result[6]=1;}

if (decNum - 32 < 0)
{result[5]=0;}
else {result[5]=1;}

if (decNum - 16 < 0)
{result[4]=0;}
else {result[4]=1;}

if (decNum - 8 < 0)
{result[3]=0;}
else {result[3]=1;}

if (decNum - 4 < 0)
{result[2]=0;}
else {result[2]=1;}

if (decNum - 2 < 0)
{result[1]=0;}
else {result[1]=1;}

if (decNum - 1 < 0) //checks right most binary bit
{result[0]=0;}
else {result[0]=1;}

return result;
}

That's actually less efficient than using a String. You're using 16 bytes to store 8 bits... Bit silly really.

You don't need to do any conversion at all. I have already shown you code to access each individual bit within the existing decimal value. You are trying to do something similar in your dectobin() function, but it's not a good way of doing it.

You should really get to grips with boolean operations, such as AND (&), OR (|), and bit shifting (<< and >>).

You have, for example, the value 186. That is internally represented as a pattern of on and off signals. That's binary that is. 186 is internally represented as 10111010.

If you AND the binary value 10111010 with 10000000 you end up with 100000000 (128 in decimal):

10111010
10000000 &
--------
100000000

Then if you AND it with 01000000 you end up with 00000000:

10111010
01000000 &
--------
010000000

AND returns a 1 in any bit where both are 1 and 0 in a bit where none or only one are 1.

The bit shifting operators slide bits to the left or right. So, if you take the decimal value 1, which is 00000001 in binary, and left shift it 3 places, that is "1 << 3" you end up with 00001000. The value has shifted to the left three places - anything in the upper bits will drop off the end and fall on the floor.

Combining the two together you can use bit shifting to create the value to AND against from a loop counter:

i = 0, mask = 1 << i (00000001)
i = 1, mask = 1 << i (00000010)
i = 2, mask = 1 << i (00000100)
i = 2, mask = 1 << i (00001000)
... etc.

ANDing those mask values with the incoming decimal value gives you the sequence:

i = 0, val & mask = 0 (10111010 & 00000001 = 00000000)
i = 1, val & mask = 2 (10111010 & 00000010 = 00000010)
i = 2, val & mask = 0 (10111010 & 00000100 = 00000000)
i = 3, val & mask = 8 (10111010 & 00001000 = 00001000)
i = 4, val & mask = 16 (10111010 & 00010000 = 00010000)
i = 5 val & mask = 32 (10111010 & 00100000 = 00100000)
i = 6, val & mask = 0 (10111010 & 01000000 = 00000000)
i = 7, val & mask = 128 (10111010 & 10000000 = 10000000)

So, doing it as code, nice and explicitly:

byte val = 0b10111010
for (byte i = 0; i < 8; i++) {
  byte mask = 1 << i; // Sequence of 1, 2, 4, 8 etc
  byte ANDed = val & mask;  // Each bit in turn, or 0 if bit is not set
  digitalWrite(pins[i], ANDed); // Set the pin HIGH if ANDed is anything but 0, set it LOW if it is 0.
}

And that is all you need. Your incoming decimal value is a packed array of bits. No need to waste time or memory exploding it into an array of integers that are either 1 or 0 - it's completely pointless.

The code finally worked. Thank you all that helped.
Here is the final code to visually show incrementation of a binary number on a 8 segment LED bar.

/*
from yigiter007
Code made by the help of
arduino forum
majenko
MarkT
PaulS
michinyon
*/

//Code to visually show incrementation of a binary number on a 8 segment LED bar.

int pins[8]={2, 3, 4, 5, 6, 7, 8, 9}; //pins that output to LED bar segment
byte val = 0b00000000; // binary srartng number

void setup()
{
Serial.begin(9600); //serial input to watch decimal number increment
pinMode(pins[0], OUTPUT);
pinMode(pins[1], OUTPUT);
pinMode(pins[2], OUTPUT);
pinMode(pins[3], OUTPUT);
pinMode(pins[4], OUTPUT);
pinMode(pins[5], OUTPUT);
pinMode(pins[6], OUTPUT);
pinMode(pins[7], OUTPUT);
}

void loop()
{

for (byte i = 0; i <= 8; i++) //loop to check each bit
{
byte mask = 1 << i; // Sequence of 1, 2, 4, 8 etc
byte ANDed = val & mask; // Each bit in turn, or 0 if bit is not set
digitalWrite(pins*, ANDed); // Set the pin HIGH if ANDed is anything but 0, set it LOW if it is 0.*

  • delay(25);*
    }
    Serial.println(val); //prints to screen
    ++val; //increases by 1
    }
    [/quote]

Post question. Is there a way to output the binary number to the screen like PRINT PORTX

Serial.println(val, BIN);

I would go with Reply #1 but to avoid having to understand how bitwise operators work, use the bitRead() function to read a specified bit from a number. I don't see any reason to represent the values textually at any point, unless you want to print them to the serial port for diagnostic purposes, and the code to do that would be just as easy as the code calling digitalWrite().