Electronic – Multiplexing vs shift registers (input)


I'm going to use a microcontroller to read 80 digital inputs (push button switches).
I'm wondering (just to understand, I don't have any critical time constraint) if it would take less time using multiplexing over a 9*9 matrix (but using one shift register on the rows to reduce used pins on the uC, and columns directly connected to the uC) or using 10x chained shift registers (74HC165).
I'm having hard time calculting that, so I'm asking for some clarification. Also, how does that change if I use SPI.
Other assumptions:
– uC: arduino uno
– I'd like to consider also the time needed in software to provide the data in a "clean" format.

Best Answer

There are so many possibilities I don't even know where to begin.

It all depends on two things: button wiring and availability of the MCU pins. You mentioned "push button switches" first, then "9*9 matrix". If you have matrix keyboard with built-in diodes it is one thing, if you have discrete push buttons that you planning on assembling into matrix it is completely different.

Keep in mind that physical button arrangement has nothing to do with electrical wiring. For example, a single 16 bit 74LS674 shift register needs only 5 additional wires to read all 80 buttons. The buttons can be placed 9x9, 4x20 etc.

Anyway, here are just some options out of many.

  • For matrix with diodes you can actually use both, multiplexor for columns and shift register on rows. This will reduce required number of pins even more.

  • You can also use BCD to decimal decoder like HCF4028B instead of multiplexor.

  • You can use two I2C or SPI mux-demux chips. This will reduce the number of required IO pins down to only 2, but will increase polling time a lot.

  • You can use a single ADG725 chip. It has two 16 bit muxes, so you can use one for columns and the other one for rows. This option has extremely easy wiring.

  • If you do not wire your buttons into matrix, you can use a chain of 9 shift registers as in your question. Or you can use 3 ADG731 chips, each is 32 bit mux.

Now, regarding processing time. The shift registers require clocking for reading data. In this regard they are slower than muxes or decoders with binary address input. However the later require you to switch between all addresses to get one reading, so in the end they are slightly slower. The chips with I2C or SPI control will be slower still.

However the differences between the chips do not define the processing time, because they are negligible when compared with the timings of human interaction. The defining factor is system latency and the shortest button pressed time you want to detect. In all the schematics above (and in your question) you need very frequent polling by MCU. It is not the best use of MCU time, really.

You did not specify in the question whether your MCU is supposed to do something between presses, or it should only react when button pressed. In the former case MCU can constantly poll the matrix. It has nothing else to do anyway. In the latter you need something better.

So, here is one trick you can use to minimize the reaction time without polling constantly:

  • Use output shift register like 74HC595 on the columns. This would allow you to power up several columns simultaneously, something that muxes or decoders cannot do.
  • Use input shift register like 74HC165 on the rows.
  • Also connect all rows via diodes into single line wired to separate GPIO.
  • Introduce "waiting mode" in you code. In this mode all output lines are high, so pressing any button will result in signal on one of the rows. And consequently, this will produce a signal on that additional line combining the rows.
  • Program that pin for interrupt. This would free entire MCU time for your other needs. When interrupt triggers, it will assert boolean flag telling your main loop that button should be processed. Then you main loop can pause what it was doing, perform some debouncing and use shift registers to figure out which button is pressed. When button released debounce again and de-assert the flag to return to waiting mode.

Note, that the above trick can be used with non-matrixed keyboard as well. Only instead of combining rows you will be combining all the buttons into one interrupt line.

In short - there are almost too many options available to you. Figure out the required latency of the system and how many pins you can spare, this will narrow it down.