Oli gave a good answer, but wait, mine will be better! :-)
Oli commented on the limited current from the coin cell, and that's indeed something to keep an eye on. This CR2430 cell gives 5 mA as maximum continuous. Let's see if we can manage that.
It's a good thing that you only need one LED on at a time, otherwise I would even consider the coin cell. This looks like a nice LED: typically 15 mcd at 2 mA.
Oli went for a SIPO (Serial-In, Parallel-Out) shift register for the LEDs and a PISO (Parallel-In, Serial Out) for the buttons. That saves you a lot of I/O but costs extra components. Can't we use the I/O of a microcontroller directly? 22 LEDs and 8 buttons is 30 I/Os, no problem, but we can do it a bit cheaper if we multiplex the LEDs in a 4 x 5 matrix. Normally this would decrease the LEDs luminosity by 75 %, but since we only have to light one LED at a time we can select one row and one column statically. So we need 4 + 5 + 8 = 17 I/Os.
Usual suspects for a microcontroller are Atmel AVR and Microchop PIC. Usually I'd avoid PIC for LED driving because it can't source or sink 20 mA, but we have a low LED current so no problem. PIC is also cheaper than AVR. The PIC16F57 has 20 I/Os, so that's enough. The datasheet says 22.5 µA maximum for a 32.768 kHz clock at 2 V, so at 3 V that still will be below 50 µA.
That's it. A microcontroller, a cheap crystal, 22 LEDs, 8 buttons, and 12 resistors (4 for the LEDs and 8 for the buttons. The PIC16F57 doesn't seem to have internal pull-ups). No shift registers needed.
Some controllers can write to their own program flash under software control; others cannot. If you need to use a secondary processor to program the primary one, it's really not much different from any other task that requires willing certain pins in certain sequences with certain timing constraints. The one biggest thing to look for is that some parts can be programmed in a variety of ways, some of which may be much faster than others. If the part to be programmed can write to parts of its own flash under software control but can't do everything and thus requires the use of a secondary processor, it may sometimes be fastest to have the secondary processor program the primary one with just enough of a boot loader to receive its code via some other means (such as a UART) than to use the in-circuit programming mode for everything.
Best Answer
If 256 buttons will be enough, you can use two
MCP23017
(16 port I2C GPIO): the first one as 16 outputs, the second one as 16 inputs, of course with 16x16 matrix of buttons. If not enough, you can use three of them, or "borrow" additional three lines form MCU (so, it will make 16x19 = 304 buttons possible).As @jonk mentioned, if you want to detect multiple buttons pressed at the same time, you need to add diodes (
1N4148
,1N914
) to each button, like below:If you don't need to handle multiple pressed buttons, you need to protect only the output lines by diodes, like below:
MCP23017
is pretty cheap and works very well.