Matrix of SPST switches and buttons with Arduino
I'm sure this has been posted at least a million times on the web somewhere. I happened to pick up this image from a PDF manual sitting at a web site that holds documents in order to capture email addresses, etc. So I'm not providing a link to that site. Just the same, it's a good diagram:



Those are all SPST switches. (If you ever want to handle an SPDT, just take up two rows on a single column above for that.)

The diodes above can be wired with opposite polarity. All that does is change the meaning of "active" vs "inactive." As shown above, "active" means "HI".

The above matrix is larger than you specified. But it gets the idea across and is even larger than you need. Just trim rows or columns, as appropriate.

Not shown on the matrix above are the "pull-down" resistors on each of the columns. This is so that when a switch on an active row is not engaged, the value read by the column input will be a definite LOW. But if the switch is engaged on an active row, then the diode will pull up on the column line and it will be read as a definite HIGH by the column inputs.

To scan, you would make all of your rows as outputs, with only one of the rows active at a time. The others would be inactive. The columns would be inputs.

When a row is active, you'd read in the values for all of the columns. It's usually convenient to arrange all of the columns so that they attach to pins on the same I/O port of your MCU. It makes reading them easier/better.

It would be advisable to also do debouncing of these column values. I usually use a small state machine for this purpose, with \$8\:\text{ms}\$ per sample and using three samples for any switch to complete its state machine and be recognized as a value. An example of the state machine I use is found here, here, and here. So, for me this is \$24\:\text{ms}\$ per debounced value. You need to work out your own issues, though.

If you look closely at the matrix above, I think you can see that if only one row is active (HIGH in this case) and all of the other rows are inactive (LOW), then only the switches along that row are able to affect the column values you read. The others rows (inactive LOW) will have their diodes reverse-biased and cannot affect the column line. This avoids interference from switches that aren't being scanned at the moment.



There are many other issues you may need to deal with. I've already alluded to one: debounce time. But there are more. How do you want to handle multiple-press events, key roll-over, key combinations, and so on. But that's just software. So have at it.