2015/06/22

How to use shift register (74HC165)

Below is an example on how to use 74HC165 shift register with Arduino Uno. I made this post to record my findings while following Sparkfun's tutorial on shift registers.

The Sparkfun tutorial website on shift registers is here: https://learn.sparkfun.com/tutorials/shift-registers

Wiring Diagram:


Waveform:

This is taken from the 74HC165 datasheet, observe that !PL needs to be LOW for certain time period.


Observe that "tw" is the time period that !PL must remain LOW.


The minimum tw is 120ns (0.12ms). In the program, we add 5ms delay by putting "delayMicroseconds(5);" after pulling !PL to LOW "(digitalWrite(shld_pin, LOW);" to ensure this requirement is met.


The Code:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// HARDWARE CONNECTIONS
// Connect the following pins between your Arduino and the 74HC165 chip
// Connect pins D7 - D0 to 5V or GND or switches or whatever

const int data_pin = 11; // Connect Pin 11 to SER_OUT (serial data out) - Pin 9 (Q7) of 74HC165
const int shld_pin = 8;  // Connect Pin 8 to SH/!LD (shift or active low load) - Pin 1 (!PL) of 74HC165
const int clk_pin = 12;  // Connect Pin 12 to CLK (the clock that times the shifting) - Pin 2 (CP) of 74HC165
const int ce_pin = 9;    // Connect Pin 9 to !CE (clock enable, active low) - Pin 15 (!CE) of 74HC165

byte incoming; // Variable to store the 8 values loaded from the shift register

// The part that runs once

void setup() {                
  // Initialize serial to gain the power to obtain relevant information, 9600 baud
  Serial.begin(9600);

  // Initialize each digital pin to either output or input
  // We are commanding the shift register with each pin with the exception of the serial
  // data we get back on the data_pin line.
  pinMode(shld_pin, OUTPUT);
  pinMode(ce_pin, OUTPUT);
  pinMode(clk_pin, OUTPUT);
  pinMode(data_pin, INPUT);

  // Required initial states of these two pins according to the datasheet timing diagram
  digitalWrite(clk_pin, HIGH);
  digitalWrite(shld_pin, HIGH);
}

// The part that runs to infinity and beyond

void loop() {
  incoming = read_shift_regs(); // Read the shift register, it likes that

  // Print out the values being read from the shift register
  Serial.println("\nThe incoming values of the shift register are: ");
  Serial.println("D7 D6 D5 D4 D3 D2 D1 D0:");
  print_byte(incoming); // Print every 1 and 0 that correlates with 8 through 1 of the dip switch

  //Serial.println(incoming, BIN); // **This way works too but leaves out the leading zeros**
  delay(2000); // Wait for some arbitrary amount of time
}

// This code is intended to trigger the shift register to grab values from its D7 - D0 inputs

byte read_shift_regs(){

  byte the_shifted = 0;  // An 8 bit number to carry each bit value of D7 - D0

  // Trigger loading the state of the A-H data lines into the shift register
  digitalWrite(shld_pin, LOW);
  delayMicroseconds(5); // Requires a delay here according to the datasheet timing diagram
  digitalWrite(shld_pin, HIGH);
  delayMicroseconds(5);

  // Required initial states of these two pins according to the datasheet timing diagram
  digitalWrite(clk_pin, HIGH);
  digitalWrite(ce_pin, LOW); // Enable the clock

  // Get D7 ~ D0 values
  // The function shiftIn() shifts in a byte (8-bit) of data one bit at a time staring from either the most (leftmost) or the least (rightmost) significant bit.

  the_shifted = shiftIn(data_pin, clk_pin, MSBFIRST);
  digitalWrite(ce_pin, HIGH); // Disable the clock

  return the_shifted;
}

void print_byte(byte val){
// This part is a bit different from the Sparkfun code.
// Reference:  The Quick Reference section of Bit Math Tutorial http://playground.arduino.cc/Code/BitMath on how to isolate individual bit.

      Serial.print(val >> 7 & 1, BIN); // print 7th bit of val
      Serial.print("  ");
      Serial.print(val >> 6 & 1, BIN); // print 6th bit of val
      Serial.print("  ");
      Serial.print(val >> 5 & 1, BIN); // print 5th bit of val
      Serial.print("  ");
      Serial.print(val >> 4 & 1, BIN); // print 4th bit of val
      Serial.print("  ");
      Serial.print(val >> 3 & 1, BIN); // print 3th bit of val
      Serial.print("  ");
      Serial.print(val >> 2 & 1, BIN); // print 2th bit of val
      Serial.print("  ");
      Serial.print(val >> 1 & 1, BIN); // print 1th bit of val
      Serial.print("  ");
      Serial.println(val >> 0 & 1, BIN); // print 0th bit of val 

// the above code can be written as follow

      //int i;
      for (int i = 8; i > 0; i--){
          Serial.print(val >> (i - 1) & 1, BIN);
          Serial.print("  ");
      }
      Serial.print("\n");  
}

The Result:


Note:

