|  | @@ -0,0 +1,389 @@
 | 
	
		
			
				|  |  | +---
 | 
	
		
			
				|  |  | +title: Keyboard Scanning
 | 
	
		
			
				|  |  | +author: Pat Beirne <patb@pbeirne.com>
 | 
	
		
			
				|  |  | +date: Dec, 2024
 | 
	
		
			
				|  |  | +version: 1.0
 | 
	
		
			
				|  |  | +---
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +There's a dozen ways to connect a keyboard to a microcontroller, and this paper attempts to enumerate many of them.
 | 
	
		
			
				|  |  | +There are similar articles on the internet [[see below](#ext_ref)], 
 | 
	
		
			
				|  |  | +but this paper introduces some new techniques: [row-grounded](#3x4gnd), 
 | 
	
		
			
				|  |  | +[row-grounded-with-diodes](#3x4diodes), 
 | 
	
		
			
				|  |  | +[row-grounded-with-4-diodes](#3x4double_diodes)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Some articles focus on a full-function, unambiguous keyboard, 
 | 
	
		
			
				|  |  | +where multiple key-presses can be detected. Something
 | 
	
		
			
				|  |  | +like a piano keyboard needs this, because multiple-keypresses are inherent 
 | 
	
		
			
				|  |  | +to the task. This paper focuses more
 | 
	
		
			
				|  |  | +on the pre-wired 3x4 and 4x4 membrane keyboards that are cheaply available 
 | 
	
		
			
				|  |  | +[like this]( https://bc-robotics.com/shop/membrane-3x4-matrix-keypad/); 
 | 
	
		
			
				|  |  | +these keypads are only appropriate for tasks which 
 | 
	
		
			
				|  |  | +can live with a "one keypress at a time" limitation. 
 | 
	
		
			
				|  |  | +Sometimes, this is appropriate if the keypad is small or in an awkward location, inherently limiting the user to a single finger press. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#### Terminology
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +In this document, *n* refers to the number of keys that are in the keyboard. The letter *k* refers to a specific key
 | 
	
		
			
				|  |  | +that is being pressed during an explanation.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +## One per Pin <a name="one_per_pin" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The simplest way to connect keys to a microcontroller is one key to one pin. 
 | 
	
		
			
				|  |  | +Connect the other side of the key to ground. 
 | 
	
		
			
				|  |  | +In your software, change all the pins to have a "pullup" and to be "inputs"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +In idle, all the pins will read as a logic "high" or a 1. 
 | 
	
		
			
				|  |  | +When a key is pressed, it will change to a "low" or 0.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This configuration has a few advantages:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- zero, one or any number of keys can be pressed simultaneously with out ambiguity
 | 
	
		
			
				|  |  | +- there is no keyboard scan....which helps keep scan-noise out of the power supply; helpful in an audio environment
 | 
	
		
			
				|  |  | +- can easily be set to wake-on-interrupt, which means that you can power down between keystrokes
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +See [KeyBounce](#bounce) below.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Of course, this solution does not apply to a keyboard which has *rows* and *columns*.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +## Resistor Ladder
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The other extreme is to only use a single input pin. There's a couple of ways to implement this.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### Single Chain
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +By connecting the keys to different taps on a resistor ladder, you can supply different voltages to a common pin. Most
 | 
	
		
			
				|  |  | +microcontrollers have an A/D converter, and that can be used to determine which tap was connected.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +A naive approach would be to simply use equal-valued resistors, and then each tap would be *k*/(*n*+1) of the supply voltage.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### 3x4 Chain <a name="3x4chain" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Sometimes a keyboard will be pre-wired as a grid, so you don't have access to the individual keys. You can still use 
 | 
	
		
			
				|  |  | +the resistor ladder to determine the key-press.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +When no key is pressed, the 100k resistor will pull down the CPU pin to 0V. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +When a key is pressed, the CPU pin will rise up to a certain voltage, according to the following chart. Let's assume that
 | 
	
		
			
				|  |  | +Vcc = 3.3V.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +| key label |    | value | 
 | 
	
		
			
				|  |  | +| --- | --- | ---  |
 | 
	
		
			
				|  |  | +| # | 3.3 * 100k/100k = | 3.30V |
 | 
	
		
			
				|  |  | +| 0 | 3.3 * 100k/103.3k = | 3.19V | 
 | 
	
		
			
				|  |  | +| * | 3.3 * 100k/106.6k = | 3.10V | 
 | 
	
		
			
				|  |  | +| 9 | 3.3 * 100k/110k = | 3.00V |
 | 
	
		
			
				|  |  | +| 8 | 3.3 * 100k/113.3k = | 2.91V | 
 | 
	
		
			
				|  |  | +| 7 | 3.3 * 100k/116.6k = | 2.83V | 
 | 
	
		
			
				|  |  | +| 6 | 3.3 * 100k/120k = | 2.75V |
 | 
	
		
			
				|  |  | +| 5 | 3.3 * 100k/123.3k = | 2.68V | 
 | 
	
		
			
				|  |  | +| 4 | 3.3 * 100k/126.6k = | 2.61V | 
 | 
	
		
			
				|  |  | +| 3 | 3.3 * 100k/130k = | 2.54V |
 | 
	
		
			
				|  |  | +| 2 | 3.3 * 100k/133.3k = | 2.48V |
 | 
	
		
			
				|  |  | +| 1 | 3.3 * 100k/136.6k = | 2.42V |
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The smallest band is 0.06V, so an 8bit ADC would still have enough resolution (just barely) to determine which key was
 | 
	
		
			
				|  |  | +pressed. A 10 bit or 12 bit A/D converter will have no problem with these bands, even with 5% resistors.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The sense voltages are designed to *all* be above the halfway point, so that the 
 | 
	
		
			
				|  |  | +idle CPU pin can be programmed as a logic 
 | 
	
		
			
				|  |  | +input, and have interrupts enabled. 
 | 
	
		
			
				|  |  | +Once a logic "high" is sensed, the CPU pin can be changed to an A/D pin, 
 | 
	
		
			
				|  |  | +and the voltage
 | 
	
		
			
				|  |  | +measured (after a short pause). The 1nF capacitor helps with keyboard bounce; 
 | 
	
		
			
				|  |  | +the time constant is ~10us.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Of course, if the user presses multiple keys simultaneously, the measurement will correspond to the highest voltage on that chart.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The same logic can be applied to a 4x4 keypad matrix, 
 | 
	
		
			
				|  |  | +using 2.2k and 10k resisters over a 100k base. 
 | 
	
		
			
				|  |  | +The center voltages will be 2.42, 2.46, 2.50, 2.54, 2.61, 2.65, 2.70, 
 | 
	
		
			
				|  |  | +2.75, 2.83, 2.88, 2.94, 3.00, 3.10, 3.16, 3.23, 3.30, which is should be fine for a 10 bit A/D.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +In both cases, the resistors being identical allows the designer 
 | 
	
		
			
				|  |  | +to use a multi-resistor pack.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +See also [this article](https://github.com/sgmne/AnalogKeypad)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +## Scanning
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### 3x4 Scanning <a name="3x4scan" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The simplest connection of a 3x4 keyboard is to simply use 7 GPIO pins, 4 for the rows, and 3 for the columns.
 | 
	
		
			
				|  |  | +Enable input & pullups on the columns and rows. At scan time, assert each row pin, one at a time, as a low, and measure
 | 
	
		
			
				|  |  | +the column inputs. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Example
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +D4..6 as the columns, D0..3 as the rows. 
 | 
	
		
			
				|  |  | +Assert all as input+pullup.
 | 
	
		
			
				|  |  | +At scan time, assert D0 as output=0, measure D4..D6. Then restore D0, and assert D1 as low. Measure D4..D6 again.
 | 
	
		
			
				|  |  | +Repeat for D2 & D3.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +You then have 4 measurements of 3 pins each. Any detected 0's on those inputs indicate a key-press.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This method allows you to determine 0, 1 or 2 keypresses; any combination of more keys *may* be ambiguous, and should
 | 
	
		
			
				|  |  | +be ignored. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The logic for a 4x4 keyboard is the same; it uses 8 GPIO pins.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This scheme can be configured for interrupt triggering 
 | 
	
		
			
				|  |  | +[[see interrupts]](#interrupts) if the row pins are set to outputs, all=0, and the 
 | 
	
		
			
				|  |  | +columns are set to input+pullup+interrupt. 
 | 
	
		
			
				|  |  | +Any keypress will then pull at least one column line low.  Once the 
 | 
	
		
			
				|  |  | +interrupt is triggered, change to the logic described above, scan the keyboard 
 | 
	
		
			
				|  |  | +[over the [debounce period](#bounce) and then restore they keyboard 
 | 
	
		
			
				|  |  | +to the "ready-for-interrupt" configuration.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### 3x4 plus Ground [new design] <a name="3x4gnd" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +If you are really tight on pins, you can ground one of the rows and still get a functioning keyboard.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +However, you can no longer determine if someone is pressing 2 keys at the same time. For example, pressing the "1"
 | 
	
		
			
				|  |  | +and "4" keys simultaneously will mask the "4" key.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This configuration also can be used as an interrupt-triggered keyboard. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The software scan for this configuration is basically the same as the previous section:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- set all rows to input+pullup; read the columns
 | 
	
		
			
				|  |  | +- set D4 to output=0; read the columns
 | 
	
		
			
				|  |  | +- set D5 to output=0; read the columns
 | 
	
		
			
				|  |  | +- set D6 to output=0; read the columns
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The resulting 4 groups of 3 bits indicate the state of the keyboard; 1=open, 0=keypress.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Again, the same logic will allow you to manage a 4x4 keyboard with 7 GPIO pins.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### 3x4 plus Ground and 2 Diodes [new design] <a name="3x4diodes" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Again, we can scrape off one more GPIO if we can add a pair of diodes to the row pins.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The software is a little more complex, and depends heavily on the one-keypress-at-a-time assumption.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- set all rows to input+pullup; read the columns
 | 
	
		
			
				|  |  | +- set D0 to output=0; read the columns
 | 
	
		
			
				|  |  | +- set D1 to output=0; read the columns
 | 
	
		
			
				|  |  | +- set both D0 and D1 to output=0; read the columns.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The columns have been read 4 times, 3 bits each.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +If a column bit was pulled low when D0/D1 are both idle, then we know the key
 | 
	
		
			
				|  |  | +is in the first row. If a column bit is pulled low only during D0, we know it's 
 | 
	
		
			
				|  |  | +in the 2nd row. D1 means the third row. If a column is pulled low 
 | 
	
		
			
				|  |  | +for *both* D0 and D1 active......we know that it must be in the 4th row; the diodes act like an *OR* function.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +For illustration, let's watch D4 as we cycle through D1/D0 = 11/10/01/11
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- D4=1.1.1.1 no keypress
 | 
	
		
			
				|  |  | +- D4=0.0.0.0 "1"
 | 
	
		
			
				|  |  | +- D4=1.0.1.0 "4"
 | 
	
		
			
				|  |  | +- D4=1.1.0.0 "7"
 | 
	
		
			
				|  |  | +- D4=1.0.0.0 "*"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Putting together the whole keyboard, these are the values that each key 
 | 
	
		
			
				|  |  | +will present to D6/D5/D4 as we cycle through D1/D1 = 11/10/01/00
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +| key press | D6 D5 D4 after D1D0=11.10.01.00 | octal |
 | 
	
		
			
				|  |  | +| --- | --- | --- |
 | 
	
		
			
				|  |  | +| none | 111.111.111.111 |7777 |
 | 
	
		
			
				|  |  | +| 1 | 110.110.110.110 |6666|
 | 
	
		
			
				|  |  | +| 2 | 101.101.101.101 |5555|
 | 
	
		
			
				|  |  | +| 3 | 011.011.011.011 |3333|
 | 
	
		
			
				|  |  | +| 4 | 111.110.111.110 |7676|
 | 
	
		
			
				|  |  | +| 5 | 111.101.111.101 |7575|
 | 
	
		
			
				|  |  | +| 6 | 111.011.111.011 |7373|
 | 
	
		
			
				|  |  | +| 7 | 111.111.110.110 |7766|
 | 
	
		
			
				|  |  | +| 8 | 111.111.101.101 |7755|
 | 
	
		
			
				|  |  | +| 9 | 111.111.011.011 |7733|
 | 
	
		
			
				|  |  | +| * | 111.110.110.110 |7666|
 | 
	
		
			
				|  |  | +| 0 | 111.101.101.101 |7555|
 | 
	
		
			
				|  |  | +| # | 111.011.011.011 |7333|
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[Here](keyboard.c) is some example code to illustrate this decode; in C; 
 | 
	
		
			
				|  |  | +look for the symbol **FIVE_PIN**.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +This configuration is also interrupt-capable, by setting the row drivers to output-low, and the columns as 
 | 
	
		
			
				|  |  | +input+pullup+interrupt.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### 3x4 plus Ground and 4 Diodes [new design] <a name="3x4double_diodes" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +As an extreme, you can decode a 3x4 keypad with only 4 GPIO pins, 
 | 
	
		
			
				|  |  | +using 4 external diodes. 
 | 
	
		
			
				|  |  | +The decode logic is somewhat obtuse, and multiple-keypresses are not handled at all.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +There are two row drivers, with one row connected to ground, and the 4th
 | 
	
		
			
				|  |  | +row connected to a diode pair, as in the previous section.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +There are 2 column sensors, with the 3rd column connected to a diode pair.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +A 4x4 matrix can be decoded with only 5 GPIO pins and 4 diodes.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Because there are several keypresses that involve 2 diodes in a row, 
 | 
	
		
			
				|  |  | +I strongly recommend using Schottky key diodes, although I have built several test
 | 
	
		
			
				|  |  | +rigs with regular 1N4148's and had no problem interfacing to ESP8266.
 | 
	
		
			
				|  |  | +Schottky diodes are not much more expensive than regular diodes.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +To illustrate the operation of this keyboard, follow the logic of the
 | 
	
		
			
				|  |  | +previous section. This time, there are only 2 column inputs to observe.
 | 
	
		
			
				|  |  | +So you get 4 observations of 2 pins; this can neatly be squeezed into a byte, so
 | 
	
		
			
				|  |  | +the table below shows 4 observations of D5/D4 squeezed into a byte. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +| key press | D5 D4 pattern after D1D0=11.10.01.00 | hex |
 | 
	
		
			
				|  |  | +| --- | --- | --- | 
 | 
	
		
			
				|  |  | +| none | 11.11.11.11 | ff |
 | 
	
		
			
				|  |  | +| 1 | 10.10.10.10 | aa|
 | 
	
		
			
				|  |  | +| 2 | 01.01.01.01 | 55|
 | 
	
		
			
				|  |  | +| 3 | 00.00.00.00 | 00|
 | 
	
		
			
				|  |  | +| 4 | 11.10.11.10 | ee|
 | 
	
		
			
				|  |  | +| 5 | 11.01.11.01 | dd|
 | 
	
		
			
				|  |  | +| 6 | 11.00.11.00 | cc|
 | 
	
		
			
				|  |  | +| 7 | 11.11.10.10 | fa|
 | 
	
		
			
				|  |  | +| 8 | 11.11.01.01 | f5|
 | 
	
		
			
				|  |  | +| 9 | 11.11.00.00 | f0|
 | 
	
		
			
				|  |  | +| * | 11.10.10.10 | ea|
 | 
	
		
			
				|  |  | +| 0 | 11.01.01.01 | d5|
 | 
	
		
			
				|  |  | +| # | 11.00.00.00 | c0|
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Notice that *any* keypress will involve at least one *zero*, so this configuration
 | 
	
		
			
				|  |  | +can be interrupt driven, by asserting D1=D0=*low*. Of course, once a key triggers
 | 
	
		
			
				|  |  | +and interrupt, the D1 and D0 must be set to *pullup* (high) so that the scanning
 | 
	
		
			
				|  |  | +can happen.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +[Here](keyboard.c) is some example code to illustrate this decode; in C; 
 | 
	
		
			
				|  |  | +look for the symbol **FOUR_PIN**.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### Keyboard Debounce <a name="bounce" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +When a key is pressed, there is a short time during closure when the 
 | 
	
		
			
				|  |  | +physical elements almost-touch, and the 
 | 
	
		
			
				|  |  | +input pin may measure 1 or 0, even bouncing between them, 
 | 
	
		
			
				|  |  | +until the key fully closes. For mechanical and elastomer 
 | 
	
		
			
				|  |  | +switches, this may last as long as 1-5ms. 
 | 
	
		
			
				|  |  | +The only switch that may not bounce would be an optical switch, but even then,
 | 
	
		
			
				|  |  | +unless the sensor has hysteresis, it may bounce as well.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Elastomer keys may also exhibit a slow contact phenomena, where the resistance
 | 
	
		
			
				|  |  | +if the key drops from *infinity* down to a few hundred ohms over a period of 
 | 
	
		
			
				|  |  | +5msec. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +There are several ways to handle debouncing, some illustrated here:  
 | 
	
		
			
				|  |  | +<https://my.eng.utah.edu/~cs5780/debouncing.pdf>  
 | 
	
		
			
				|  |  | +<https://dygma.com/blogs/stories/switch-bounce-and-debounce-delay>  
 | 
	
		
			
				|  |  | +<https://www.eejournal.com/article/ultimate-guide-to-switch-debounce-part-1/>  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +In general it comes down to postponing the decision about which key is pressed
 | 
	
		
			
				|  |  | +until the bouncing has finished. You may average several observations, or simply
 | 
	
		
			
				|  |  | +delay ~5ms and read the final result. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Similarly, bouncing may happen at key-release time, but the duration of
 | 
	
		
			
				|  |  | +that bounce will almost certainly be shorter.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#### Other Techniques
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Hackaday hackaday.com has some articles on alternative techniques. 
 | 
	
		
			
				|  |  | +One involves using an SPI output and a shift register   
 | 
	
		
			
				|  |  | +<https://hackaday.com/2015/04/15/simple-keypad-scanning-with-spi-and-some-hardware/>   
 | 
	
		
			
				|  |  | +This design requires an external chip ($0.10), 8 diodes and 4 resistors.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### Reading DIP switches <a name="dip_switches" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +In some situations, it's helpful to read an array of DIP switches, 
 | 
	
		
			
				|  |  | +perhaps to read a configuration at power-on. In this case, 
 | 
	
		
			
				|  |  | +there's no need for keyboard debounce. 
 | 
	
		
			
				|  |  | +The read can be done with a parallel-to-serial device (74HC165 $0.08), 
 | 
	
		
			
				|  |  | +or even a serial-to-parallel device, (74HC595 $0.10).
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### Multikey Presses
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Of course, if you have wired your project for one-gpio-per-key, 
 | 
	
		
			
				|  |  | +then there is never a problem with multiple key presses.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +The 3x4 and 4x4 keypads are are available on the market do not have diodes 
 | 
	
		
			
				|  |  | +at the grid junctions, and it is impossible
 | 
	
		
			
				|  |  | +to disambiguate certain key presses. For example, if "1" & "2" are pressed 
 | 
	
		
			
				|  |  | +(R1, C1 & C2 are shorted), clever software can determine that this is the case.
 | 
	
		
			
				|  |  | +But if "1", "2" and "4" are pressed, then R1, R2, C1 and C2 are all shorted, 
 | 
	
		
			
				|  |  | +and it's impossible to determine if the "5" key is pressed or not. Diodes are 
 | 
	
		
			
				|  |  | +required at each junction to disambiguate.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### External keyboard processor <a name="external_hardware" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +With the current cost of processors, consider adding an external coprocessor to your project. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +- with a few dozen I/O pins, lots of keys could be connected, without the need for key multiplexing
 | 
	
		
			
				|  |  | +  - this would also allow interrupt-driven keyboard response 
 | 
	
		
			
				|  |  | +- the external processor can do the keyboard debounce
 | 
	
		
			
				|  |  | +- optionally, you can load this external CPU with extra tasks
 | 
	
		
			
				|  |  | +  -light LEDs 
 | 
	
		
			
				|  |  | +  -drive watchdog circuitry
 | 
	
		
			
				|  |  | +  -manage power-up/power-down sequencing that the main CPU may not be able to handle
 | 
	
		
			
				|  |  | +  -manage narrow-duty-cycle master CPU (perhaps a WiFi CPU) in order to optimize battery drain
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +For example, the PY32F002AF/Cortex-M0+ is currently USD$0.10, 
 | 
	
		
			
				|  |  | +and has 18 GPIO pins, each with pullup capability.
 | 
	
		
			
				|  |  | +You could easily connect 16 pins and still have Tx/Rx serial to report 
 | 
	
		
			
				|  |  | +to your project-master CPU. This processor
 | 
	
		
			
				|  |  | +only sucks 1mA while running, so it's not a big part of your power budget.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +(The next one down is the PY32F002AW with 14 PGIO, and the PY32F002AA with 8 GPIO)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +At the low extreme, the CH32V003J is an 8 pin device with 6 GPIO pins. 
 | 
	
		
			
				|  |  | +One could use 4 pins to interface to a 3x4 keypad, and still have 2 pins 
 | 
	
		
			
				|  |  | +to send back decoded key information, over a 2/3 wire bus.
 | 
	
		
			
				|  |  | +It's U$0.11, 16k flash, 2k ram, 6gpio, sop8. 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +## Summary
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +| name | # pins | simultaneous keys  | extra components |
 | 
	
		
			
				|  |  | +| --- | --- | ---: | ---: |
 | 
	
		
			
				|  |  | +| one per pin           | *n* for *n* | *n* | no |
 | 
	
		
			
				|  |  | +| resistor ladder       | 1 | 1 | *n* resistors | 
 | 
	
		
			
				|  |  | +| classic scan          | 8 for 4x4, 7 for 3x4     | 2 | no |
 | 
	
		
			
				|  |  | +| scan with ground   | 7 for 4x4, 6 for 3x4     | 1 | no | 
 | 
	
		
			
				|  |  | +| scan with diodes   | 6 for 4x4, 5 for 3x4     | 1 | 2 diodes | 
 | 
	
		
			
				|  |  | +| scan with 4 diodes | 5 for 4x4, 4 for 3x4     | 1 | 4 diodes | 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +### External References <a name="ext_ref" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +An excellent overview of keyboard scanning directly from a microcontroller.  
 | 
	
		
			
				|  |  | +<https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ApplicationNotes/ApplicationNotes/00003407A.pdf>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Here is another excellent article:   
 | 
	
		
			
				|  |  | +<http://www.openmusiclabs.com/learning/digital/input-matrix-scanning/index.html>  
 | 
	
		
			
				|  |  | +I found the above at https://hackaday.com/2018/09/30/whats-the-cheapest-way-to-scan-lots-of-buttons/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#### Notes for the ESP8266
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +I got burned on this. On many boards, the gpio15 has a pulldown resistor on board.
 | 
	
		
			
				|  |  | +And gpio16 does not have an on-chip pullup resitor. That makes it difficult to use
 | 
	
		
			
				|  |  | +these pins with the techniques above. FWIW.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 |