CD4021 PCB not working

Hi,

I made a PCB for the CD4021 to get more inputs. But it's not working.

All resistors are 5k1 ohm. When nothing is connected to an input I measure 4.7V, when I connect 5V to simulate a button press I measure -0.3V. Clearly something is off.

My schema:

My code:

 //**************************************************************//
//  Name    : shiftIn Example 2.1                               //
//  Author  : Carlyn Maw                                        //
//  Date    : 25 Jan, 2007                                      //
//  Version : 1.0                                               //
//  Notes   : Code for using a CD4021B Shift Register       //
//          :                                                   //
//****************************************************************

//define where your pins are
int latchPin = 6;
int dataPin = 2;
int clockPin = 5;

//Define variables to hold the data
//for each shift register.
//starting with non-zero numbers can help
//troubleshoot
byte switchVar1 = 72;  //01001000
byte switchVar2 = 159; //10011111
byte switchVar3 = 159; //10011111
byte switchVar4 = 159; //10011111
byte switchVar5 = 159; //10011111
byte switchVar6 = 159; //10011111


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

  //define pin modes
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, INPUT);

}

void loop() {

  //Pulse the latch pin:
  //set it to 1 to collect parallel data
  digitalWrite(latchPin,1);
  //set it to 1 to collect parallel data, wait
  delayMicroseconds(20);
  //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);
//  switchVar2 = shiftIn(dataPin, clockPin);
//  switchVar3 = shiftIn(dataPin, clockPin);
//  switchVar4 = shiftIn(dataPin, clockPin);
//  switchVar5 = shiftIn(dataPin, clockPin);
//  switchVar6 = shiftIn(dataPin, clockPin);


  //Print out the results.
  //leading 0's at the top of the byte
  //(7, 6, 5, etc) will be dropped before
  //the first pin that has a high input
  //reading  
  Serial.println(switchVar1, BIN);
//  if(switchVar1 > 0) Serial.println(switchVar1, BIN);
//  if(switchVar2 > 0) Serial.println(switchVar2, BIN);
  delay(500);
//  Serial.println(switchVar1, BIN);
//  Serial.println(switchVar2, BIN);
//  Serial.println(switchVar3, BIN);
//  Serial.println(switchVar4, BIN);
//  Serial.println(switchVar5, BIN);
//  Serial.println(switchVar6, BIN);

}

//------------------------------------------------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) {
  Serial.println("ShiftIn Function");
  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;
}

Great that you posted a schematic. It is a little tangled and difficult to read. My tip to improve it would be to use the +V and GND symbols that most schematic drawing packages have. Put as many of these around your schematic as you like, one per chip or even more. Then you don't have to join up all the 5V & ground lines with wires, which is making your schematic look so tangled.

When you say you are measuring -0.3V, where are you placing the meter probes?

Are you using these old chips just to read buttons? How many? 32? This can be done with 12 Arduino pins and no extra chips, if you make your buttons into a matrix.

PaulRB:
Great that you posted a schematic. It is a little tangled and difficult to read. My tip to improve it would be to use the +V and GND symbols that most schematic drawing packages have. Put as many of these around your schematic as you like, one per chip or even more. Then you don't have to join up all the 5V & ground lines with wires, which is making your schematic look so tangled.

Hi Paul,

Thanks once again for your answer! I tried decluttering the schematic, but it didn't really look any better. So instead I painted lines over all the important parts, I sincerely hope it's readable now!

PaulRB:
When you say you are measuring -0.3V, where are you placing the meter probes?

I placed 1 probe on the Pi-1 pin for example, and the other on the GND pin.

PaulRB:
Are you using these old chips just to read buttons? How many? 32? This can be done with 12 Arduino pins and no extra chips, if you make your buttons into a matrix.

