A good circuit for a large number of push button inputs?

You basically listed them all.

  1. A Matrix of x rows and y columns. You need x+y pins.

    Matrix

  2. Digital GPIO Expander IC, preferably with interrupt. I2C, SPI, even Serial are available. Interrupt pins allow you to read on interrupt instead of polling. You need to have hardware I2C/SPI/UART, or add software code. This approach is mainly used if you need a lot more GPIO than you have available on the main microcontroller. At that point, you are basically still using options 1, 3, and 4, or the direct one button per pin.

  3. Resistor Ladder. You need an ADC, and constant polling. Better to break up into a few similar groups on multiple ADC channels, but you can make a large 20 button one if you really need to.

    enter image description here

  4. Charlieplexing. Like a multiplexed matrix (#1), but with \$N \times (N – 1)\$ where \$N\$ is the number of pins used. Requires as many diodes as buttons, so you are changing pin count for diodes. You could use LEDs though.

enter image description here

For the most part, #1 is the most common method. Every keyboard or touch tone phone you have ever used, 1000 to 1, would have used it. Hell, even cell phones use it (specifically, the Nokia 5110 I know uses it.) For 20 buttons, a 4x5 matrix will only take 9 pins, more than enough.


Texas Instruments makes an i2C keypad encoder. Surface mount. It doesn't get much simpler than that.


An IC that'll make the job easy?

Definitely.

The LM8330 I/O - Expander and Keypad Controller is a dedicated device designed to unburden a host processor from scanning a matrix-addressed keypad and to provide flexible and general purpose, host programmable input/output functions. Three independent Pulse Width Modulation (PWM) timer outputs are provided for dynamic LED brightness modulation.

It communicates with a host processor through an I2C-compatible ACCESS.bus serial interface. It can communicate in Standard (100 kHz) and Fast-Mode (400 kHz) in slave Mode only.

With this you can probably get away with using a ATtinyX5 instead of a ATmega.