I had an application where I needed to enter numeric
information over the phone line and decided to experiment with sending the
numbers with the Dios. DTMF tones are a combination of two tones
used to represent a key on the keypad. The characters 0-9 and #* are
represented.
| |
1209 |
1336 |
1477 |
| 697 |
1 |
2 |
3 |
| 770 |
4 |
5 |
6 |
| 852 |
7 |
8 |
9 |
| 941 |
* |
0 |
# |
The frequencies are in the form of rows and columns as
shown above. The send a 1 you would send the tones 1209 and 697.
Don't be Square
To properly mix the two tones they must be analog sine
waves. Microcontrollers create very nice square waves but
these signals wont work for generating sine waves. To create a
accurate sign wave we need a digital to analog converter. You can
use an R-2R ladder to create a nice analog to digital converter but this
requires 16 resistors for each channel. I decided to us the built-in
PWM generators to create the two analog signals so that they could be
mixed.
The hardware PWM frequency is set to 39.2Khz. We
will set the duty cycle of this frequency at particular intervals for each
tone. By changing the duty cycle and passing the signals through a
simple low pass RC filter we strip the 39.2Khz frequency and pass just the
modulated level. The larger the duty cycle the higher the output
voltage. The output will be in the form of a sine wave.
In order to create the frequencies needed for the DTMF we
need to to change the duty cycle of the two channels at over 1000 times a
second. We use inline assembly to do this. A lookup table for
each tone is used. Each table contains the analog levels for each
tone as it goes through at least one complete cycle. The 127 at the
end of each table represents the end of the cycle/s. Note that a few
of the tones are more than one cycle. This is done to tweak the
frequency closer to that needed.
Dios Hookup

