Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: SN74HC165 shift register revisited

  1. #1
    Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    70

    SN74HC165 shift register revisited

    The SN74HC165 shift register makes it easy to add digital input to a Teensy/Arduino. On the Arduino playground a description can be found: SN74HC165N, a Sparkfun tutorial relies on the same approach.
    It always seemed strange to me that shifting in would require 4 wires, whereas shifting out can make do with three. Turns out that you only need three wires, the clock inhibit is superfluous. The tutorial mentioned refer to the timing diagram:

    Click image for larger version. 

Name:	sequence.png 
Views:	19 
Size:	67.8 KB 
ID:	12398

    The way I interpret the datasheet this diagram refers to the case where there's a continuously running clock, not when you have full control over the clock. Also in the datasheet is an example of a typical application with a microcontroller:

    Click image for larger version. 

Name:	typicalApplication.png 
Views:	26 
Size:	76.0 KB 
ID:	12399

    In this example the clock inhibit (pin 15) is connected to ground and just three wires are used.

    The tutorials also make use of delay() statements for timing purposes.

    Code:
    /* Width of pulse to trigger the shift register to read and latch.
    */
    #define PULSE_WIDTH_USEC   5
    
    
    BYTES_VAL_T read_shift_regs()
    {
        long bitVal;
        BYTES_VAL_T bytesVal = 0;
    
        /* Trigger a parallel Load to latch the state of the data lines,
        */
        digitalWrite(clockEnablePin, HIGH);
        digitalWrite(ploadPin, LOW);
        delayMicroseconds(PULSE_WIDTH_USEC);
        digitalWrite(ploadPin, HIGH);
        digitalWrite(clockEnablePin, LOW);
    
        /* Loop to read each bit value from the serial out line
         * of the SN74HC165N.
        */
        for(int i = 0; i < DATA_WIDTH; i++)
        {
            bitVal = digitalRead(dataPin);
    
            /* Set the corresponding bit in bytesVal.
            */
            bytesVal |= (bitVal << ((DATA_WIDTH-1) - i));
    
            /* Pulse the Clock (rising edge shifts the next bit).
            */
            digitalWrite(clockPin, HIGH);
            delayMicroseconds(PULSE_WIDTH_USEC);
            digitalWrite(clockPin, LOW);
        }
    
        return(bytesVal);
    }
    Using an oscilloscope I performed some tests to see whether the delay is actually required. The test setup (alle delay statements removed and clock inhibit connected to ground) is shown in the following picture:

    Click image for larger version. 

Name:	shift-test-setup.jpg 
Views:	28 
Size:	158.7 KB 
ID:	12400

    The stripboard contains four 74HC165 shift registers for the buttons and three 74HC595 shift registers for the leds, the other buttons are on two separate boards. Alle the IC sockets have 100nF decoupling caps build in. A Teensy 3.6 is mounted on a Tall Dog extension board, it is mounted on its side for easy access to all the pins.
    I'm no electrical engineer but this looks like a decent clock pulse to me. Here's a screenprint showing the clock measured at the last IC in the chain:

    Click image for larger version. 

Name:	shift-wave-last.png 
Views:	23 
Size:	28.5 KB 
ID:	12401

    The clock frequency is just over 2MHz, pulse width is about 175ns. From the datasheet:

    Click image for larger version. 

Name:	timing.png 
Views:	25 
Size:	65.3 KB 
ID:	12402

    Worst case is a maximum of 6MHz and a minimum pulse width of 80ns so we're well in the clear. No need for any delays in the code.

    The code running in the test:
    Code:
    unsigned long readShiftRegisters()
    {
        int bitVal;
        unsigned long bytesVal = 0;
        // Trigger a parallel Load to latch the state of the data lines
        digitalWrite(ploadPin, LOW);
        digitalWrite(ploadPin, HIGH);
        // Loop to read each bit value from the serial out line of the SN74HC165N.
        for(int i = 0; i < DATA_WIDTH; i++)
        {
            bitVal = digitalRead(dataPin);
            // Set the corresponding bit in bytesVal.
            bytesVal |= (bitVal << ((DATA_WIDTH-1) - i));
            // Pulse the Clock (rising edge shifts the next bit).
            digitalWrite(clockPin, HIGH);
            digitalWrite(clockPin, LOW);
        }
        return(bytesVal);
    }

    Kind regards,

    Gerrit

  2. #2
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    1,153
    What you are doing looks basically like a bit-banging emulation of a slow ancestor of the SPI bus. Great to see that it works!

  3. #3
    Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    70
    Quote Originally Posted by Theremingenieur View Post
    What you are doing looks basically like a bit-banging emulation of a slow ancestor of the SPI bus. Great to see that it works!
    I had a look at the SPI library documentation, it seems this is intended for more specialised applications. Using shift registers this way is really easy as there is no protocol overhead and all buttons can be debounced simultaneously.
    While browsing the libraries I found a similar case of clock ringing mentioned in the OctoWS2811 documentation so I thought I'd try a putting a series resistor in the clock line. I started with 220Ω and and then tried 100Ω. The resistor is mounted on the cable connector at the Teensy side.

    Click image for larger version. 

Name:	clock-100ohm-220ohm.jpg 
Views:	14 
Size:	57.3 KB 
ID:	12423

    220Ω is a bit too much, the corners are rounded off and the rise time increases, 100Ω is just fine. The little blips in front of the first pulse are the result of crosstalk from the parallel load line, adding a series resistor cleans it up a little. Here's a before-after comparison of the clock signal without any series resistors and with 100Ω series resistors in the clock an parallel load lines:

    Click image for larger version. 

Name:	shift-wave-before-after.jpg 
Views:	11 
Size:	58.8 KB 
ID:	12424

    I'm quite satisfied with this result. A nice, clean clock signal and 32 buttons scanned in about 15Ás.

    Kind regards,

    Gerrit

  4. #4
    Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    70
    The finished button panel:

    Click image for larger version. 

Name:	button-panel-board.jpg 
Views:	27 
Size:	156.1 KB 
ID:	12461

    Real old school wiring, it looks a little messy but remember that with shift registers the high frequency clock and data signals are confined to the ICs so there's no risk of RF interference. This is about as far as I'd go without designing a PCB but at least when using strip board like this it is easy to get exact dimensions for a front panel design by counting holes. Mounted on the front panel it look like this:

    Click image for larger version. 

Name:	button-panel.jpg 
Views:	20 
Size:	112.2 KB 
ID:	12462

    The board is mounted on 8 M3 threaded standoffs on the back of the frontpanel, fortunately the measurements were correct so all the buttons are perfectly aligned In case you're wondering, this is part of a DAW (Digital Audio Workstation) plugin controller project I'm working on.

    Kind regards,

    Gerrit

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,227
    Looks good!

    Wonder if you could use the Arduino function shiftin (https://www.arduino.cc/reference/en/...ed-io/shiftin/)
    To do each byte... But since you already have it working...

  6. #6
    Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    70
    Quote Originally Posted by KurtE View Post
    Looks good!

    Wonder if you could use the Arduino function shiftin (https://www.arduino.cc/reference/en/...ed-io/shiftin/)
    To do each byte... But since you already have it working...
    Thanks.

    I thought about using shiftIn() but, as you said, it's working now and there's still a lot to do. When my project is finished I'll take another look at this, it could well be that shiftIn() is faster.
    In the meantime I've got to the point where all the buttons and leds are operational with the DAW software (Logic Pro X).

    Kind regards,

    Gerrit

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •