Notifications
Clear all

Shift Register

19 Posts
3 Users
6 Reactions
466 Views
(@fordav1)
Member
Joined: 4 months ago
Posts: 5
Topic starter  
Hi Guys,
 
I have hooked up a 74HC165 to an Arduino to read the state of an 8-position dip switch and it works well using the code on this page...
 
My question is, can that be done with less GPIO used?
Can it be done somehow by setting one of the pins permanently low or high or through a pull-up or pull-down resistor? If yes please provide the code.
Note I want the actual state of the switches I don't want to use the shift function as that gives incorrect results showing (for example) SW1 as 2 when shifted.
Basically I need one more GPIO pin for my project and this may be the solution if I can get it to work.
Thanks.
 

   
Quote
(@davee)
Member
Joined: 3 years ago
Posts: 1859
 

Hi @fordav1,

  To begin with, sorry, I am not completely clear about what you are trying to do, so this reply will not be as clear and simple as either of us would like, but hopefully it will be a step in the right direction.

You say: "My question is, can that be done with less GPIO used?"

Let's make sure we are looking at the same sketch:

https://dronebotworkshop.com/shift-registers/ <... the section headed "Arduino & 74HC165 Hookup"

This shows Arduino with 4 connections (plus +5V and GND) to the 74HC165.

The connections being:

GPIO 4 --> HC165 Pin 15  CLK INH

GPIO 5 --> HC165 Pin 7    not_Qh

GPIO 6 --> HC165 Pin 2    CLK

GPIO 7 --> HC165 Pin 1    SH/not_LD

And the logic diagram for HC165 from

https://www.ti.com/document-viewer/SN74HC165/datasheet#pin_configuration_and_functions/SCLS1161064 looks like:

image

With regard to saving a GPIO pin, a first glance at the logic diagram suggests that HC165 pin 7 (not_Qh) and pin 1 (SH/not_LD) are fundamental to the operation, but Pin 15 (CLK_INH) and Pin 2 (CLK) are both responsible for producing the CLK transitions.

That is, if either Pin 15 or Pin 2 is held high, then, the effective CLK signal seen by the C1 inputs of the shift registers are also held high, and there are no CLK transitions. Hence, all of the time Pin 15 (CLK_INH) is held high, the CLK input on Pin 2 is ignored, but when Pin 15 is held low, then all of the CLK transitions are sent to the registers, and the load or shift operations will occur.