I am indeed using these just to read buttons. I thought this solution would be fancier and better expandable than a button matrix. If these don't work out (it'd be a shame because I already had the PCB's manufactured since I got it to work on my breadboards), i'll try to make another one with a matrix. I'd prefer this simply because of the fact I already have most components.

Please let me know if you can help me further or need anything else!

Okay, I removed 5 IC's and just kept going with one. It would occassionally work, the way I hold it seems to matter... this is really weird.

Edit: not sure, but now I can't get it to work anymore. I feel like all my IC's broke or something..
Edit1: I thought about the grid, but it'll use too many pins considering I am using an Arduino Mini for the HID support.

It sounds to me like you have floating inputs. They would be easily influenced by being touched, or might just not work at all sometimes. Did you design the PCB? Maybe you made an error, PCB design isn't easy, even for experienced people, and judging by your schematic, I'm guessing you're new to that also. Try using your meter to check continuity between all the points that should be ground, all the Vcc points etc.

Your bypass caps seem to be 1uF. Usually they should be 0.1uF, ceramic, and close to the Vcc pin of each chip. Using a larger cap may not be as effective.

What do you mean by "HID support"?

What else do you need the Arduino pins for, so that you can't spare 12 for the matrix?

PaulRB:
It sounds to me like you have floating inputs. They would be easily influenced by being touched, or might just not work at all sometimes. Did you design the PCB? Maybe you made an error, PCB design isn't easy, even for experienced people, and judging by your schematic, I'm guessing you're new to that also. Try using your meter to check continuity between all the points that should be ground, all the Vcc points etc.
Your bypass caps seem to be 1uF. Usually they should be 0.1uF, ceramic, and close to the Vcc pin of each chip. Using a larger cap may not be as effective.
What do you mean by "HID support"?
What else do you need the Arduino pins for, so that you can't spare 12 for the matrix?

My bypass condensators are 0.1uF tantalum capacitors (the 1uF was a typo). Could that be a problem?

By HID support I mean when the Arduino board is connected to the computer, it shows up as a device so I can use the Joystick library. The ultimate goal is a button box.

Also, I am using this Arduino Micro so it would barely have enough pins, I also need 1 pin for an output, so I'd need another Arduino aswell (which is fine, but it just gets expensive having to replace all the parts):

For now I am hoping using the right capacitor would fix the problem. What do you think?

topiek:
I am using an Arduino Mini for the HID support.

Ah, another typo. You can't use Arduino Mini for USB HID, but you can use Micro. That's why I asked the question, wondering if you had chosen the wrong Arduino for your project.

I doubt changing the capacitor type will have any effect, but try that if you like.

Can you say more about the way the keyboard will be used? For typing text? Playing music? A crucial question would be do you need the ability to cope with multiple simultaneous key presses (rollover)?

I still don't get why you think Micro will not have enough pins for a key matrix. 12 will be needed for 32 keys. 16 would allow for 64 keys. Micro has 20 digital pins.

PaulRB:
Ah, another typo. You can't use Arduino Mini for USB HID, but you can use Micro. That's why I asked the question, wondering if you had chosen the wrong Arduino for your project.

I doubt changing the capacitor type will have any effect, but try that if you like.

Can you say more about the way the keyboard will be used? For typing text? Playing music? A crucial question would be do you need the ability to cope with multiple simultaneous key presses (rollover)?

I still don't get why you think Micro will not have enough pins for a key matrix. 12 will be needed for 32 keys. 16 would allow for 64 keys. Micro has 20 digital pins.

I am making a button box, mainly for gaming (simracing). So it would be nice if I could press multiple buttons at once.

I find it weird that the PCB sometimes works and sometimes it doesn't, so I am hoping changing capacitor type fixes it (I ordered ceramic capacitors)

topiek:
I am making a button box, mainly for gaming (simracing). So it would be nice if I could press multiple buttons at once.

Multiple buttons at once means:

  • Can't use a Charlieplexed button matrix. Shame, because that would only require 7 pins for up to 42 buttons.
  • You will need diodes in series with each key in a matrix, to prevent "ghosting".

