The ATtiny85 is a great little chip, but decidedly lacking when it comes to IO pins. While excellent mobile robots can certainly be built around its innate capabilities, I decided that I needed to expand beyond 5 pins for the sorts of applications I had in mind. Figuring out different ways to do so has proven wonderfully educational.
The obvious and easiest place to start was with shift registers, as first suggested to me by the Sparkfun Tiny AVR Programmer Hookup Guide.
Accordingly, I acquired some 74HC165 (PISO: Parallel-In/Serial-Out) and 74HC595 (SIPO: Serial-In/Parallel-Out) shift register chips, and set about learning how to make the Tiny talk to one, the other, and then both of them.
There are a plethora of helpful guides on using these chips with Arduino:
- http://www.ecs.umass.edu/ece/m5/tutorials/parallel_serial_shift_register.html
- http://playground.arduino.cc/Code/ShiftRegSN74HC165N
- https://learn.sparkfun.com/tutorials/shift-registers
- https://learn.adafruit.com/adafruit-arduino-lesson-4-eight-leds/the-74hc595-shift-register
- http://www.electronics-tutorials.ws/sequential/seq_5.html
- http://www.arduino.cc/en/Tutorial/ShiftOut
These methods (with the exception of those utilizing the shiftIn() function) transfer easily to the ATtiny85. However, because it lacks sufficient IO pins and built-in SPI support, talking to more than one (non-daisy-chained) shift register at once is not so easy on the smaller chip.
The solution I found was to share a single clock line between the PISO and SIPO shift registers, with separate latch and data lines for each, holding the various enables and inhibits steady. While this approach has drawbacks, such as requiring firm temporal separation of input and output phases and the need to refresh the SIPO register for each output, it allowed me to easily control the two shift registers with only 5 pins.
As a first project, I chose to reproduce the setup demonstrated in Sparkfun's introductory Shift Register video, reading the state of an 8-position DIP switch with a 74HC165 and turning on a corresponding bank of 8 LEDs through a 74HC595.
Here's a photo of the setup (schematic forthcoming soon!):

And here's the code:
// 8xDIP --> 74HC165 --> ATtiny85 --> 74HC595 --> 8xLED
// ====================================================================================
// Updated 05May2015
// By C. Parkin
// 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(5);
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();
}
Worked like a charm!
Up next: adapting this setup (PATS: PISO --> ATtiny85 --> SIPO) to read bump switches and control motors for a simple mobile robot.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
anyone try this? I am not getting this to work?
maybe there are some schematics?
Are you sure? yes | no