Multiple CD4021BE Shift Registers

Greetings
I've been working on a project for awhile to have 32 analog inputs into my pc. At first I was going to do this with the keyboard.h library and just have it type a letter. I later found the joystick.h library and I am trying that route. I have four shift registers each with 8 inputs. the first shift register is for inputs 1-8, second register is 9-16, etc. When I was using the keyboard library, input 1 worked as designed. Now that I moved it to joystick.h the first input isn't working. I went back to keyboard.h and it isn't work now either. So I moved on. Physical input 2 is now showing up in the serial monitor as input 1. Physical input 3 is showing as 2 and so on. So that means when I get to input 25 it shows as input 24. When I test input 26, nothing happens. I then created a fifth variable because I wasn't sure if there was room in the byte because everything seem to have shifted. That hasn't seemed to make a difference either.
Here are my questions. What have I don't incorrectly that the fourth shift register isn't reading any inputs? Why does physical input 1 no longer work? What can I do to make this code better?



//*************************************** Libraries ***************************************************

#include <Keyboard.h>

//define pins for shift registers
int latchPin = 8;
int dataPin = 9;
int clockPin = 7;

byte switchVar1 = 0;
byte switchVar2 = 0;
byte switchVar3 = 0;
byte switchVar4 = 0;
byte switchVar5 = 0;
byte variable = 0;

int duration = 150;

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

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

  Keyboard.begin();
}

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,LSBFIRST);
  switchVar2 = shiftIn(dataPin, clockPin,MSBFIRST);
  switchVar3 = shiftIn(dataPin, clockPin,MSBFIRST);
  switchVar4 = shiftIn(dataPin, clockPin,MSBFIRST);
  switchVar5 = shiftIn(dataPin, clockPin,MSBFIRST);

