Source:

Code:
'
'***********************************************************************************
'*                                                                                 *
'*                                 Telephony                                       *
'*                          Rotary to DTMF converter                               *
'*                        Microchip Pic 16F628 @ 8MHz                              *
'*                              (c) Art 2013                                       *
'*                                                                                 *
'*                          [email protected]                               *
'*                                                                                 *
'***********************************************************************************
'
'
DEFINE OSC 20								' but we are really using 8 MHz
DEFINE NO_CLRWDT							' watchdog is cleared manually
LCD_DATAUS CON 50							' LCD timing
LCD_COMMANDUS CON 2000						'
'
DATA  " Art 2013 " ' Rotary to DTMF - (c) Brek Martin 2013
'
'
number var byte[18]	' number entry array
fnum var byte[18]	' phone number array
digcnt var byte		' phone number entry counter
fcount var byte		' phone number digit counter
i var byte			' counter
digit var byte		' dtmf digit
pulses var byte 	' rotary pulse count
tcount var word 	' cycle counter
shiftcount var word	' timer to accept a phone number digit
longcount var word	' timer to dial DTMF number
emergency var bit 	' emergency speed dial status
pressed var bit		' hangup  button status
donedtmf var bit	' dialed number status
'
'
' execution time!
'
'
'
CMCON = 7	' set portb to digital
trisb.6 = 0	' set LCD backlight output
trisb.4 = 0	' set DTMF output
trisb.5 = 1	' set button input
portb.6 = 1	' turn on LCD backlight
'
'
PAUSE 500			'pause for LCD to start
@ clrwdt			; clear watchdog timer manually
PAUSE 500			'
@ clrwdt			;
PAUSE 200			'
'
LCDOUT $FE,$80
LCDOUT "  ROTARTY DIAL  "
LCDOUT $FE,$C0
LCDOUT " DTMF CONVERTER "
'
PAUSE 500			'pause to display message
@ clrwdt			; clear watchdog timer manually
PAUSE 500			'
@ clrwdt			;
PAUSE 300			'
'

'
resetx:
donedtmf = 0	' reset status
emergency = 0	' reset emergency speed dial
reset:
digit = 0	' reset digit variable
digcnt = 0	' reset phone number entry counter
pulses = 0	' reset pulse count
tcount = 0	' reset cycle counter
fcount = 0	' reset phone number digit counter
shiftcount = 0 ' reset digit accept timer
longcount = 0	' reset timer
pressed = 0	' reset hangup button status
'
FOR i = 0 TO 17	' reset number arrays
number[i] = 0
fnum[i] = $FF
NEXT i
'
LCDOUT $FE,1		'clear LCD
LCDOUT $FE,$80		'set to start of first line
'
'
cycle:				' main routine - user program
@ clrwdt			; clear watchdog timer manually
'
'
IF pressed = 0 THEN
IF portb.5 = 0 THEN ' reversed
pressed = 1	' set status
tcount = 0	' start counter
shiftcount = 0
IF pulses < 10 THEN ' valid count only
pulses = pulses + 1
ENDIF

ENDIF ' button pushed
ENDIF ' ignore if button already down
'
'
'
IF pressed = 1 THEN	' increment counter while button is down
IF tcount < 2500 && portb.5 = 0 THEN ' reversed
tcount = tcount + 1
ENDIF

IF tcount > 2499 && portb.5 = 0 THEN ' reversed
gosub printerror		' hangup held down too long
IF portb.5 = 1 THEN		' wait for off hook again to restart
goto resetx				' restart properly
ENDIF
ENDIF

IF tcount < 2500 && portb.5 = 1 && pressed = 1 THEN ' reversed
IF tcount > 20 THEN					'debounce button

IF pulses < 10 THEN
number[digcnt] = pulses
ELSE
number[digcnt] = 0
ENDIF

gosub senddigit
digcnt = digcnt + 1
tcount = 0
pressed = 0
ENDIF
ENDIF ' debounce
'
ENDIF
'
'
'

IF shiftcount > 0 && digcnt > 0 THEN
IF pressed = 0 THEN
shiftcount = shiftcount + 1
IF shiftcount > 9999 THEN
shiftcount = 0
fnum[fcount] = number[digcnt-1]
gosub acceptdigit
fcount = fcount + 1
longcount = 0
pulses = 0 : digcnt = 0
ENDIF
ENDIF

ENDIF


'
'

IF fcount != 0 && shiftcount = 0 && donedtmf = 0 THEN
longcount = longcount + 1
IF longcount > 65000 THEN
IF donedtmf = 0 THEN
gosub dodtmf
@ clrwdt			; clear watchdog timer manually
PAUSE 500
@ clrwdt			; clear watchdog timer manually
PAUSE 500
donedtmf = 1
goto reset
ENDIF
ENDIF
ENDIF



'
'
'
goto cycle			' end main routine - do the next frame
'
'
senddigit:
LCDOUT $FE,$80
IF fcount > 0 THEN
FOR i = 0 TO fcount-1
LCDOUT " "
NEXT i
ENDIF
LCDOUT #number[digcnt]
shiftcount = 1
return
'
acceptdigit:
LCDOUT $FE,$01
LCDOUT $FE,$C0
FOR i = 0 TO fcount
LCDOUT #fnum[i]
NEXT i
tcount = 0

IF donedtmf = 1 THEN
DTMFOUT portb.4,[fnum[fcount]]
ENDIF


return
'
dodtmf:

IF fnum[0] = 1 && fnum[1] = 1 THEN
IF fnum[2] = 1 && fnum[3] = $FF THEN
fnum[0] = 0 : fnum[1] = 0 : fnum[2] = 0
emergency = 1
ENDIF
ENDIF


LCDOUT $FE,$01
LCDOUT $FE,$80
IF emergency = 0 THEN
LCDOUT "    DIALING...  "
ELSE
LCDOUT "   EMERGENCY!   "
ENDIF

LCDOUT $FE,$C0
FOR i = 0 TO fcount-1
LCDOUT #fnum[i]
NEXT i
FOR i = 0 TO fcount-1
@ clrwdt			; clear watchdog timer manually
DTMFOUT portb.4,[fnum[i]]
NEXT i
return
'
printerror:
'LCDOUT $FE,$01
LCDOUT $FE,$80
LCDOUT "                "
LCDOUT $FE,$C0
LCDOUT "    ON HOOK     "
LCDOUT $FE,$80
return
'
'
Cheers, Art.