Help with ShiftOut

I am trying to understand shiftOut in my project and need some help.

I have a project that has several different momentary buttons. Depending on what button is pushed, a different LED will turn on/off.

I am trying to control this with shiftOut. The plan was to create an array that would hold 8 variables - one for each button - and then shiftOUt the array.

This is what I was thinking:

int button1 = 0;
int button2 = 0;
...
int button8 = 0;

int myArray = { button1, button2, button3, ... button8 }

// detect state of each button here, then shiftOut

shiftOut(data, clock, MSBFIRST, myArray);

I keep getting errors when I try to set up the array with a bunch of variables in it. I tried looking this up elsewhere but the discussions were way over my head.

Any help pointing me to a simple answer would be very appreciated.

If it helps, I am using an uno with a 74hc595.

Look at the documentation for shiftOut(). Does it handle arrays? No. Always read and at least try to understand the documentation and examples before you go looking for help. Please post a link to the documentation to prove that you have done this. :slight_smile:

The shiftOut function works with bytes. There are 8 bits in a byte. You have 8 switches. There are bit functions that let you set and clear bits in a byte. If you have an array of 8 switches, it is easy to iterate through them, set or clear a bit in a byte , then shift that byte out.

I for one would do away with the array in that case, just use a single byte value, and set bits accordingly when you want to toggle one of the LEDs.

Check out the first answer of this StackOverflow question for all you need to know about single bit manipulations.

It can be done even simpler.
Assuming you have your buttons connected to one shift register, and your LEDs (in order) to another, you can simply read a complete byte from one shift register, then write that exact byte to the other shift register, and you're done. The LEDs reflect your buttons, no matter how many buttons you press at the same time.

Something like this:

byte state;
loop() {
  shiftIn(data, clock, state);  // read the 8-bit state.
  shiftOut(data, clock, state);  // write the 8-bit state to the other (part of the) register.
}

groundFungus:
The shiftOut function works with bytes. There are 8 bits in a byte. You have 8 switches. There are bit functions that let you set and clear bits in a byte. If you have an array of 8 switches, it is easy to iterate through them, set or clear a bit in a byte , then shift that byte out.

groundFungus - Thank you for responding. I understand that each one of the 8 outputs on the register is controlled by a bit. However, I am not understanding how to send that data to the register using shiftOut.

For example, if I wanted to turn on just one of the 8 led's, I should be able to send a byte like 00000001. I have tried that using:

shiftOut(data, clock, MSBFIRST, 0000001);

I have also tried using a variable in place of the byte but neither of them work.

As you suggested, I read the link on bitWrite() but there is not much information there and no examples of when or how to use it. Would I use something like that inside a for loop that reads an array?

Thanks for your help!

bkirkby:

shiftOut(data, clock, MSBFIRST, 0000001);

That's octal notation. You want binary notation.

shiftOut(data, clock, MSBFIRST, 0b00000001);

Doesn't make any difference on a 1, but makes a HUGE difference to any other number.

Thank you all for your help!

I figured out a solution that was easier for me to understand. It is probably not very elegant code and I would be curious to know how I could have done this more efficiently.

My solution is:

  // Make an array that will be updated by individual button clicks

  int btnStateArray[8] = {0, 0, 0, 0, 0, 0, 0, 0};

  // Read array and create a byte

  int newBit = 0;

  if(btnStateArray[0] == 1){
    newBit = newBit + 128;
  }
  if(btnStateArray[1] == 1){
    newBit = newBit + 64;
  }
  if(btnStateArray[2] == 1){
    newBit = newBit + 32;
  }
  if(btnStateArray[3] == 1){
    newBit = newBit + 16;
  }
  if(btnStateArray[4] == 1){
    newBit = newBit + 8;
  }
  if(btnStateArray[5] == 1){
    newBit = newBit + 4;
  }
  if(btnStateArray[6] == 1){
    newBit = newBit + 2;
  }
  if(btnStateArray[7] == 1){
    newBit = newBit + 1;
  }

  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, newBit);
  digitalWrite(latch, HIGH);

bkirkby:
I figured out a solution that was easier for me to understand. It is probably not very elegant code and I would be curious to know how I could have done this more efficiently.

Yes, can be made a lot smaller.

  int btnStateArray[8] = {0, 0, 0, 0, 0, 0, 0, 0};

You could make this an array of bool. Faster, and an int takes two bytes in memory, while bool takes just one. All you’re going to store is a true/false state anyway.

Or even better, store the button states in a single byte:

byte btnState = 0;
  if(btnStateArray[0] == 1){

newBit = newBit + 128;
  }
  // rest removed.

Instead of the array and this list of if/then statements, you store the button state in your btnState value. After all every button is a simple 1/0 state: on or off.
I assume buttons are wired active low and the pin numbers are stored in the buttonPin array. You would update this variable as you read the buttons, so the whole btnStateArray is not needed any more.

for (byte i = 0; i < 8; i++) {  // Iterate over all eight buttons.
   if (digitalRead(buttonPin[i])) { // Check the button state.
    btnState &= ~(1 << i);  // Reset bit i in btnState: this button is not pressed.
  else {
    btnState |= 1 << i; // Set bit i in btnState: this button is pressed.
  }
}

Now everything is stored in the singly byte btnState and this can be written to your shift register as is.

Beware: the order of bits is the exact opposite as in your code. Your btnStateArray[0] writes bit 7 in btnState, in my code buttonPin[0] sets bit 0 in btnState. This just means you have to update your wiring, or reverse the order of pin numbers in the buttonPin array.

wvmarle:
Beware: the order of bits is the exact opposite as in your code. Your btnStateArray[0] writes bit 7 in btnState, in my code buttonPin[0] sets bit 0 in btnState. This just means you have to update your wiring, or reverse the order of pin numbers in the buttonPin array.

Or you could use LSBFIRST instead of MSBFIRST.

I have to admit being unfamiliar with the exact communication between the Arduino and the shift register. I just have a rough understanding on how they work and what kind of data they expect :slight_smile: The part of getting the data onto the shift register I'll leave to OP.