Dave Thomas's PIC DTMF
Encoder
;
; keypad tone generator with wakeup on keypress
;
DEVICE PIC16C56,HS_OSC,PROTECT_OFF,WDT_OFF
TONE_DURATION equ 30000
audioport equ RA
ROWMASK equ 00000001b
COLMASK equ 00000010b
keyport equ RB
KEYMASK equ 00001111b
col0 equ RB.4
col1 equ RB.5
col2 equ RB.6
temp equ 09h
colcount equ 0ah
ccount equ 0bh
rowcount equ 0ch
rcount equ 0dh
tonetimehi equ 0eh
tonetimelo equ 0fh
row0 equ 10h ; current state of key row 0
row1 equ 11h ; current state of key row 1
row2 equ 12h ; current state of key row 2
keycode equ 13h
RESET Start
zzzzz
clrb col0
clrb col1
clrb col2
sleep
; KeyMap -- map key ID to DTMF tone code
KeyMap
jmp PC+W
; straightforward matrix
; retw 0000b,0001b,0010b
; retw 0100b,0101b,0110b
; retw 1000b,1001b,1010b
; retw 1100b,1101b,1110b
; PacTec brain damaged membrane keyboard
retw 1000b,0000b,1100b
retw 0100b,1001b,0001b
retw 1101b,0101b,1010b
retw 0010b,1110b,0110b
;697 Hz 90 123A row
;770 Hz 81 456B row
;852 Hz 73 789C row
;941 Hz 66 *0#D row
;1209 Hz 52 147* col
;1336 Hz 47 2580 col
;1477 Hz 42 369# col
;1633 Hz 38 ABCD col
RowTab
jmp PC+W
retw 90,81,73,66
ColTab
jmp PC+W
retw 52,47,42,38
;
; DTMF_send -- send a DTMF tone pair as encoded in W on entry.
; encoding is xxxxRRCC where x = dont care, RR = row#, CC = col#
;
DTMF_send
; get row and col encoding into rowcount,colcount
mov colcount,W
mov rowcount,W
and colcount,#00000011b
rr rowcount
rr rowcount
and rowcount,#00000011b
; replace with actual counts from lookup tables
mov W,colcount
call ColTab
mov colcount,W
mov W,rowcount
call RowTab
mov rowcount,W
; preload counters && timers
mov rcount,rowcount
mov ccount,colcount
mov tonetimehi,#TONE_DURATION<
mov tonetimelo,#TONE_DURATION>
:dtmf_loop
; time to stop?
dec tonetimelo
jnz :keepon
dec tonetimehi
snz
ret ; done! get out.
:keepon
; wait for clock tick
mov temp,RTCC
:tickwait
mov W,RTCC
xor W,temp
jz :tickwait
; decrement counters
djnz rcount,:checkcol
; row count reached zero -- toggle audio and reset counter
mov W,audioport
xor W,#ROWMASK
mov audioport,W
mov rcount,rowcount
:checkcol
djnz ccount,:dtmf_loop
; col count reached zero -- toggle audio and reset counter
mov W,audioport
xor W,#COLMASK
mov audioport,W
mov ccount,colcount
jmp :dtmf_loop
Scan
clrb col0
mov row0,keyport
setb col0
xor row0,#KEYMASK
and row0,#KEYMASK
clrb col1
mov row1,keyport
setb col1
xor row1,#KEYMASK
and row1,#KEYMASK
clrb col2
mov row2,keyport
setb col2
xor row2,#KEYMASK
and row2,#KEYMASK
ret
Decode
clr keycode
test row0
jz :tryrow1
; definitely a bit on in row0
mov keycode,#1
:loop0
snb row0.0
ret
rr row0
inc keycode
jmp :loop0
:tryrow1
test row1
jz :tryrow2
; definitely a bit on in row1
mov keycode,#5
:loop1
snb row1.0
ret
rr row1
inc keycode
jmp :loop1
:tryrow2
test row2
snz
ret
; definitely a bit on in row2
mov keycode,#9
:loop2
snb row2.0
ret
rr row2
inc keycode
jmp :loop2
Start
mov OPTION,#00000100b ; RTCC @ 125 KHz
mov !RB,#00001111b
mov !RA,#0000b ; all outputs
setb col0
setb col1
setb col2
Wakeup
call Scan ; read keyboard
call Decode ; decode bit pattern to key ID
test keycode
jz :release ; if no key, don't send
dec keycode
mov W,keycode ; get key ID
call KeyMap ; map key ID to DTMF code
call DTMF_send ; send DTMF tone
; now wait for key to be released and sleep
:release
call Scan
call Decode
test keycode
jnz :release
jmp zzzzz