Path: Home => AVR-Overview => Applications => Keys and switches on an ADC => Keyboard => resistor matrix   Diese Seite in Deutsch:   AVR-Single-Chip-Processors AT90S, ATtiny, ATmega of ATMEL in practical examples.

# 12- and 16-pin keypad on an AVR

### 1.1 Connections, 12 keys The scheme shows a 12 key wide keypad and its external resistor matrix. The four rows are connected with four stacked resistors that are tied to the positive operating voltage. The three columns are connected with three stacked resistors that are tied to the negative operating voltage.

If none of the keys is pressed, there is no connection between plus and minus, the output voltage at point Y is zero because R1, R2 and R3 pulls it down to the negative operating voltage. If Y is connected with an analog-to-digital converter (ADC), its state reads as zero.

If a key is pressed, e.g. key 5, it connects the row line (here: the horizontal connection between 4-5-6) with the column line (here the vertical connection between 2-5-8-0).

#### 1.1.1 The resistors if key 1 is pressed This is what happens if the key 1 is pressed: this key connects row 1 with column 1. Now R1, R4, R5, R6 and R7 operate as a voltage divider. The current through these five resistors in a row, I1 = U+ / (R1 + R4 + R5 + R6), causes a small voltage on R1, Y1 = I1 * R1. As the ADC input is of a very high resistance, the voltage on R1 appears on Y and the ADC sees this voltage.

The formula below combines the current calculation and the voltage calculation. The calculated Y1 is the fraction of the operating voltage (U+) that appears on the ADC, whenever key 1 is pressed.

To the top of the page

#### 1.1.2 The resistors if key 9 is pressed If the key 9 is pressed, the voltage divider works different. Now R1, R2 and R3 together are the lower resistor of the voltage divider. The upper resistor of the voltage divider are the resistors R6 and R7. The current now is I9 = U+ / (R1 + R2 + R3 + R5 + R6 + R7), The voltage on Y is then Y9 = I9 * (R1 + R2 + R3).

Every key combines specific resistors to a voltage divider, and so produces a specific voltage on output Y. With that voltage it can be determined if any one and which specific key is currently pressed. The task then is to select the resistor values in an optimal way (using the software provided below).

### 1.2 Keypad with 16 keys Four more keys require an additional resistor to work in a similar way. Looks very much like the 12-key version, but the calculation of the voltage divider is different and produces very different voltages. In that case the resistors have to be of a higher accuracy of 2 or 1% (see below).

### 1.3 Alternative schematic with parallel resistors

The four upper resistors do not have to be stacked necessarily, they can also be parallel. The following schemes show this alternative.  This changes the mode of calcuation slightly, but the main calculation scheme remains the same.

To the top of the page

## 2 Calculating resistor values

Here a tool for calculating resistors is provided and introduced.

### 2.1 Calculation basics and rules

