// 8xDIP --> 74HC165 --> ATtiny85 --> 74HC595 --> 8xLED
// ====================================================================================
// Updated 05May2015
// By C. Parkin
// https://hackaday.io/project/5439-one-tiny-bot/log/17466-expanding-the-attiny85s-io-capacity-with-shift-registers

// Pins
int clockPin    = 0;  // *COMMON* connected to pin 11 (SH_CP, SRCLK) of 595, pin 2 (CLK/CP) of 165
int outLatchPin = 1;  //connected to pin 12 (ST_CP, RCLK) of 595
int outDataPin  = 2;  //connected to pin 14 (DS, SER) of 595
int inLatchPin  = 3;  //connected to pin 1 (SH/LD, PL)("shift/load") of 165
int inDataPin   = 4;  //connected to pin 9 (QH, Q7) ("data") of 165

// Other Pin Settings:
// 165:
//    Pin 15 (CLK INH or CE) ("clock enable") to GROUND (active low)
//    Pin 10 (SER, DS) ("serial data input") to GROUND (when not connected to another 165)
//    Pin 11-14 (A-D), 3-6 (E-H) to parallel inputs
//    Pin 16 to Vcc
//    Pin 8 to GND
//    Pin 7 (Q_H or Q_7) ("complementary output from the last stage") left unconnected?(as shown on 2+ sources)
//
// 595:
//    Pin 10 (MR, SRCLR) ("Master Reset", "Serial Clear") to Vcc
//    Pin 13 (OE) ("output enable input") to GROUND (active LOW)
//    Pin 16 to Vcc
//    Pin 8 to GND
//    Pin 15, 1-7 to parallel outputs
//    Pin 9 (Q7") ("Serial out") left unconnected w/only 1 chip?

// Serial storage variables
byte inByte;    //for the 8 values loaded FROM the 165 shift register
byte outByte;    //for the 8 values loaded TO the 595 shift register

// function to read in from 165
void getter() {
  // take the latch pin low to move the parallel inputs into the shift register
  digitalWrite(inLatchPin, LOW);
  delayMicroseconds(5);   //some resources suggest 10 for this; try that if 5 doesn't work.
  digitalWrite(inLatchPin, HIGH);
  // populate the inByte
  for (int bitCount = 0; bitCount < 8; bitCount++)  {
    // set the current bit to the current value of inDataPin
    bitWrite(inByte, bitCount, !digitalRead(inDataPin));
    //pulse the clock to shift to the next serial-in bit
    digitalWrite(clockPin, HIGH);
    delayMicroseconds(5);
    digitalWrite(clockPin, LOW);
  }
}

// function to write out to 595
void putter() {
  // output the outByte
  for (int bitCount = 0; bitCount < 8; bitCount++)  {
    // set outDataPin according to current bit value:
    digitalWrite(outDataPin, bitRead(outByte, bitCount));
    //pulse the clock
    digitalWrite(clockPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(clockPin, LOW);
  }
  //take the latch pin high to move the new sequence to the parallel output
  digitalWrite(outLatchPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(outLatchPin, LOW);
}

void setup()  {
  // Common Clock Pin
  pinMode(clockPin, OUTPUT);    //sends pulses to the shift registers
  // IN specific pins
  pinMode(inLatchPin, OUTPUT);     //latch/loads the current parallel in values into the shift register for serial output to tiny
  pinMode(inDataPin, INPUT);    //serial input from shift register to tiny
  // OUT specific pins
  pinMode(outLatchPin, OUTPUT);    //shifts current serial values in register to register outputs
  pinMode(outDataPin, OUTPUT);    //serial output from tiny to shift register
  // Set pins to proper states: (Is this better done in the loop or getter/putter functions?)
  digitalWrite(inLatchPin, HIGH); // SH/LD is active low, so we set it high to avoid premature loading
  digitalWrite(clockPin, LOW);    // clock is low-to-high edge-triggered, so start low
  digitalWrite(outLatchPin, LOW); // SH_CP is positive-edge triggered, so start low
  // Initialize in/outBytes to zero
  inByte = B00000000;
  outByte = B00000000;
}

void loop() {
  getter();
  // Here is where we would, in a more complicated program, figure out what to do with the input data
  outByte = inByte;    // In this simple case, simply pass it over to the Putter function
  putter();
}
ATTINY8520PU
74HC595
74HC165