/*
  if (switchVar1 == B10000000) {
      Serial.print("Button 1 pressed --> ");
      Serial.println(switchVar1, BIN);    
  }  
  
  if (switchVar1 == B1000000) {
      Serial.print("Button 2 pressed --> ");
      Serial.println(switchVar1, BIN);
     }
  if (switchVar1 == B100000) {
      Serial.print("Button 3 pressed --> ");
      Serial.println(switchVar1, BIN);
  }  
  if (switchVar1 == B10000) {
      Serial.print("Button 4 pressed --> ");
      Serial.println(switchVar1, BIN);      
  }
  if (switchVar1 == B1000) {
      Serial.print("Button 5 pressed --> ");
      Serial.println(switchVar1, BIN);
  }
  if (switchVar1 == B100) {
      Serial.print("Button 6 pressed --> ");
      Serial.println(switchVar1, BIN);
  }

  if (switchVar1 == B10) {
    Serial.print("Button 7 pressed --> ");
    Serial.println(switchVar1, BIN);
    //Keyboard.write('R');
  }
*/

  //if (switchVar1 == B1) {
    Serial.print("Button 8 pressed --> ");
    Serial.println(switchVar1, BIN);
    //Keyboard.write('D');
  //}

  //if (switchVar2 == B10000000) {
    Serial.print("Button 9 pressed --> ");
    Serial.println(switchVar2, BIN);
  //}

  //if (switchVar2 == B1000000) {
    Serial.print("Button 10 pressed --> ");
    Serial.println(switchVar2, BIN);
  //}

  //if (switchVar2 == B100000) {
    Serial.print("Button 11 pressed --> ");
    Serial.println(switchVar2, BIN);
    //Keyboard.write('k');
  //}

  //if (switchVar2 == B10000) {
    Serial.print("Button 12 pressed --> ");
    Serial.println(switchVar2, BIN);
    //Keyboard.write('l');
  //}

  //if (switchVar2 == B1000) {
    Serial.print("Button 13 pressed --> ");
    Serial.println(switchVar2, BIN);
    //Keyboard.write('m');
  //}

  //if (switchVar2 == B100) {
    Serial.print("Button 14 pressed --> ");
    Serial.println(switchVar2, BIN);
    //Keyboard.write('n');
  //}

  //if (switchVar2 == B10) {
    Serial.print("Button 15 pressed --> ");
    Serial.println(switchVar2, BIN);
    //Keyboard.write('o');
  //}

  //if (switchVar2 == B1) {
    Serial.print("Button 16 pressed --> ");
    Serial.println(switchVar2, BIN);
    //Keyboard.write('p');
  //}

  //if (switchVar3 == B10000000) {
    Serial.print("Button 17 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('q');
  //}

  //if (switchVar3 == B1000000) {
    Serial.print("Button 18 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('r');
  //}

  //if (switchVar3 == B100000) {
    Serial.print("Button 19 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('s');
  //}

  //if (switchVar3 == B10000) {
    Serial.print("Button 20 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('t');
  //}

  //if (switchVar3 == B1000) {
    Serial.print("Button 21 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('u');
  //}

  //if (switchVar3 == B100) {
    Serial.print("Button 22 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('v');
  //}

  //if (switchVar3 == B10) {
    Serial.print("Button 23 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('w');
  //}

  //if (switchVar3 == B1) {
    Serial.print("Button 24 pressed --> ");
    Serial.println(switchVar3, BIN);
    //Keyboard.write('x');
  //}

  //if (switchVar4 == B10000000) {
    Serial.print("Button 25 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('y');
  //}

  //if (switchVar4 == B1000000) {
    Serial.print("Button 26 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('z');
  //}

  //if (switchVar4 == B100000) {
    Serial.print("Button 27 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('1');
  //}

  //if (switchVar4 == B10000) {
    Serial.print("Button 28 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('2');
  //}

  //if (switchVar4 == B1000) {
    Serial.print("Button 29 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('3');
    //Joystick.setButton (31,1);
  //}

  //if (switchVar4 == B100) {
    Serial.print("Button 30 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('4');
  //}

  //if (switchVar4 == B10) {
    Serial.print("Button 31 pressed --> ");
    Serial.println(switchVar4, BIN);
    //Keyboard.write('5');
  //}

  //if (switchVar4 == B1) {
    Serial.print("Button 32 pressed --> ");
    Serial.println(switchVar4, BIN);  //used for debugging
    //Keyboard.write('6');
  //}
    Serial.print("Button 33 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 34 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 35 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 36 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 37 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 38 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 39 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.print("Button 40 pressed --> ");
    Serial.println(switchVar5, BIN);  //used for debugging
    Serial.println();
    Serial.println();
  delay(2500);
}


Thank you for your time and help.

Instead of using shiftIn, just roll your own.

This here will read in one shift register so all you need to do is expand it to read 3 more.

const int dataPin = 2;   /* Q7 */
const int clockPin = 3;  /* CP */
const int latchPin = 4;  /* PL */
 
const int numBits = 8;   /* Set to 8 * number of shift registers */
 
void setup() {
  Serial.begin(115200);
  pinMode(dataPin, INPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}
 
void loop() {
  // Step 1: Sample
  digitalWrite(latchPin, LOW);
  digitalWrite(latchPin, HIGH);
 
  // Step 2: Shift
  Serial.print("Bits: ");
  for (int i = 0; i < numBits; i++) {
    int bit = digitalRead(dataPin);
    if (bit == HIGH) {
      Serial.print("1");
    } else {
      Serial.print("0");
    }
    digitalWrite(clockPin, HIGH); // Shift out the next bit
    digitalWrite(clockPin, LOW);
  }
 
  Serial.println();
  delay(1000);
}
1 Like

@HazardsMind hase given you a good start.

Sorry the line drawing in not easy to read.

First shift is LSBFIRST, remaining are MSBFIRST.  What's up wit dat?

Greetings
I was just trying different things and I apparently when I copied the code that's the way I was messing with it.

Greetings,
Thank you. I will try that and report back.

@HazardsMind
I implemented the code you provided. I understand it somewhat. I get the logic, just not always the high and low. I understand the concept, just not the practice.

When I run the code, after I changed the pins to match what I have, I get all 0's, no matter which input might be triggered.

I have two inputs shorted or closed and this is what I see in the Serial Monitor.
image

Ideas of what I've done wrong still?

Can you send a clearer picture or diagram of your wiring? Have you tested it with a single SR yet?

Greetings
See if this helps.
PCB_Leonardo-v.3_2024-09-21 Bottom.pdf (148.9 KB)
PCB_Leonardo-v.3_2024-09-21 Top.pdf (72.6 KB)

Have you double checked all your wiring?
Have you been able to test with a single SR?
What voltage are you using, I’m going to assume 5v.
If you have a voltmeter, check for shorts as well as continuity.

Greetings
I have checked the wiring to be the best of my ability. Doesn't mean I didn't mess something up.
I am using the 5v from the USB at this point. When I get everything working I'm planning on powering the Arduino from something other than the USB.
I have checked for shorts, and I find none. When I first made this, the first 16 inputs worked like I expected. Not the first one isn't recognized and everything has shifted down one bit.

I understand if this isn't possible, but is there a way that I could send you the actual the circuit board file? It isn't something I want to post publicly.

I have not taken out three of the Shift Registers to just use the first one yet no.

Why not? It's not like you've done anything we would laugh at or steal.

Also, have you tried or incorporated any of the suggestions offered?

Please post the code you have now that compiles and runs and shows this odd behaviour. I'd like to run it myself and would like to start on the same page.

TIA

a7

You may want to run it on an external power supply, just something else that can provide 5v as 4 shift registers may be too much for the usb to handle them and the Arduino.

If you do use an external supply, just make sure its ground is connected to the Arduino’s ground too. One of the gnd pins.

Greetings
Here is the code I'm running currently that doesn't show me when an input is "pressed".
The new version of the circuit board I have has a power input point that is tied to the ground.

const int dataPin = 9;   /* Q7 */
const int clockPin = 7;  /* CP */
const int latchPin = 8;  /* PL */
 
const int numBits = 32;   /* Set to 8 * number of shift registers */
 
void setup() {
  Serial.begin(115200);
  pinMode(dataPin, INPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}
 
void loop() {
  // Step 1: Sample
  digitalWrite(latchPin, LOW);
  digitalWrite(latchPin, HIGH);
 
  // Step 2: Shift
  Serial.print("Bits: ");
  for (int i = 0; i < numBits; i++) {
    int bit = digitalRead(dataPin);
    if (bit == HIGH) {
      Serial.print("1");
    } else {
      Serial.print("0");
    }
    digitalWrite(clockPin, HIGH); // Shift out the next bit
    digitalWrite(clockPin, LOW);
  }
 
  Serial.println();
  delay(1000);
}

This is an EasyEDA file.
PCB_Leonardo-v.4_2024-09-22.json (238.4 KB)

The code is fine. It works here, but I did have to use the only shift register IC available to me, the 74hc165.

A shift register is a shift register, lartch, clock and data. I think that this means…

… any differences would be down to the polarity or sense of the latch and clock signals. I am without time just now to get out both data sheets to see if they use the same signals or inversions. I thinkj data be data the same for both.

HTH

It can't hurt to try. But four CMOS shift register ICs shouldn't break the bank I don't think.

a7

I noticed the 4 ICs are all labeled P1 and the ports on the board are the same. I would be helpful if they were numbered P1-4 instead to denote which headers go to which IC.

Also did you intend to have the silkscreen on both sides or is that a bug with the EasyEDA software?

Do you by chance have a drawn out schematic instead of a traceroute layout?

Greetings
I did intend a silkscreen on both sides. The bottom side identifies what each part is for. Like the 4 shift registers, they are labeled for which switch bank they go to.

I do not have a drawn out schematic. I apologize. Unfortunately I don't even own a breadboard.

Did you test this board before you designed it? Or did you design it first and you are now testing it?

If it’s the latter, then you are kinda cutting before you measure and that is not a good idea.

I don’t really know any other way I can be of help with this. Perhaps someone can lend a hand?

Greetings
I designed it first and am now testing it. With the code I originally supplied, the first three shift registers worked. I agree, this is like cutting then measuring, but it was the option I had.

I appreciate your help so far.

Are you testing it with actual hardware now or simulator? If you are testing with hardware, try removing the last IC and see if anything comes in. My guess is the last one may be the issue as it could be wired wrong or just shorted. Also check your orientations. The chips seem to be going in two different orientations.

If you are testing on the simulator, again start removing traces from the last IC and see if any of them were wired incorrectly.