This chapter shows the rules and how to calulate resistor values in a correct way. Calculating the resistors for those voltage dividers is not trivial:
• Resistors are available with an accuracy of plus and (!) minus 0.1, 1, 2 or 5% only. Resistor values with 5% inaccuracy so are within a band of 10% of the nominal value. For a 1k resistor that means that its value can be anywhere between 950 and 1,050 Ohms. The resulting voltages produced so are within a certain bandwidth. The minimum voltage produced appears if all resistors in the lower resistor chain are on their lowest value and all those in the upper resistor chain are in their upper bandwidth value. The maximum voltage is gained if the lower resistor chain is on their highest value and the resistors of the upper chain on their highest. Those inaccuracies have to be taken into account, the bandwidth requires that a lower and upper limit has to be checked if the key is to be identified. With that we do not have to select accurate values manually and we do not need to keep the temperature of our matrix constant. Fortunately we do not need resistors with accuracies of 0.1%, so we can forget this.
• Resistors are only available with certain discrete values, known as E rows. The most common one is the E12 row: 1.0 - 1.2 - 1.5 - 1.8 - 2.2 - 2.7 - 3.3 - 3.9 - 4.7 - 5.6 - 6.8 - 8.2, and their decadic manifolds, such as 10 - 12 - etc. or 100 - 120 - etc.. The E48 row has double, the E96 row four times more discrete values. So we can only select resistor values from these rows. Solving the problem with discrete formulas (with 7 resp. 8 unknowns) would in almost every case lead to resistor values that are not commercially available, so forget this theoretical calculation option.
• Even having those extended E48 and E96 rows, most of these resistors are not available commercially in practice. Most sellers fear having hundreds of boxes with exotic values only rarely saled and sitting around in their boxes for years. So we have to stick with the E12 and E24 row, and E48 or E96 values are only theoretical (or only for those with excellent connections to certain dealers). You can play around with those extended rows, but a visit in your local electronics store or a look into the catalogue of your preferred parts dealer gets you down to earth and to E12 values. Finally the good message: the problem is resolvable with only E12 values.
• Whenever we change one resistor value to a different one in the E row, nearly the whole set of voltages (and their voltage bandwidth) changes. So selecting values has to be iterated step by step, keeping an ideal state in mind (the voltages produced are uniformly deployed over the whole range from 0 to the operating voltage) and no overlaps occur (every key produces its unique voltage range).
• Another criterion is that pressing keys does not lead to elevated currents, e.g. of 100 mA. The sum of the resistors R1 and R7 (resp. R8) so should not be smaller than 1,000 Ohms, causing a maximum current of less than 5 mA.
• The other case would be too large resistor values. If the currents through the matrix would be less than 10µA the potential influence of noise would be too large. So all the resistor values should be divided then by ten reducing noise on the voltages.
• If the AD converter works with the operating voltage of the keypad as reference voltage, the design is especially easy. If 8 bit resolution is selected (the left adjust result bit ADLAR is set to one, only the MSB of the ADC is read), the results are between 0 and 255. In the 10 bit case the results are between 0 and 1023. In both cases no conversion to voltages is necessary.
To the top of the page

### 2.2 Calculation software As designing such matrices is a lengthy process, I designed this software tool. It allows to play around with values and parameters.

The software provided here (Win64 executable) or here for Linux i386-x64 is a simple command line application. Download it, unzip the executable and start it. You can download the pascal source code, too, compile it with the Free Pascal Compiler fpc and run this executable. If you are cautious with downloaded executables or if you need the executable file for other operating systems, you can go this way.

The version including upper serial as well as parallel resistors is provided as Win64 executable here and as Free Pascal Source Code here.

The software allows to
• select between 12 and 16 key keypads (switch by pressing the key k),
• single step through the iteration process (press s for a single step, selects one of the resistors to be processed randomly),
• perform 1,000 iteration steps at once (press i),
• select 8 or 10 bit resolution of the ADC (press r, input 8 or 10),
• set resistors R1 to R7 resp. R8 to desired values manually (press n, input resistor value in Ohms),
• select resistor accuracy and E row (press t, input 1, 2 or 5% tolerance, input resistor row E24, E48 or E96),
• write the current results to a text file (press w),
• exit the application (press x).
The window displays
• the current resistor values R1 to R7 resp. R8,
• the ADC results for the 12 resp. 16 keys, according to the current ADC resolution, as nominal, minimum and maximum values as well as the ideal reference value,
• the current key row by produced nominal voltages (can change),
• the selected resistor row (E12, E24, E48, E96),
• the number of current overlaps (total number of overlapping bandwidths, should be zero),
• the sum of differences between the nominal values and their ideal reference values (should be as small as possible),
• the tolerance of the resistors and the ADC resolution.

To the top of the page

### 2.3 Example calculation 12 keys

