Please help with shift register CD4021BE (Update)

Hello all

I'm in a project where I need 5 shift registers CD4021BE for inputs buttons.
Daisy chaining them is giving me a lot of problems
I'm using five 74HC595 for outputs to leds and they work perfectly!

I've make a lot of search about this:
I'ld like to know if there is a way to put all those on my arduino mega without daisy chaining them...
each one independent from the other
It is ok to use 15 pins (3 for each one)... I just can't find the way.

When I make the tutorials from Arduino and other forums, they always only have two shift register maximum and they say that I can continue daisy chainig them... but honestly, as soon I go to the third, the problems don't stop.

I only can imagine the numbers on the variables to hold the data for each shift register... they say 72 for the first and 159 for the second, but after that, I don't know what to do (I've tried with different numbers for the other ones and again... all goes crazy)

Thank you in advance.

Hi and welcome.

We will need a schematic and your code if we are going to help you. Your explanation of the problem does not make much sense at the moment. The schematic can be hand drawn as long as it is neat. Post your code using code tags <>.

You want to read 40 buttons? There are much simpler ways, without using any shift registers. For example a matrix configuration of 5x8 would need 13 digital pins.

Paul

Hello and thanks for the reply.

I’ll make a schematic and upload the code, meanwhile check out some pics… I’m very happy with what I’m doing and the setup… let me know what you think.

Thanks
Luis

let me know what you think.

I think you are asking for trouble using solder-less bread board for such a big project. It will end in tears.

all goes crazy)

There is NO decoupling capacitors anywhere in that circuit. You need a 0.1uF ceramic capacitor on EVERY chip.

http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

CD4021, old part. I'd use something more modern, 74HC165.
http://www.digikey.com/product-detail/en/SN74HC164N/296-8248-5-ND/376946
One pin to capture state of all inputs, then shift the data out.
Can shift data in at same time as shift data out to HC595 if you use SPI interface.

Don’t forget 0.1uF cap on every device’s Vcc pin as Grumpy_Mike says. Those are important.

ba60b8ded9d6486f3546e6d891d4948edcd26a5d.jpg
4d5c5fbb2e2b8449c9ac93bc2aa093e4c770e833.jpg
453c31390f7f55cbd95574619ce07fab9046de17.jpg
Holy crap that is a big breadboard!

Hello all
Thanks for all that valuable information.

I’m preparing the squematic using the 123d-Circuit site to upload it with the code.

Anyway, I think I must take in consideration the advice about the obsolete CD4021BE and go for those more modern 74HC165 shift registers… umh, I’m signing in to my DigiKey account right now.

About the decoupling capacitors… I read about that, but now I see I was trying to do it the wrong way.

For you have an idea of how newbie I am, I’ll have to buy a new Arduino (Due) because I did’nt know that my lovely Mega can’t send keyboard commands… what can I say?

Here are some updated pictures

Thank you.
Luis

I’ll attach those pics properly for you again so everyone can see them.

I’m not sure the 7400 series chips are any more modern than 4000 series. Both invented back in the '60s? A geniunely more modern chip to consider would be i2c i/o expanders. Looks like you are already using i2c bus for your lcd display, and the expanders would be able to use the same two Arduino pins.

I must ask again, why are you convinced you must have shift registers for this? It can be done with no extra chips and fewer digital pins than you were considering using.

c66944b4e81410a3c3e9829eb1b5461bf7a3bd27.jpg

8420f46b1e3821dc9808917d9c34e524285b244d.jpg

Hello all

As you requested, here are the squematic and the code of the project.
I hope it is ok and lead us to the problem…

About the shift register use for this project, even when there are easier ways to acomplish it, I must be honest and say the following, when I fell in love with Arduino and its possibilities a few months ago, I did not know anything about electronics (still I don’t… but working hard the get better), I make a lot of research about what I wanted to do at that moment. The ICs, in this case the shift registers, had been for me a mistery, a little black “thing” in a complicated PCB and I decided to use this “hardest” method as a way to learn… maybe not the best decision, but at the stage I’m now, I think it does’nt worth to change the method (because the learning).

Honestly, I’ve learn a lot and the most important is I’m starting to see the circuits as a not so impossible challenge… hard, but not impossible.

You can’t imagine how grateful I am with all you… your help and interest.
Please help me to acomplish this, I promise to take all the neccesary advice… by the way, the 74HC165’s are on its way.

How do I attach images the way PaulRB did?.. anyway I attached the squematic by the attach option.
Please remember that the shift registers are 74HC595 and cd4021BE… (the 123D software do not have available the second one to include in the squematic, so I use another 16 pins IC, so watch for correct pins)

int latchPin = 8;
int dataPin = 9;
int clockPin = 7;

#include <SPI.h>
#include <Wire.h>

#include <ShiftRegister74HC595.h>
long time = 0;         // the last time the output pin was toggled
long debounce = 300;   // the debounce time, increase if the output flickers
ShiftRegister74HC595 sr1 (1, 6, 5, 4);

//Define variables to hold the data 
//for each shift register.
//starting with non-zero numbers can help
//troubleshoot
byte switchVar1 = 0;  //10000000