D7 ~ D0 are corresponding to the pinout of 74HC165, not the label on the dip switch.

References:

- Arduino - print(), http://www.arduino.cc/en/Serial/Print
- Arduino - bitshift right (>>), http://www.arduino.cc/en/Reference/Bitshift
- Arduino - bitwise AND (&), http://www.arduino.cc/en/Reference/BitwiseAnd
- 74HC165 datasheet - http://www.nxp.com/documents/data_sheet/74HC_HCT165.pdf

--------------------------------------------------------------------------------------------------------------------------

Working with ESP8266 and 74HC165 on 3.3V

The section below is added on Jan. 17, 2020 to show how to interface ESP8266 (WeMos D1 Mini) with 74HC165 and have them working on 3.3V.

The Schematic


The Code

It's basically the same as the one above with minor changes to the pin assignment.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
// HARDWARE CONNECTIONS
// Connect the following pins between your Arduino and the 74HC165 chip
// Connect pins D7 - D0 to 5V or GND or switches or whatever

const int data_pin = 4; // Connect WeMos D1 Mini D2 pin (GPIO4) to SER_OUT (serial data out) - Pin 9 (Q7) of 74HC165
const int shld_pin = 2; // Connect WeMos D1 Mini D4 pin (GPIO2) to SH/!LD (shift or active low load) - Pin 1 (!PL) of 74HC165
const int clk_pin = 5;  // Connect WeMos D1 Mini D1 pin (GPIO5) to CLK (the clock that times the shifting) - Pin 2 (CP) of 74HC165
const int ce_pin = 0;   // Connect WeMos D1 Mini D3 (GPIO0) to !CE (clock enable, active low) - Pin 15 (!CE) of 74HC165

byte incoming;          // Variable to store the 8 values loaded from the shift register

// The code below triggers the shift register to grab values from its D7 - D0 inputs
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
byte read_shift_regs(){

  byte the_shifted = 0;  // An 8-bit number to carry each bit value of D7 - D0

  // Trigger loading the state of the A-H data lines into the shift register

  digitalWrite(shld_pin, LOW);
  delayMicroseconds(5); // Requires a delay here according to the datasheet timing diagram
  digitalWrite(shld_pin, HIGH);
  delayMicroseconds(5);

  // Required initial states of these two pins according to the datasheet timing diagram

  digitalWrite(clk_pin, HIGH);
  digitalWrite(ce_pin, LOW); // Enable the clock

  // Get D7 ~ D0 values
  // The function shiftIn() shifts in a byte (8-bit) of data one bit at a time staring from either the most (leftmost) or the least (rightmost) significant bit.
  
  the_shifted = shiftIn(data_pin, clk_pin, MSBFIRST);
  digitalWrite(ce_pin, HIGH); // Disable the clock

  return the_shifted;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void print_byte(byte val){

// This part is a bit different from the Sparkfun code.
// Reference:  The Quick Reference section of Bit Math Tutorial http://playground.arduino.cc/Code/BitMath on how to isolate individual bit.

      /*
      Serial.print(val >> 7 & 1, BIN); // print 7th bit of val
      Serial.print("  ");
      Serial.print(val >> 6 & 1, BIN); // print 6th bit of val
      Serial.print("  ");
      Serial.print(val >> 5 & 1, BIN); // print 5th bit of val
      Serial.print("  ");
      Serial.print(val >> 4 & 1, BIN); // print 4th bit of val
      Serial.print("  ");
      Serial.print(val >> 3 & 1, BIN); // print 3th bit of val
      Serial.print("  ");
      Serial.print(val >> 2 & 1, BIN); // print 2th bit of val
      Serial.print("  ");
      Serial.print(val >> 1 & 1, BIN); // print 1th bit of val
      Serial.print("  ");
      Serial.println(val >> 0 & 1, BIN); // print 0th bit of val
      */

// the above code can be written as follow
      
      //int i;
      for (int i = 8; i > 0; i--) {
          Serial.print(val >> (i - 1) & 1, BIN);
          Serial.print("  ");
        }
      Serial.print("\n");  
}

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

  // Initialize each digital pin to either output or input
  // We are commanding the shift register with each pin with the exception of the serial
  // data we get back on the data_pin line.

  pinMode(shld_pin, OUTPUT);
  pinMode(ce_pin, OUTPUT);
  pinMode(clk_pin, OUTPUT);
  pinMode(data_pin, INPUT);

  // Initialize the below two pins according to the datasheet timing diagram
  digitalWrite(clk_pin, HIGH);
  digitalWrite(shld_pin, HIGH);
}

void loop(){

  incoming = read_shift_regs(); // Read the shift register, it likes that

  // Print out the values being read from the shift register

  Serial.println("\nThe incoming values of the shift register are: ");
  Serial.println("D7 D6 D5 D4 D3 D2 D1 D0:");
  print_byte(incoming); // Print every 1 and 0 that correlates with 8 through 1 of the dip switch
  
  //Serial.println(incoming, BIN); // **This way works too but leaves out the leading zeros**

  delay(2000); // Wait for some arbitrary amount of time
}

The Result