PaulRB:
Multiple buttons at once means:

  • Can't use a Charlieplexed button matrix. Shame, because that would only require 7 pins for up to 42 buttons.
  • You will need diodes in series with each key in a matrix, to prevent "ghosting".

Alright. I ordered the right capacitor, should be arriving tomorrow. Hopefully that fixes it. Considering it sometimes does work makes me hopeful!

Sadly the capacitors didn't fix it :frowning:

Let’s see a good image of the wiring.

Do you have a scope, logic probe, data scope?

Suggest after you transfer the inputs into the registers, take the clock (normally at LOW) to a HIGH, then back to LOW, then read the data.

larryd:
Let’s see a good image of the wiring.

Do you have a scope, logic probe, data scope?

I have none of those. Also there is no wiring as I fabricated the PCB shown above.

larryd:
Suggest after you transfer the inputs into the registers, take the clock (normally at LOW) to a HIGH, then back to LOW, then read the data.

I will report back after trying this!

Edit: when should I make the clock high low? I don't quite understand when you mean I should do that (where in the code)

In setup() make the clock pin LOW.

void setup()
{
. . .
digitalWrite(myClockPin, 0);
. . .
}
. . .
for (i=7; i>=0; i--)
{
digitalWrite(myClockPin, 1);
digitalWrite(myClockPin,0);
temp = digitalRead(myDataPin);
. . .

Note: after your parallel load, read bit 1 first then on the subsequent bits execute the code above.

larryd:
Note: after your parallel load, read bit 1 first then on the subsequent bits execute the code above.

What do you mean by this exactly? My current code is the following:

 //**************************************************************//
//  Name    : shiftIn Example 2.1                               //
//  Author  : Carlyn Maw                                        //
//  Date    : 25 Jan, 2007                                      //
//  Version : 1.0                                               //
//  Notes   : Code for using a CD4021B Shift Register       //
//          :                                                   //
//****************************************************************

//define where your pins are
int latchPin = 6;
int dataPin = 2;
int clockPin = 5;

//Define variables to hold the data
//for each shift register.
//starting with non-zero numbers can help
//troubleshoot
byte switchVar1 = 72;  //01001000
byte switchVar2 = 159; //10011111
byte switchVar3 = 159; //10011111
byte switchVar4 = 159; //10011111
byte switchVar5 = 159; //10011111
byte switchVar6 = 159; //10011111


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

  //define pin modes
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, INPUT);

  digitalWrite(clockPin, 0);

}

void loop() {

  //Pulse the latch pin:
  //set it to 1 to collect parallel data
  digitalWrite(latchPin,1);
  //set it to 1 to collect parallel data, wait
  delayMicroseconds(20);
  //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);
//  switchVar2 = shiftIn(dataPin, clockPin);
//  switchVar3 = shiftIn(dataPin, clockPin);
//  switchVar4 = shiftIn(dataPin, clockPin);
//  switchVar5 = shiftIn(dataPin, clockPin);
//  switchVar6 = shiftIn(dataPin, clockPin);


  //Print out the results.
  //leading 0's at the top of the byte
  //(7, 6, 5, etc) will be dropped before
  //the first pin that has a high input
  //reading  
  //if(switchVar1 > 0) {
    Serial.print("Switchvar 1:");
    Serial.print(switchVar1, BIN);
    Serial.print("\n");
  //}
//  if(switchVar2 > 0) Serial.println(switchVar2, BIN);
  delay(500);
//  Serial.println(switchVar1, BIN);
//  Serial.println(switchVar2, BIN);
//  Serial.println(switchVar3, BIN);
//  Serial.println(switchVar4, BIN);
//  Serial.println(switchVar5, BIN);
//  Serial.println(switchVar6, BIN);

}