This two pin input arrangement can be useful in some circumstances, but if the signal sent to CLK input Pin 2 is carefully designed to only change level when the load or shift operation is required, then Arduino control of Pin 15 is redundant, and Pin 15 can be directly tied to GND (using a wire, it doesn't need a resistor).

-----------

Hence GPIO 4, is now free, and may be assigned to another purpose.

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

Please note, this assumes the library function called on line 46 (byteincoming=shiftIn(dataIn,clockIn,LSBFIRST) is the only code that can affect the CLK GPIO 6 output, which appears to be the case, but I have not explicitly checked.

---------

 Then, the lines in the sketch referring to GPIO 4 can be deleted (from sketch "74HC165 Shift Register Demonstration 1". At first glance, (again not confirmed by testing), the lines to be deleted would be:

lines 14-15:

  // CE pin 15
  int clockEnablePin = 4;


line 29:

  pinMode(clockEnablePin, OUTPUT);

line 45:

  digitalWrite(clockEnablePin, LOW);


line 47:

  digitalWrite(clockEnablePin, HIGH);

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

However, all of the above ignores your other statement:

Note I want the actual state of the switches I don't want to use the shift function as that gives incorrect results showing (for example) SW1 as 2 when shifted.

Sorry, I don't understand this statement.

Best wishes, Dave

 


   
Ron reacted
ReplyQuote
(@fordav1)
Member
Joined: 4 months ago
Posts: 5
Topic starter  

Yes the sketch I'm referring to is the one about the 165 hookup at the link I posted, section titled "Arduino & 74HC165 Hookup".

Some more info...
When hooked up to an 8 position dip swtich block in the same manner as the diagram on that page (with pullup resistors but a dip switch instead of separate push buttons),  the script on that page will show a binary number. Initially with all switches off it shows 0 since all are pulled high. When moving each switch in order from sw1 to sw8 it will show....

10000000

11000000

11100000

11110000

11111000

11111100

11111110

11111111

This is correct behavour.

 

That 'carefully designed' part is the secret sauce I'm looking for. If it wasn't obvious I'm not a programmer. I know the basics of what's going on and can mostly understand it but I'm not capable of writing anything in a c-like language from scratch. I know Commodore 64 BASIC and Turbo PASCAL but that's doesn't help here 😉

This is part of a *much* bigger PCB project that actually works using a Pi pico but it's using 8 GPIO lines to read the switches and I want to use less. It works with 4 GPIO using a 165 but I want less 😉

I'm using an Arduino simply because this is available here for quick prototype testing of the chip and switches and I'm not the person writing the pico code, I'm the person doing the hardware design. I'd post a pic of the design fully routed etc but well, I'm considered scum at this stage and attachments are not allowed.

Consider my other work if you want to see I'm very serious about this and I'm definitely not random internet scum.

removed link

removed link eagle/

removed link re/

 

(Admin: Might be nice if there was way to turn off the double-line spacing so a keyboard ENTER does not equal linefeed+carriage return+carriage-return ?)

 

Anyway...

With this code in the script (lines 43-47 and the clockEnablePin lines disabled)...

  // Get data from 74HC165
  digitalWrite(clockIn, HIGH);
  //digitalWrite(clockEnablePin, LOW);
  byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
  //digitalWrite(clockEnablePin, HIGH);

and the actual HC165 pin 15 tied LOW on the chip the output is only partially working.

Dip switches 1-7 respond correctly while dip switch 8 does nothing.

So that approach does not work. At least not with the above code.

If I change the above code to this...

digitalWrite(clockIn, HIGH);
byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
digitalWrite(clockIn, LOW);

and again with the 165 pin 15 tied to ground, the output is exactly the same. sw1-7 respond like normal but sw8 does nothing and has no effect on the output.

I read the 165 datasheet and it does suggest that either clock or clockenh can be tied high or low as required and the other pin used to fetch the data but it doesn't appear to work in the load mode. In the shift mode (with load high) it may perform that function but I don't want to shift anything.

I'm beginning to think it's simply not possible to control the HC165 with less than 4 "active" pins and have all the switches read correctly.

 


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1859
 

Hi @fordav1,

  To start with, I, and I am sure the other genuine forum members, do not think you are 'scum', but unfortunately there are some on the web who seem to get a thrill by abusing the efforts of others, and hence the generous and altruistic website host, Bill (AKA @dronebot-workshop) has had to impose some limitations for newcomers. However, these only apply to the first few posts by the newcomer, so just keep in touch by posting more notes, and the 'shackles' should magically disappear.

As I indicated, I haven't actually tried to repeat your experiment, and from (bitter) personal experience, I know it is not unusual to be caught out by any number of things, like a simple oversight, a mistake, and so on.

However, I seem to have some chips with 74HC165 markings in the 'spares' box, so I'll try to find some time in the next few days to duplicate your experiment, and hope to come back to you with an update of my findings.

Best wishes, Dave


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7642
 

@fordav1 FYI @davee Here is a circuit that uses only 3, the 4th is tied to G.

https://www.woolseyworkshop.com/2021/02/18/adding-digital-io-to-your-arduino-part-2-the-74hc165/#BuildingTheCircuit

and

https://www.rs-online.com/designspark/basics-of-74hc165

Both are 3 pin solutions.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7642
 

@davee FYI @foedav1 I also found this. It's a bit above my level of knowledge, but if I had to could probably decode it. Dave may have something to say I hope.

https://www.romanblack.com/shift1.htm

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1859
 

Hi Ron @zander,

  Thanks for those links on 74HC165.

  The Woolsey Workshop one appears to confirm my suggestion.

  The Design Spark/ THE ENGINEERING PROJECTS one still uses 4 pins, so not achieving th epin release required .. it is just drawn differently, with the 4th wire above the board.

  The Roman Black one, I would tend to avoid recommending, although it can probably be 'made to work'. It depends on getting sensible RC values, and matching them to the software timing. This will usually be possible provided the implementer has an oscilloscope, a 'fixed' software programme (so that the timing between steps does not change ... roughly analogous to code with time-wasting loops, to achieve timing, that plagued many early embedded microprocessor designs), a range of resistors and capacitors in the spares box, and a reasonable idea of how to do it, but far from a robust solution that 'just works'.

Best wishes, Dave


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7642
 

@davee Happy to help although I am not that conversant in this stuff.

BTW, the Design Spark article only has a description, NO diagram, I think the diagram you looked at was the 'also' look at this link which is a different idea. I have pics of both.

Since I am not conversant in this stuff, I may be wrong, but I only count 3 pins in addition to the 8 data pins and the 2 power pins.

Screenshot 2024 06 17 at 14.53.12
Screenshot 2024 06 17 at 14.53.31

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1859
 

Hi Ron  @zander,

  Re: the DesignSpark, the list you show includes both CLK INH and CLK. My suggestion is that one of these two can be connected to ground, thereby freeing an Arduino pin. I didn't see any mention of this concept. The list misses the SH/not_LD pin, that will need to be controlled for most (probably all) applications.

 Plus, I was a bit confused about how the page itself was useful, as it only provided a list of pins and doesn't provide a circuit, so I assumed the reference included the second page found by clicking the link. This page shows both CLK INH and CLK being connected to respective GPIO pins.

Best wishes, Dave


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7642
 

@davee Sorry for infecting you with my confusion virus. I did see a better diagram, but maybe I forget to clip it. One pin was connected to ground, but I have yet to see a circuit with less than 3. I do know if anyone can make that work it will be you, so I will patiently wait for your solution.

I just found it. It was the Woolsey. PL to 3, CP to 4, Q7 to 2. 8 data pins and VCC , Gnd. DS and CE are grounded.

My gut says what should work is 2 power, 8 data, a clock and an enable, no idea why one more is needed but as I said, I am verrrrrrrry rusty on this stuff.

Looking forward to your solution Dave.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1859
 

Hi Ron @zander,

 As I previously said, the Woolsey diagram matched my suggestion, which was a useful confirmation of my analysis.

It needs three control lines, not just two, because the shift register has two different actions.

  1. LOAD 8 switch voltages (high or low) into the 8 shift register bits in a single parallel clocked operation
  2. SHIFT the data value (high or low) of each register, into the register to its 'right' (in the logic diagram I snipped in a post above).

The '3rd' control pin labelled LD/not_SH

(where "not_" is actually a bar over SH) 

image

 Is used to decide whether the rising edge of the CLK signal performs the "LOAD" operation, or the "SHIFT" operation.

--------

Depending upon the surrounding circuit's requirements, I might expect typical sequences to be:

  1. With CLK HIGH, Set SH/not_LD LOW
  2. Pulse CLK LOW, then return to HIGH     # This will load the switch levels into all 8 register bits
  3. Set SH/not_LD HIGH
  4. Pulse CLK LOW, then return to HIGH     # This will shift the data to the next adjacent register
  5. Repeat steps 3. and 4. a further 6 or 7 times
  6. Restart sequence at 1., if the switches are to be continuously monitored.

This needs a minimum of three pins.

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

If the drive to the CLK pin cleanly follows the sequence, with transitions only occurring at the right times, there should not be a need for a clock enable pin. I would hope the output from Arduino pins, with appropriate software, would meet this criteria.

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

I presume the 165 logic was designed (in the late 1960s/early 1970s), (as SN74165/SN54165), when microprocessors were still being invented, and a CLK enable pin would have been useful in an 'mulitple 74 logic chip' circuit, with many chips got the same CLK signal, and the CLK enable signal was used to control which register chips were active on each specific clock pulse. (This is a basic synchronous design method, which aims to minimise timing problems.)

Hope this trip into the past helps.

Best wishes, Dave


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7642
 

@davee Great explainer Dave, and SHORT too. I think I understand, like I said rusty but with your explanation some of it is starting to come back.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
DaveE reacted
ReplyQuote
(@fordav1)
Member
Joined: 4 months ago
Posts: 5
Topic starter  

As previously mentioned I tied CLKINH to ground and toggled CLK high then low with a shift in between like this...

digitalWrite(clockIn, HIGH);
byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
digitalWrite(clockIn, LOW);

The code is running in a loop so any dip switch that is changed shows immediately on the screen serial console output.

It almost works but the 8th dip switch does nothing when toggled.

 

The datasheet has a paragraph that is unclear...

 

*****

These registers also feature gated clock (CLK) inputs and complementary outputs from the eighth bit. All inputs are diode-clamped to minimize transmission-line effects, thereby simplifying system design.
Clocking is accomplished through a two-input positive-NOR gate, permitting one input to be used as a clock-inhibit function. Holding either of the clock inputs high inhibits clocking, and holding either clock input low with SH/LD high enables the other clock input. Clock inhibit (CLK INH) should be changed to the high level only while CLK is high. Parallel loading is inhibited as long as SH/LD is high. Data at the parallel inputs are loaded directly into the register while SH/LD is low, independently of the levels of CLK, CLK INH, or serial (SER) inp

*****

 

"Complementary outputs from the eighth bit". Perhaps that is what is happening here, where the eighth bit remains at 0? There's a lot of holding clocks high or low to enable/disable things so it seems there are multiple way to make it work. Plus the part about data being loaded directly into the register when SH/LD is low, independent of the level of CLK or CLKINH. Yet if CLK and CLKINH is not used the chip does nothing. The whole thing seems to contradict itself several times heh!

 

 


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1859
 

Hi @fordav1,

  As I promised a few days ago, I have now had time to build a copy of Bill (@dronebot-workshop)'s demonstration

(the Arduino & 74HC165 Hookup section in the blog https://dronebotworkshop.com/shift-registers/),

with the significant circuit change that the CLK INH pin is simply connected to ground, thereby freeing up a GPIO pin.

However, as you discovered, Bill's sketch software used that pin to effectively prevent a shift clock pulse 'losing' the first bit.

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

Before proceeding, I should note that I have had more time to check the operation of the 74HC165, and I have discovered I made an error in my explanation to Ron (@zander) above. Most of what I said was valid, but I missed one point, namely the LOAD operation is independent of the clock, rather than synchronised by the clock. The shift operation is synchronised by the clock as I described. Hopefully, the explanation below is correct.

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

The problem with using Bill's code without modification is hidden in the definition of the shiftIn function, that is called in line 46

  digitalWrite(clockEnablePin, LOW);
  byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
  digitalWrite(clockEnablePin, HIGH);

The 74HC165, as wired in this sketch, effectively requires the 'grab data bit into the Arduino' and 'send CLK pulse'from the Arduino' to be done in a different order to that coded in the shiftIn function. The order required must match the following sequence.

  1. Parallel load the data from the switches into the shift register. This only needs a low going pulse on the SH/not_LD pin.  It does not need any clock pulses.
  2. After the short  propagation delay through the74HC165, typically 10s of nanoseconds, the data from Switch '7' appears at the Qh and not_Qh outputs.
  3. Grab the data bit from not_Qh output, into the Arduino.
  4. Send High going pulse to CLK input from Arduino, to shift the bits in the shift register, by one bit towards the register with the Qh & not_Qh outputs.
  5. If this is the eighth time through this step, then exit, else Go back to Step 2, bearing in mind the new data appearing at the Qh and not_Qh will be the data just shifted from the adjacent shift register, instead of the data from Switch '7'

 

I have made several changes to' Bill's sketch. I attempted to show it in this message, but that produced an empty post, so I am attaching the file.

Points to note:

  1. I used an ESP8266 instead of an Arduino, so the GPIO port numbers will need to be modified to match the microcontroller you are using. (lines 1-30)
  2. I added some code to produce an oscilloscope trigger for debugging. The extra lines for this have #ifdef wrappers, so as supplied, with the #define SCOPE_DEBUG commented out, the compiler will totally ignore the extra lines. They can of course be deleted as well .... just match the #ifdef and #endif s like brackets. I hope it is not too confusing.
  3. function loadByte, loads the data bits from the switches, into the shift register.
  4. function readByte is the replacement for shiftIn. The actual code is fairly similar, to keep the same functionality principle.
  5. byteToString is a simple function to create a string equivalent to incoming byte in binary, which always shows all 8 bits. The Serial.print function removes leading zeroes, which I found irritating.

 

I hope it will now work.

Best wishes, Dave


   
Ron reacted
ReplyQuote
(@fordav1)
Member
Joined: 4 months ago
Posts: 5
Topic starter  

WOW!! It works now with only 3 GPIO pins connected. Thanks Dave, you are a true master 🙂

One small thing. My hookup is dipsw1 to A, dipsw2 to B..... dipsw8 to H.

I'm not even sure if that's how it should be connected. I assumed A is the LSB but the output is backwards. I quickly scanned through the 165 datasheet and I didn't see any mention of which pin is the LSB pin? 

Normally (at least in my arcade world) binary numbers are read from right to left, so 10010010 is 2+16+128 = 146.

Where 2=dipsw2, 16=dipsw5, 128=dipsw8

The display shows 128 when dipsw1 is on and I want it to show dipsw1 = 1, dipsw2=2, dipsw3=4, dipsw4=8, dipsw5=16, dipsw6=32, dipsw7=64, dipsw8=128

It is possible to reverse it in the code so my dipsw1 shows 1?

In the other version I just changed LSB to MSB and it worked but this new version isn't as simple.

Thanks.

 

 


   
ReplyQuote
Page 1 / 2