The following example is based on the following parameters: tolerance 5%, 8 bit resolution, resistor row E12. This is the result after a single step. The random step selected R4, decreased this resistor from 68k to 56k, resulting in reducing the overlaps and the differences between nominal and reference readings from 599 to 548. Another step increases R5 from 27k to 33k, reducing overlaps, but increasing the differences. This is the result after 1,000 iteration steps. The number of overlaps is zero, the differences are minimized to 32. All voltages are within a well suitable bandwidth of ADC readings: not too small bandwidth, enough difference to the next key.

Note that the iteration step does not always lead to optimal results. As the steps are done randomly, different runs might lead to sub-optimal one-way-streets. Try another iteration (select 16 keys, then 12 keys again, then restart iteration) or change resistors manually.

To the top of the page

### 2.4 Example calculation 16 keys By pressing k the calculation switches to 16 keys, 1% tolerance and 10 bits resolution of the ADC. These are necessary values to get the matrix working (5% is too large, 2% would also be sufficient, 8 bit is too small). Resistor row still is E12 to ease availability.

With standard resistors the number of overlaps is already at zero, but differences can be optimized. The result after 1,000 iteration steps. Also looks fine. Problem solved.

To the top of the page

### 2.5 12 key result files A view on the result files documenting the results, with a simple editor. The name of the result file reflects the parameters used, the example file for 12 keys is here.

The upper portion of the files shows the program output. The lower portion provides a table to be copied to the assembler source file. The table can be used to identify the key pressed (see below). The first value on every line holds the 8-bit lower limit for the respective key, the second the value at the end of the bandwidth plus one. So a key is recognized if the ADC result is equal or above the lower limit (a CP instruction ends with the carry flag clear) AND is smaller than the given upper limit plus one (a CP instruction ends with the carry flag set).

The table ends with two zero bytes to signal that the end of table has been reached.

The last two lines in the file provide an ASCII table with the respective key values.

### 2.6 16 key result files The file name produced reflects the parameters used, the example file is here.The upper portion of the file again shows the program output.

The lower portion again provides a table to be copied to the assembler source file. Its content are now two 16-bit values per line, with the lower limit and the upper limit plus one.

The table ends with a zero word to signal that the end of table has been reached.

The last two lines in the file again provide an ASCII table with the respective key values.

## 3 Assembler software

The assembler software is a little bit different for the 8 and 10 bit ADC versions.

### 3.1 Assembler software for 8 bit ADC values

The following assumes
• that the 8-bit ADC value is in register R2,
• registers R0 and R1 are available and can be temporarily used,
• register pair Z can be used.
The table as provided in the result file is included:
``````
; Decimal table for assembler
Keytable: ; lower limit, upper limit +1), 'Key'
.DB 25, 31 ; '1'
.DB 34, 41 ; '2'
.DB 45, 54 ; '3'
.DB 66, 78 ; '4'
.DB 84, 96 ; '5'
.DB 104, 117 ; '6'
.DB 117, 130 ; '7'
.DB 138, 151 ; '8'
.DB 159, 171 ; '9'
.DB 178, 189 ; '*'
.DB 194, 204 ; '0'
.DB 209, 217 ; '#'
.DW 0 ; table end
Keyvalues:
.DB "123456789*0#" ; Key values ascii
``````
The following subroutine first reads in the lower limit from the table. If the lower limit is zero, the table is at the end and no key is recognized (routine returns with FF in R0). Then it checks if the ADC value is smaller then the lower limit. If yes, no key is pressed or the value is in between two valid key limits (routine returns with FF in R0). Then the upper limit plus one is read from the table. If the ADC value is higher than this upper limit, the routine continues from the start. If the ADC value is smaller, a valid key has been detected, the respective ASCII value is read from the table and returned in R0.
``````
GetKey12: ; get the ascii value of the key pressed, return result in R0
clr R1 ; clear counter                        +-------------------+
dec R1 ; set counter to FF                    | Set counter R1=FF |
ldi ZH,HIGH(2*Keytable) ; point Z to table    | Set Z to table    |
ldi ZL,LOW(2*Keytable) ;                      +-------------------+
GetKey1:                                                    |
tst R0 ; table at the end?                      /      / \__________> yes
breq GetKey3 ; table end reached               |       \0/no         |
inc R1 ; count up                              |    Inc counter      v
cp R2,R0 ; compare ADC result with lower limit |       / \__________>|
brcs GetKey3 ; smaller than lower limit        |       \C/no         |
adiw ZL,1 ; upper limit in table               |  Read upper limit   |
lpm ; read to R0                               |    and compare      |
adiw ZL,1 ; next byte                          |        |            |
cp R2,R0 ; compare with upper limit             \______/ \           |
brcc GetKey1 ; larger than upper limit               no\C/           |
ldi ZH,HIGH(2*KeyValues) ; point to result table  Z to value table   |
ldi ZL,LOW(2*KeyValues) ;                               |            |
brcc GetKey2 ; no overflow                              |            |
inc ZH ; overflow, add one to MSB                 Inc MSB table      |
GetKey2: ;                                                  |            |
ret ; return with result                               RET           |
GetKey3: ; table at end or value in between, return FF                   v
clr R0 ; clear result                                R0 to FF <------
dec R0 ; return FF                                      |
ret ;                                                  RET
``````
That is it all.