//------------------------------------------------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) {
  //Serial.println("ShiftIn Function");
  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);
    digitalWrite(myClockPin, 1);
    digitalWrite(myClockPin,0);
    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;
}

I do not have a CD4021 so this is not tested, should be close.

This is for just one hardware byte closest to the Arduino (I.C. #C0) .

//CD4021 or 74HC165  parallel in to serial out
// Version  1.01
//

#define CD4021

//                          75HC165                CD4021
const byte latchPin = 6; //    1 (HIGH = serial)      9 (LOW = serial)
const byte clockPin = 5; //    2                     10
const byte dataPin  = 2; //    9                      3

unsigned int switchVar1;


//*******************************************************************
void setup()
{
  Serial.begin(9600);

  pinMode(latchPin, OUTPUT);

  pinMode(clockPin, OUTPUT);
  digitalWrite(clockPin, 0);

  pinMode(dataPin, INPUT_PULLUP);

  digitalWrite(clockPin, 0);

} //END of setup()


//*******************************************************************
void loop()
{
#ifndef CD4021                  //for 74HC165
  //serial data transfer mode
  digitalWrite(latchPin, LOW);
#endif

  digitalWrite(latchPin, HIGH);

#ifdef CD4021                   //for CD4021
  //serial data transfer mode
  digitalWrite(latchPin, LOW);
#endif

  switchVar1 = shiftIn(dataPin, clockPin);
  Serial.print("Switchvar1 = ");
  printBits(switchVar1);


  delay(500);

} //END of loop()


//*******************************************************************
byte shiftIn(byte myDataPin, byte myClockPin)
{
  byte temp = 0;
  byte myDataIn;

  myDataIn = 0;

  for (int i = 7; i >= 0; i--)
  {
    //shift data left one bit
    myDataIn = myDataIn << 1;

    //get the next bit
    temp = digitalRead(myDataPin);

    //add to data
    myDataIn = myDataIn | temp;

    //advance to the next bit
    digitalWrite(myClockPin, 1);
    digitalWrite(myClockPin, 0);

  }

  return myDataIn;
  
} //END of   shiftIn()

//*******************************************************************
//print in binary with leading zeros
void printBits(unsigned int var)
{
  for (unsigned int x = 0x80; x; x = x >> 1)
  {
    Serial.print(var & x ? 1 : 0);
  }

  //Or use:
  //  for (int x = 7; x >= 0; x--)
  //  {
  //    if ((var & 1 << x) != 0)
  //    {
  //      Serial.print(1);
  //    }
  //    else
  //    {
  //      Serial.print(0);
  //    }
  //  }

  Serial.print("\n");

} //END of   printBits()

Oh my... so the issue ended up being I had the wrong latch pin... I am so sorry! :frowning:

Hold on there:

The sketch offered you can be used with either 74HC165 or the CD4021 parallel to serial shift registers.

As the comments state, the pins are a different between these two chips.

Yours (CD4021) use 9 (latch) 10 (clock) 3 (data).

The pins on the Arduino can be any I/O pin you wish to use, hence 6, 5 and 2.

This line of code “#define CD4021” should make the code work with your CD4021.

I have proven the code works with the 74HC165, but I do not have a CD4021 to test.

larryd:
Hold on there:

The sketch offered you can be used with either 74HC165 or the CD4021 parallel to serial shift registers.

As the comments state, the pins are a different between these two chips.

Yours (CD4021) use 9 (latch) 10 (clock) 3 (data).

The pins on the Arduino can be any I/O pin you wish to use, hence 6, 5 and 2.

This line of code “#define CD4021” should make the code work with your CD4021.

I have proven the code works with the 74HC165, but I do not have a CD4021 to test.

Your code worked just fine with the CD4021. My issue was that I am a little dumb and I soldered 2 green wires, 1 for some LED output and one for the latch wire. Now in my code I had the led output pin (pin 6) as latch, because I got the wires mixed up as they were both green. It seems to work now though.