DTMF Keypad (and more) Explanation

Wow, I just realised I created this project back in May 2008… I think the principal and technique used for the keypad is worth explaining however so I’m publishing it now.

When my local repeater GB3PY started providing Echolink access my shack radio was an Icom IC-910 which does not support DTMF to control Echolink. This meant I was unable to connect to nodes or disconnect nodes.

The answer for me was to build my own DTMF keypad, and this was a good excuse to learn how to interface a keypad into a PICAXE.

DSCF6230 (Custom)

The schematic was below shows I used a PICAXE-20M which ‘scanned’ the keypad and when an input was detected enabled the PTT via Q2 then generated the DTMF tones using an HT9200B chip.


There are a couple of methods to read a keypad input, I used the ‘scanning’ method but a simpler way might be using ADC.

Keypad Scanning

Explaining the scanning method is harder than it actually is, but lets give it a go.  The keypad us divided into ROWs and COLUMNS, in a HEX keypad (those with *, # and A-D) there are 4 of each

If we pressed the ‘0’ key then it would create a connection between ROW4 with COL2 which is a unique ROW/COL combination we can use to identify which key is pressed. An issue arises though when it comes to reading this same unique combination using a PIC we need to read a voltage, but on the ROW or COL line?

Lets say we supply a voltage to all ROWs so when a key is pressed a voltage appears on the corresponding COLUMN (you can swap COLUMNs and ROWs around in hardware implementation if you wish but you will see one way works better than the other), if we pressed the ‘6’ key then we would get the ROW2 +5v voltage on COL3. But wait a minute, we would also get +5v on COL3 if we pressed keys ‘3’, ‘6’, ’9’ or ‘B’.  This is no use now is it!

The solution is quite simple in fact.  The voltage supplied to each ROW comes from an output of the PIC and so can be ‘scanned’ when an input is detected.  The code in the PIC sits  with all outputs high so all ROWs have +5v on them waiting for any key to be pressed, when it detects a key has been pressed, as a voltage will appear on a COL line, it switches the outputs off and then turns each one on individually in turn until it finds which COLUMN has the voltage on it.  This means means we know only one ROW has a voltage on it and which COL the key has connected it to and therefor the button pressed, this is how the scanning works.  Additionally we connect the ROW voltage to the higher bits of the PIC inputs meaning we can add the ROW bit to the COL bit to create a unique value, as using just the 4 COL inputs means we can only have 4 values, bits 1, 2, 4 & 8 (pins 1, 2, 3 & 4) but adding the ROW also gives us bits 16, 32, 64, 128 (pins 5, 6, 7 & 8 ) to add meaning key 6 (COL3& ROW2) gives 4+32 (36). The PIC can then assign a value to the key, it can convert 36 to 6 using a lookup table.

Keypad ADC

The other method is to use a bunch of resistors and the supply voltage to create a unique voltage (ADC value) for each key press;

KeyPad Using ADC

This can simplify the method but adds much more components to the BOM and will also be less accurate, poor switch contact resistance for instance will result in the wrong key value being read.  Also as this is a project designed to be used in an RF environment, the RF could induce voltage into the keypad causing the ADC to read a wrong value for the key pressed.

The PIC will still need to translate the detected value into the real key value, but the advantage is only one PIC input is needed to read all 16 keys. 4 outputs and 8 inputs are needed for the ROW and COL scanning method.

The Project Goals

DSCF6229 (Custom)

When I planned this project I wanted it to have 2 modes, one mode would send DTMF and the other CAT or CI-V frequency control.  Pressing something like the ‘A’ for 3 seconds would toggle modes.  I never did implement the CI-V aspect into this project but the DTMF worked fine.

DSCF6239 (Custom)



'Define Inputs and Outputs and Registers
'Logic	Use			Physical
'In 0		Keypad Row 4	3
'In 1		Keypad Row 3	4
'In 2		Keypad Row 2	5
'In 3		Keypad Row 1	6
'In 4		Keypad Column 4	7
'In 5		Keypad Column 3	8
'In 6		Keypad Column 2	9
'In 7		Keypad Column 1	10
'Logic	Use			Physical
'Out 0	In 7 & DTMF D0	18
'Out 1	In 6 & DTMF D1	17
'Out 2	In 5 & DTMF D2	16
'Out 3	In 4 & DTMF D3	15
'Out 4	DTMF Enable		14
'Out 5	Serial TX		13
'Out 6	PTT			12
'Out 7	**Unused		11
'Register	Use
'B10		Key_Value
'B11		Row Scan
'B12		TX Timer
'B13		Mode (1 for DTMF and 2 for CAT)

SYMBOL key_value	= B10
SYMBOL row_scan	= B11
SYMBOL Tx_timer	= B12
SYMBOL Mode		= B13

EEPROM 0,("123A456B789*0#D")	'Load 16 keypad real numbers/chracters into memory

Mode = 1

pause 2000

high 4

If Mode = 1 then goto DTMF_Mode
If Mode = 2 then goto CAT_Mode

if Tx_timer = 0 then
low 6
dec Tx_timer

'debug Tx_timer

gosub check_keys

if key_value = 0 then goto start

'debug ROW_SCAN
'debug key_value
pins = key_value

Tx_timer = 50
high 6

low 4
pause 1000
key_value = 0

goto start

goto start

row_scan = 1	'if row 1 key value will be between 1 and 4
high 2		'set to high to provide voltage to keypad row1
gosub check_column
low 2

row_scan = 4	'if row 2 key value will be between 5 and 8
high 3		'set to high to provide voltage to keypad row2
gosub check_column
low 3

row_scan = 7	'if row 3 key value will be between 9 and 12
high 1		'set to high to provide voltage to keypad row3
gosub check_column
low 1

row_scan = 11	'if row 4 key value will be between 12 and 16
high 0		'set to high to provide voltage to keypad row4
gosub check_column
low 0			'test the input pins for which column the key is in

if pin0 = 1 then gosub first'column
if pin1 = 1 then gosub second'column
if pin2 = 1 then gosub third'column
if pin3 = 1 then gosub forth'column

key_value = row_scan		'No addition required, column number [1]

key_value = row_scan + 1	'This is row number + column number [2]

key_value = row_scan + 2	'This is row number + column number [3]

if row_scan = 1 then
key_value = 13

if row_scan = 4 then
key_value = 14

if row_scan = 7 then
key_value = 15

if row_scan = 11 then
key_value = 0

'key_value = row_scan + 4	'This is row number + column number [4]

Leave a Reply

%d bloggers like this: