Control CD4021 and 74HC595 over the same SPI bus

Working on a project I needed extra digital in’s and extra digital out’s for my Arduino Uno (lots of LEDs, lots of buttons). I’ll use a CD4021 to extend the digital in’s and a 74HC595 to gain extra digital out’s. I decided it would be best to both access the data of the CD4021 and send data to the 74HC595 over the hardware SPI bus on the Arduino (see previous post). Turns out te be not that hard (fortunately ;) ). Here’s the eagle schematic for 1 4021 and 1 595. Of course you can cascade more IC’s if you need more in’s or out’s. Only difference is that you’ll have to interpret and send more bytes (1 byte per IC).

Here’s my Arduino code so far:

#include <SPI.h>

#define PIN_SCK          13             // SPI clock
#define PIN_MISO         12             // SPI data input
#define PIN_MOSI         11             // SPI data output
#define PIN_SS1          10             // SPI hardware default SS pin, 4021
#define PIN_595_1        9              // SPI 74HC595

// result byte for 4021
byte buttons8;

// global vars for button timeout and debounce
long button1timeout = 0;
long button2timeout = 0;
long debounce = 200;

void setup() {
  Serial.begin(9600);
  SPI.begin();
  
  // set all IC select pins HIGH
  digitalWrite(PIN_SS1,HIGH);
  pinMode(PIN_595_1, OUTPUT);
  digitalWrite(PIN_595_1,HIGH);
}

void loop() {
   
  // SS1 = HIGH -> 4021 is gathering data from parallel inputs
  
  // select 595
  digitalWrite(PIN_595_1,LOW);
  
  // send BIN number to 595 to light 1 LED (not necessarily the 1 example LED on the schematic)
  SPI.transfer(B00000100);
  
  // deselect 595
  digitalWrite(PIN_595_1,HIGH);
  
  // select 4021
  digitalWrite(PIN_SS1,LOW);
  // read CD4021 IC
  buttons8 = SPI.transfer(0x00);
  
  // button functions and debounces
  // needs refactoring for smaller footprint
  if((B10000000 & buttons8) && (millis() - button1timeout > debounce)) {
    Serial.println("but1");
    button1timeout = millis();
  }
  if((B01000000 & buttons8) && (millis() - button2timeout > debounce)) {
    Serial.println("but2");
    button2timeout = millis();
  }
  
  // deselect 4021
  digitalWrite(PIN_SS1,HIGH);
}