Kronos Robotics and Electronics
Site Map
 
Home Zeus Projects App Notes Downloads Dios Athena Forums
 

DAN158

Generate DTMF with the Dios

 By Michael Simpson

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

 

 

Copyright © 2001 - 2007 Kronos Robotics