!Important!!
The MC24119 is no longer available. You may also use a transistor
to drive the speaker.
The output of the two DTMF tones input to the filter at R3
and R4 from IO ports 4 and 13. The filter output is sent to R1.
This signal is to low to drive a speaker directly so we will use a MC34119
amplifier to drive the speaker. By placing the headset mouth piece
over the speaker you can dial the number of your choice.
The main routine for DTMF generator is dtmfout function.
You pass a string with the numbers you want to dial and the duration of
each character.
Note that if you need to tweak the output frequencies you
can change the main delay routine:
'----------------------------
ASMDTMFdoprocdtmf
clrf ACUMEH
movlw .33
movwf ACUMEL
call pauseus
If you change the value in ACUMEL to a lower number the
frequencies will go up. Increasing the number will lower the
frequencies. I suppose one could actually use a look up table
to create the exact frequency for each tone. I found the current
setting worked quite well for my application.
The Program (download
it here)
'DTMF Dialer
func main()
dtmfout("703-779-9752",3000)
endfunc
'---------------------------------------------------
'Will Dial DTMF Digits in passed string.
'0123456789#* All other digits ignored
', is a single char delay
'---------------------------------------------------
'Proagram uses all the ASMDAT registers and restores
'TBLPTR registers
'---------------------------------------------------
func dtmfout(addr,duration)
dim y as integer
'Setup PWM generator
PR2=255
T2CON=4
output 4,13
CCP2CON=12
CCPR2L=128
CCP1CON=12
CCPR1L=128
again:
getstringbyte addr,y,done 'Pull character out of string.
'print y
if y >= 48 and y <= 57 then
goto senddtmf
endif
if y = 35 then
y = 59
goto senddtmf
endif
if y = 42 then
y = 58
goto senddtmf
endif
if y = 44 then
pause duration / 50
pause duration / 50
endif
goto again
done:
exit(0)
senddtmf:
ASMDAT11 = y - 48
ASMDAT12 = duration.byte(0)
ASMDAT13 = duration.byte(1)
startasm
'Backup Table pointers. The Dios Engine uses them.
movff TBLPTRL,ASMDAT8
movff TBLPTRH,ASMDAT9
movff TBLPTRU,ASMDAT10
movf ASMDAT11,w
mullw .4
movf PRODH,w
addlw high ASMDTMFtprocthekeys
movwf PCLATH
movf PRODL,w
addlw low ASMDTMFtprocthekeys
btfsc STATUS,C
incf PCLATH,f
movwf PCL
ASMDTMFtprocthekeys
goto ASMDTMFkey0
goto ASMDTMFkey1
goto ASMDTMFkey2
goto ASMDTMFkey3
goto ASMDTMFkey4
goto ASMDTMFkey5
goto ASMDTMFkey6
goto ASMDTMFkey7
goto ASMDTMFkey8
goto ASMDTMFkey9
goto ASMDTMFkeyA
goto ASMDTMFkeyP
ASMDTMFkey0
movlw low ASMDTMFrow4
movwf ASMDAT0
movlw high ASMDTMFrow4
movwf ASMDAT1
movlw low ASMDTMFcolumn2
movwf ASMDAT2
movlw high ASMDTMFcolumn2
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey1
movlw low ASMDTMFrow1
movwf ASMDAT0
movlw high ASMDTMFrow1
movwf ASMDAT1
movlw low ASMDTMFcolumn1
movwf ASMDAT2
movlw high ASMDTMFcolumn1
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey2
movlw low ASMDTMFrow1
movwf ASMDAT0
movlw high ASMDTMFrow1
movwf ASMDAT1
movlw low ASMDTMFcolumn2
movwf ASMDAT2
movlw high ASMDTMFcolumn2
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey3
movlw low ASMDTMFrow1
movwf ASMDAT0
movlw high ASMDTMFrow1
movwf ASMDAT1
movlw low ASMDTMFcolumn3
movwf ASMDAT2
movlw high ASMDTMFcolumn3
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey4
movlw low ASMDTMFrow2
movwf ASMDAT0
movlw high ASMDTMFrow2
movwf ASMDAT1
movlw low ASMDTMFcolumn1
movwf ASMDAT2
movlw high ASMDTMFcolumn1
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey5
movlw low ASMDTMFrow2
movwf ASMDAT0
movlw high ASMDTMFrow2
movwf ASMDAT1
movlw low ASMDTMFcolumn2
movwf ASMDAT2
movlw high ASMDTMFcolumn2
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey6
movlw low ASMDTMFrow2
movwf ASMDAT0
movlw high ASMDTMFrow2
movwf ASMDAT1
movlw low ASMDTMFcolumn3
movwf ASMDAT2
movlw high ASMDTMFcolumn3
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey7
movlw low ASMDTMFrow3
movwf ASMDAT0
movlw high ASMDTMFrow3
movwf ASMDAT1
movlw low ASMDTMFcolumn1
movwf ASMDAT2
movlw high ASMDTMFcolumn1
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey8
movlw low ASMDTMFrow3
movwf ASMDAT0
movlw high ASMDTMFrow3
movwf ASMDAT1
movlw low ASMDTMFcolumn2
movwf ASMDAT2
movlw high ASMDTMFcolumn3
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkey9
movlw low ASMDTMFrow3
movwf ASMDAT0
movlw high ASMDTMFrow3
movwf ASMDAT1
movlw low ASMDTMFcolumn3
movwf ASMDAT2
movlw high ASMDTMFcolumn3
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkeyA
movlw low ASMDTMFrow4
movwf ASMDAT0
movlw high ASMDTMFrow4
movwf ASMDAT1
movlw low ASMDTMFcolumn1
movwf ASMDAT2
movlw high ASMDTMFcolumn1
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFkeyP
movlw low ASMDTMFrow4
movwf ASMDAT0
movlw high ASMDTMFrow4
movwf ASMDAT1
movlw low ASMDTMFcolumn3
movwf ASMDAT2
movlw high ASMDTMFcolumn3
movwf ASMDAT3
goto ASMDTMFdtmfstart
ASMDTMFdtmfstart
movff ASMDAT0,ASMDAT4
movff ASMDAT1,ASMDAT5
movff ASMDAT2,ASMDAT6
movff ASMDAT3,ASMDAT7
ASMDTMFagain:
dcfsnz ASMDAT12,f
decf ASMDAT13,f
movf ASMDAT13,f
btfsc STATUS,Z
goto ASMDTMFalldone
'----------------------------
'Read Row
movff ASMDAT4,TBLPTRL
movff ASMDAT5,TBLPTRH
TBLRD*+
movff TABLAT,CCPR1L
movlw .127
subwf TABLAT,w
btfsc STATUS,Z
goto ASMDTMFresetrow
infsnz ASMDAT4,f
incf ASMDAT5,f
'----------------------------
'Read col
ASMDTMFdocol
movff ASMDAT6,TBLPTRL
movff ASMDAT7,TBLPTRH
TBLRD*+
movff TABLAT,CCPR2L
movlw .127
subwf TABLAT,w
btfsc STATUS,Z
goto ASMDTMFresetcol
infsnz ASMDAT6,f
incf ASMDAT7,f
'----------------------------
ASMDTMFdoprocdtmf
clrf ACUMEH
movlw .33
movwf ACUMEL
call pauseus
goto ASMDTMFagain
ASMDTMFresetcol
movff ASMDAT2,ASMDAT6
movff ASMDAT3,ASMDAT7
goto ASMDTMFdoprocdtmf
ASMDTMFresetrow
movff ASMDAT0,ASMDAT4
movff ASMDAT1,ASMDAT5
goto ASMDTMFdocol
ASMDTMFrow1
DB .149,.170,.190,.208,.224,.236,.246,.253
DB .255,.254,.250,.242,.230,.216,.199,.180
DB .160,.138,.117,.095,.075,.056,.039,.025
DB .013,.005,.001,.000,.002,.009,.019,.031
DB .047,.065,.085,.106,.127,.000,.000,.000
ASMDTMFrow2
DB .152,.175,.197,.216,.232,.244,.252,.255
DB .254,.248,.238,.224,.207,.186,.164,.140
DB .115,.091,.069,.048,.031,.017,.007,.001
DB .000,.003,.011,.023,.039,.058,.080,.103
DB .127,.000,.000,.000
ASMDTMFrow3
DB .154,.180,.203,.223,.238,.249,.255,.255
DB .249,.238,.223,.203,.180,.154,.128,.101
DB .075,.052,.032,.017,.006,.000,.000,.006
DB .017,.032,.052,.075,.101,.127,.0,.0
ASMDTMFrow4
DB .157,.185,.210,.230,.245,.254,.255,.250
DB .238,.221,.198,.171,.142,.113,.084,.057
DB .034,.017,.005,.000,.001,.010,.025,.045
DB .070,.098,.127,.00
ASMDTMFcolumn1
DB .165,.200,.228,.247,.255,.252,.238,.215
DB .183,.147,.108,.072,.040,.017,.003,.000
DB .008,.027,.055,.090,.127,.000,.000,.000
ASMDTMFcolumn2
DB .169,.206,.235,.252,.255,.245,.222,.188
DB .149,.106,.067,.033,.010,.000,.003,.020
DB .049,.086,.127,.00
ASMDTMFcolumn3
DB .173,.212,.241,.255,.252,.233,.200,.158
DB .112,.068,.032,.008,.000,.008,.032,.068
DB .112,.158,.200,.233,.252,.255,.241,.212
DB .173,.128,.082,.043,.014,.000,.003,.022
DB .055,.097,.143,.187,.223,.247,.255,.247
DB .223,.187,.143,.097,.055,.022,.003,.000
DB .014,.043,.082,.127
ASMDTMFalldone
movff ASMDAT8,TBLPTRL
movff ASMDAT9,TBLPTRH
movff ASMDAT10,TBLPTRU
endasm
pause duration / 50
goto again
endfunc
The bulk of the program is the lookup table for setting the offset for the
Row and Column duty cycle tables.
Parts
Breadboard Speaker
DiosPro 40 Pin Chip
Dios Workboard
Deluxe
Easy RS232 Driver
DiosPro 28 Pin Chip
Dios 32 Pin Carrier
(Carrier #1)
9 Pin Cable
Breadboard Regulator