### 3.2 Assembler software for 10 bit ADC values

10 bit ADC values require word-wise comparision. The following registers are used:
• R0 returns the pressed key character, if invalid the FF,
• R2:R1 is used for the table value,
• R4:R3 stores the input value,
• R5 counts,
• Z is used for pointer purposes.
``````
; Decimal table for assembler, 16 keys
Keytable: ; Lower lim, upper lim+1, 'Key'
.DW 96, 100 ; '1'
.DW 122, 127 ; '2'
.DW 158, 164 ; '3'
.DW 191, 198 ; 'A'
.DW 263, 272 ; '4'
.DW 319, 329 ; '5'
.DW 388, 399 ; '6'
.DW 444, 455 ; 'B'
.DW 497, 508 ; '7'
.DW 566, 578 ; '8'
.DW 640, 650 ; '9'
.DW 693, 703 ; 'C'
.DW 742, 751 ; '*'
.DW 794, 802 ; '0'
.DW 842, 849 ; '#'
.DW 874, 880 ; 'D'
.DW 0 ; table end
Keyvalues16:
.DB "123A456B789C*0#D" ; Key values ascii
;
; Convert ADC value in R4:R3 to key ascii code
GetKey16:
clr R5 ; clear counter
dec R5 ; set to FF
ldi ZH,HIGH(2*Keytable) ; Z to table
ldi ZL,LOW(2*Keytable)
GetKey16a:
inc R5 ; increase counter
lpm ; read LSB from table
mov R1,R0 ; copy to R1
lpm ; read MSB from table
mov R2,R0 ; copy to R2
tst R1 ; LSB zero?
brne GetKey16b ; no, go on
tst R2 ; MSB zero
breq GetKey16d ; table at end
GetKey16b:
cp R3,R1 ; compare LSB
cpc R4,R2 ; compare MSB plus overflow
brcs GetKey16d ; carry indicates value smaller then lower limit
lpm ; read LSB upper limit
mov R1,R0 ; copy to R1
lpm ; read MSB upper limit
mov R2,R0 ; copy to R2
cp R3,R1 ; compare LSB
cpc R4,R2 ; compare MSB plus overflow
brcc GetKey16a ; ADC value higher or equal upper limit
ldi ZH,HIGH(2*KeyValues16) ; Z to table
ldi ZL,LOW(2*KeyValues16)
brcc GetKey16c ; no overflow
inc ZH ; overflow, add 1 to MSB
GetKey16c:
lpm ; read ascii value from table to R0
ret ; return
GetKey16d:
clr R0 ; set R0 to FF
dec R0
ret ; return with R0=FF
``````
Hint: The LPM instructions used here are AVR old-style. By use of LPM Z+,R a few lines can be saved.

To the top of the page