I'd add something like 47-100uF near the 0.1uF decoupling capacitors on chips which have the potential of consuming bursts of current all of the sudden.
You should consider using a LED driver IC to drive your LEDs.
The shift registers are fine but there's some fineprint : most have around 25mA current limit per pin and around 70-100mA overall current limit. So even if you limit current to each LED using resistors to something like 15mA, if all leds are lit you may exceed the overall current limit and your LEDs may become dimmer.
There are cheap led driver ICs that are basically a combination of a shift register and current limiting, so you can use them just like shift registers and you set the current limit for all leds with just one resistor. In addition to that, some even let you send a command through i2c or spi that lets you set brightness to a percentage or level (ex 256 levels, a 8 bit value) which sets the leds to a percentage of the maximum current you set with the resistor.
For example, check out
TLC5916IN or
TLC5917IN , a 8 channel shift register ... each channel can do up to 120mA and you can set maximum current with one resistor and adjust output current by setting a 8 bit value (output current between 3mA and 120mA ... or the maximum current set by your resistor)
So it is a bit more expensive, but you're not having to add one resistor for each led, you only need one resistor per shift register
They're serial, you only need 4 wires to control multiple of these, you can chain them together like regular shift registers, see page 22 in the datasheet:
http://www.ti.com/lit/ds/symlink/tlc5916.pdfAlso notice you can power the chips themselves with 3v..5v and you can power the LEDs separately with up to 20v, so for example if you have a 12v power supply / wallwart adapter or 18v laptop adapter, those leds could be powered directly from this higher voltage and the led drivers will limit the current just fine. This takes the strain out of the 5v power supply ... for example if you set the led current to 10mA, you don't have to worry about 17x10 = 170mA of current loading your 5v linear regulator or USB.
As for your buttons, what I would suggest is to use port expanders.
A port expander is a chip which creates multiple I/O pins, which can be set to input or output and you can read the state or set the state of each pin from your microcontroller through SPI or i2c.
Here's for example some super cheap 16 I/O port expanders:
Microchip MCP23017 (i2c) :
https://www.digikey.com/product-detail/en/microchip-technology/MCP23017-E-SP/MCP23017-E-SP-ND/894272Microchip MCP23S17 (SPI) :
https://www.digikey.com/product-detail/en/microchip-technology/MCP23S17-E-SP/MCP23S17-E-SP-ND/894276You could chain two of these (giving each unique address on the i2c bus or just by using the serial passthrough, pinout is the same on both chips, the i2c version just has two disabled pins that are used for serial on other version) and you get 32 I/O pins.
Another benefit of using these is that they support interrupt on change, meaning you can configure them to send you a signal when the state of a single pin changes (like when you'd push a button). So provided you have decent debouncing in your code, you would have to read the state of your buttons only when your Arduino receives an interrupt from the expander chip... so instead of reading 100 times a second, you may read only 20 times a second, whenever a button changes state.
If you feel like you need a resistor for buttons you could consider resistor arrays... for example see this 8 x 1k resistor array :
https://www.digikey.com/product-detail/en/bourns-inc/4609X-101-102LF/4609X-101-102LF-ND/3593658You connect pin 1 to 5v and the other 8 pins to each button or switch, so when you press a button, 5v goes through button/switch, limited by the 1k resistor
It's more expensive, yes, but you're saving on PCB space, pins, etc... if the buttons are grouped close together.
However, for just buttons, considering you have 21 inputs, you could do a trick if you want to save some money :
* have one 16 I/O port expander
* configure the first two pins as output , and the other 14 pins as inputs.
* power the first 14 buttons from the first pin that's set on output , and power the remaining buttons from the second pin set on output , connect the second pin of all buttons and switches to your 14 pins set on input (one button/switch from each set to one input pin)
* this works if you don't send power to both sets of buttons at the same time, it's like multiplexing ... this way you can connect up to 28 buttons / switches on your 14 input pins of your port expander chip.
In your Arduino, you can set the first output pin high and the second pin low, and now only the first 14 buttons receive power. Wait a ms, then read the 14 inputs ... if a button is pressed, then you get some voltage on your input pins.
Now turn off the first output pin and turn on the second pin, wait a ms or so and read the other set of 14 buttons
If you read buttons every ms, you can basically read all 28 potential buttons 500 times a second (if you wait 1ms between each reading of buttons)
The MAX7219 are kind of expensive but if you already bought them, I guess you could use them.
If you're not afraid of a tiny bit of surface mount soldering (you can solder these to an adapter board which converts them to DIP) you could have used led driver ICs which have lots of channels.
For example, this
TLC5955DCAR has 48 channels, so you could easily display up to 6 digits at the same time using one ( 7 segments + dot , times 6 = 48 channels) and they cost 5$ each if you buy 10, compared to around 10$ for a single genuine MAX7219
They also have maximum current limit (30mA), and you can power the LEDs themselves with up to 10v (so if you have a 12v power supply, you could use a 7809 linear regulator to power the leds instead of using 5v)
These use SPI, so again you could have all your displays on a single SPI but, chaining all the displays with 6 wires (voltage, ground, serial in and out, clock , latch)