void setup() {
  //start serial
  Serial.begin(9600);

  //define pin modes
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT); 
  pinMode(dataPin, INPUT);
  
  sr1.set(0, LOW);

}

void loop() {

  //Pulse the latch pin:
  //set it to 1 to collect parallel data
  digitalWrite(latchPin,1);
//  digitalWrite(latchPinVar2,1);
//  digitalWrite(latchPinVar3,1);
  //set it to 1 to collect parallel data, wait
  delayMicroseconds(1);
  //set it to 0 to transmit data serially  
  digitalWrite(latchPin,0);

  //while the shift register is in serial mode
  //collect each shift register into a byte
  //the register attached to the chip comes in first 
  switchVar1 = shiftIn(dataPin, clockPin);

  Serial.println(switchVar1, BIN);

  delay(500);
  


  for (int n=0; n<6; n++)
  {
    if (switchVar1 & (1 << 6) ){
    }
    lcd.setBacklight(HIGH);
    {if (switchVar1 & (10) ){Serial.println("Down Arrow"),      sr1.set(6, HIGH);}     }
    {if (switchVar1 & (100) ){Serial.println("Magnifier"),      sr1.set(5, HIGH);}      }
    {if (switchVar1 & (1000) ){Serial.println("Up Arrow"),      sr1.set(4, HIGH);}       }
    {if (switchVar1 & (10000) ){Serial.println("Events 4"),     sr1.set(3, HIGH);}       }
    {if (switchVar1 & (100000) ){Serial.println("Events 3"),    sr1.set(2, HIGH);}       }
    {if (switchVar1 & (1000000) ){Serial.println("Events 2"),   sr1.set(1, HIGH);}       }
    {if (switchVar1 & (10000000) ){Serial.println("Events 1"),  sr1.set(0, HIGH);}       }
    {if (switchVar1 & (10000000) ){Serial.println("X"),        sr1.set(0, HIGH);}       }
  }

}

//------------------------------------------------end main loop

////// ----------------------------------------shiftIn function
///// just needs the location of the data pin and the clock pin
///// it returns a byte with each bit in the byte corresponding
///// to a pin on the shift register. leftBit 7 = Pin 7 / Bit 0= Pin 0

byte shiftIn(int myDataPin, int myClockPin) { 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);

//we will be holding the clock pin high 8 times (0,..,7) at the
//end of each time through the for loop

//at the begining of each loop when we set the clock low, it will
//be doing the necessary low to high drop to cause the shift
//register's DataPin to change state based on the value
//of the next bit in its serial information flow.
//The register transmits the information about the pins from pin 7 to pin 0
//so that is why our function counts down
  for (i=7
  ; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    //delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      //set the bit to 0 no matter what
      myDataIn = myDataIn | (1 << i);
    }
    else {
      //turn it off -- only necessary for debuging
     //print statement since myDataIn starts as 0
      pinState = 0;
    }

    //Debuging print statements
    //Serial.print(pinState);
    //Serial.print("     ");
    //Serial.println (dataIn, BIN);

    digitalWrite(myClockPin, 1);

  }
  //debuging print statements whitespace
  //Serial.println();
  //Serial.println(myDataIn, BIN);
  return myDataIn;
}

How do I attach images the way PaulRB did?

(the 123D software do not have available the second one to include in the squematic, so I use another 16 pins IC, so watch for correct pins)

So what you do is make one, or if you can't then abandon the software and draw them by hand.

You still have not got any decoupling caps.

4b72555a459965425e299283ab12551c894dceb2.png

if (switchVar1 & (1 << 6) ){

…should be…

if (switchVar1 & (1 << n) ){

perhaps.

And…

switchVar1 & (100)

…should be…

switchVar1 & (0b100)

maybe.

It would be easier to use the built in functions bitRead() and shiftIn().

Hello

Here is the 0.1uf ceramic capacitor from vcc to ground.

I’m placing them as recommended, as near the vcc pin as possible.
it is ok that way?

Squematic2.png

Thanks

Yes that bit is good.
However your schematic is a bit messy and would be greatly simplified by use of a ground symbol and a 5V symbol so you would reduce the number of wires in the diagram.

The other thing is that you are using the switches to connect a pulled down pin to 5V. While this might function with the chip you have if you switch to a 165 then the pull down needs to be a lot lower in value. You would be better off reversing it and having the resistor pull up and the switch connect the input to ground. This is the normal way to do things. It is just in the Arduino world that this upside down method seems to be rife.

Hello

The project is getting better, now I have a stable signal from each button and 7 from 8 works ok.

The only one is the button #5, it does two things… the one that correspond to it self and the one that correspond to button #7

I’m attaching the new code.

It is supposed to do this:
1- Print to serial monitor “Button 5”
2- Turn on led 4

But is doing this:
1- Print to serial monitor “Button 5”
2- Print to serial monitor “Button 7”
2- Turn on led 4
2- Turn on led 6

int latchPin = 8;
int dataPin = 9;
int clockPin = 7;
#include <SPI.h>
#include <Wire.h>
#include <ShiftRegister74HC595.h>
long time = 0;
long debounce = 300;
ShiftRegister74HC595 sr1 (1, 25, 23, 27);
byte switchVar1 = 72;  //10000000

void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT); 
  pinMode(dataPin, INPUT);
  sr1.set(0, LOW);
}

void loop() {
  digitalWrite(latchPin,1);
  delayMicroseconds(1);
  digitalWrite(latchPin,0);
  switchVar1 = shiftIn(dataPin, clockPin);
  Serial.println(switchVar1, BIN);
  delay(500);

  for (int n=0; n<7; n++)
  {
    if (switchVar1 & (1 << n) ){
    }
    {if (switchVar1 & (1) )          {Serial.println("Button 8"),   sr1.set(7, HIGH);}    }  // It Works!!! Prints "Button 8"
    {if (switchVar1 & (10) )         {Serial.println("Button 7"),   sr1.set(6, HIGH);}    }  // It Works!!! Prints "Button 7"  
    {if (switchVar1 & (0b100) )      {Serial.println("Button 6"),   sr1.set(5, HIGH);}    }  // It Works!!! Prints "Button 6"
    {if (switchVar1 & (0b1000) )     {Serial.println("Button 5"),   sr1.set(4, HIGH);}    }  // Don't work!!! Print "Button 7 and Button 5"
    {if (switchVar1 & (0b10000) )    {Serial.println("Button 4"),   sr1.set(3, HIGH);}    }  // It Works!!! Prints "Button 4"
    {if (switchVar1 & (0b100000) )   {Serial.println("Button 3"),   sr1.set(2, HIGH);}    }  // It Works!!! Prints "Button 3"
    {if (switchVar1 & (1000000) )    {Serial.println("Button 2"),   sr1.set(1, HIGH);}    }  // It Works!!! Prints "Button 2"
    {if (switchVar1 & (10000000) )   {Serial.println("Button 1"),   sr1.set(0, HIGH);}    }  // It Works!!! Prints "Button 1"
  }
}
byte shiftIn(int myDataPin, int myClockPin) { 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);

  for (i=7
  ; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      myDataIn = myDataIn | (1 << i);
    }
    else {
      pinState = 0;
    }
    digitalWrite(myClockPin, 1);
  }
  Serial.println();
  Serial.println(myDataIn, BIN);
  return myDataIn;
}

I writed at the end of the line preceded by // where the mistake occurs.

Thanks
Luis

That looks like a wiring fault.

How come in your table for the switches, some
are byte mask while others are decimal numbers,
Shouldn't they all be byte mask?
Dwight

dwightthinker:
How come in your table for the switches, some
are byte mask while others are decimal numbers,
Shouldn't they all be byte mask?
Dwight

I have warned the OP about this already but he seems to have only partially made the changes:

    {if (switchVar1 & (1) )          {Serial.println("Button 8"),   sr1.set(7, HIGH);}    }  // It Works!!! Prints "Button 8"
    {if (switchVar1 & (10) )         {Serial.println("Button 7"),   sr1.set(6, HIGH);}    }  // It Works!!! Prints "Button 7"  
    {if (switchVar1 & (0b100) )      {Serial.println("Button 6"),   sr1.set(5, HIGH);}    }  // It Works!!! Prints "Button 6"
    {if (switchVar1 & (0b1000) )     {Serial.println("Button 5"),   sr1.set(4, HIGH);}    }  // Don't work!!! Print "Button 7 and Button 5"
    {if (switchVar1 & (0b10000) )    {Serial.println("Button 4"),   sr1.set(3, HIGH);}    }  // It Works!!! Prints "Button 4"
    {if (switchVar1 & (0b100000) )   {Serial.println("Button 3"),   sr1.set(2, HIGH);}    }  // It Works!!! Prints "Button 3"
    {if (switchVar1 & (1000000) )    {Serial.println("Button 2"),   sr1.set(1, HIGH);}    }  // It Works!!! Prints "Button 2"
    {if (switchVar1 & (10000000) )   {Serial.println("Button 1"),   sr1.set(0, HIGH);}    }  // It Works!!! Prints "Button 1"

Well by chance 10 will work as it is 1010 so as long as only one button was pressed at once it will appear to work. The same goes for the other two I guess but I haven't checked.

As the position that doesn't work has a mask that is correct my money is on the wiring.

  for (int n=0; n<7; n++)         // <-- for each bit in the switch var...  (except bit 7?)
  {
    if (switchVar1 & (1 << n) )   // <-- ...check if the bit is set high...
    {                             // <-- ...and if it is, do nothing?!
    }
                                  //     Then continue to check each bit one by one (seven times: for n = 0 .. 6, but n is not used.)
    {if (switchVar1 & (1) )          {Serial.println("Button 8"),   sr1.set(7, HIGH);}    }  // It Works!!! Prints "Button 8"
    {...}

Grumpy_Mike:
Well by chance 10 will work as it is 1010 so as long as only one button was pressed at once it will appear to work.

It works in the sense that button 7 will still report “Button 7” (the right bit is set), but some other button than button 7 will also report “Button 7” (because some other bit is also set).