
The example shows a method of generation of DTMF signal. The following assumptions have been adopted:




' This project is designed to work with PIC P30F6014A. It has been tested
' on dsPICPRO3 board with 10.0 MHz crystal and 8xPLL. It should work with any
' other crystal. Note: the maximum operating frequency for dsPIC is 120MHz.
' With minor adjustments, this example should work with any other dsPIC MCU
'
' On-board DAC module
' Enable SPI connection to DAC on SW4 and DAC's Load(LD) and Chip Select(CS) pins on SW3.
program DTMFout
' *** Filter Designer Tool outputs *** '
const
BUFFER_SIZE = 8
FILTER_ORDER = 3
COEFF_B as integer[FILTER_ORDER+1] = (0x21F3, 0x65DA, 0x65DA, 0x21F3)
COEFF_A as integer[FILTER_ORDER+1] = (0x2000, 0xB06D, 0x47EC, 0xE8B6)
SCALE_B = 6
SCALE_A = -2
' *** DAC pinout *** '
const LOAD_PIN = 2 ' DAC load pin
const CS_PIN = 1 ' DAC CS pin
dim
THalf_Low, THalf_High as word ' half-periods of low and high-frequency square signals
char2send as byte ' char recived from UART
sample, sending_ch_cnt as word ' digital signal sample, sending char counter
us_cntL, us_cntH as word ' low and high-frequency square signal microseconds counters
input_ as integer[BUFFER_SIZE] ' filter input signal (two square signals)
output as integer[BUFFER_SIZE] ' filtered signal
sample_index as word ' index of current sample
voltageL, voltageH as integer ' square signals amplitudes
sub procedure InitMain()
LATC.CS_PIN = 1 ' set DAC CS to inactive
LATC.LOAD_PIN = 0 ' set DAC LOAD to inactive
TRISC.LOAD_PIN = 0 ' configure DAC LOAD pin as output
TRISC.CS_PIN = 0 ' configure DAC CS pin as output
' Initialize SPI2 module
Spi2_Init_Advanced(_SPI_MASTER, _SPI_16_BIT, _SPI_PRESCALE_SEC_1, _SPI_PRESCALE_PRI_1,
_SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH,
_SPI_ACTIVE_2_IDLE)
Uart1_Init(9600) ' Initialize UART1 module
end sub
sub procedure DAC_Output(dim valueDAC as word)
LATC.CS_PIN = 0 ' CS enable for DAC
' filter output range is 16-bit number DAC input range is 12-bit number
valueDAC = valueDAC >> 4
' now both numbers are 12-bit but filter output is signed and DAC input is unsigned.
' Half of DAC range 4096/2=2048 is added to correct this
valueDAC = valueDAC + 2048
SPI2BUF = 0x3000 or valueDAC ' write valueDAC to DAC (0x3 is required by DAC)
while (SPI2STAT.1 = 1) ' wait for SPI module to finish sending
nop
wend
LATC.CS_PIN = 1 ' CS disable for DAC
end sub
sub procedure SetPeriods(dim ch as word)
' DTMF frequencies:
'
' 1209 Hz 1336 Hz 1477 Hz 1633 Hz
' 697 Hz 1 2 3 A
' 770 Hz 4 5 6 B
' 852 Hz 7 8 9 C
' 941 Hz * 0 # D
' Calculate half-periods in microseconds
' example: 1/697Hz = 0.001435 seconds = 1435 microseconds
' 1435/2 = 717
select case ch
case 49
THalf_Low=717 THalf_High=414 '1'
case 50
THalf_Low=717 THalf_High=374 '2'
case 51
THalf_Low=717 THalf_High=339 '3'
case 65
THalf_Low=717 THalf_High=306 'A'
case 52
THalf_Low=649 THalf_High=414 '4'
case 53
THalf_Low=649 THalf_High=374 '5'
case 54
THalf_Low=649 THalf_High=339 '6'
case 66
THalf_Low=649 THalf_High=306 'B'
case 55
THalf_Low=587 THalf_High=414 '7'
case 56
THalf_Low=587 THalf_High=374 '8'
case 57
THalf_Low=587 THalf_High=339 '9'
case 67
THalf_Low=587 THalf_High=306 'C'
case 42
THalf_Low=531 THalf_High=414 '*'
case 48
THalf_Low=531 THalf_High=374 '0'
case 35
THalf_Low=531 THalf_High=339 '#'
case 68
THalf_Low=531 THalf_High=306 'D'
end select
end sub
sub procedure ClearBufs()
'Clear buffers
Vector_Set(input_, BUFFER_SIZE, 0)
Vector_Set(output, BUFFER_SIZE, 0)
end sub
sub procedure Timer1Int org $1A ' interrupt frequency is 20kHz
' calculate sample
sample = voltageL + voltageH ' add voltages
input_[sample_index] = sample ' write sample to input buffer
' update low-frequency square signal microseconds counter
us_cntL = us_cntL + 50 ' since us_cntL and THalf_Low are in microseconds
' and Timer1 interrupt occures every 50us
' increment us_cntL by 50
if us_cntL > THalf_Low then ' half-period exceeded, change sign
voltageL = -voltageL
us_cntL = us_cntL - THalf_Low ' subtract half-period
end if
' update high-frequency square signal microseconds counter
us_cntH = us_cntH + 50
if us_cntH > THalf_High then
voltageH = -voltageH
us_cntH = us_cntH - THalf_High
end if
'IIR(amp), filtering new sample
sample = IIR_Radix(SCALE_B, SCALE_A, @COEFF_B, @COEFF_A, FILTER_ORDER+1,
@input_, BUFFER_SIZE, @output, sample_index)
DAC_Output(sample) ' send sample to digital-to-analog converter
output[sample_index] = sample ' write filtered sample in output buffer
Inc(sample_index) ' increment sample index, prepare for next sample
if sample_index = BUFFER_SIZE then
sample_index = 0
end if
Dec(sending_ch_cnt) ' decrement char sending counter
' (character transmition lasts 90ms = 1800 samples)
if sending_ch_cnt = 0 then ' if character transmition is over
T1CON=0 ' turn off Timer1
Delay_ms(200) ' pause between two characters is 200ms
end if
IFS0.3 = 0 ' clear Timer1 interrupt flag
end sub
' --- main --- '
main:
InitMain() ' perform initializations
sending_ch_cnt = 0 ' reset counter
sample_index = 0 ' initialize sample index
' Clear interrupt flags
IFS0 = 0
IFS1 = 0
IFS2 = 0
INTCON1 = $8000 ' disable nested interrupts
IEC0 = $0008 ' enable Timer1 interrupt
' Timer1 input clock is Fosc/4. Sampling frequency is 20kHz. Timer should
' raise interrupt every 50 microseconds. PR1 = (Fosc[Hz]/4) / 20000Hz = Fosc[kHz]/(4*20)
PR1 = Clock_kHz() div 80
' Note: interrupt routine execution takes ~10us
while true
if (sending_ch_cnt = 0) and ' check if sending of previous character is over
(Uart1_Data_Ready() = 1) then ' check if character arrived via UART1
char2send = Uart1_Read_Char() ' read data from UART and store it
SetPeriods(char2send) ' set periods for low and high-frequency square signals
ClearBufs() ' clear input and output buffers
' digital filter computing error is smaller for signals of higher amplitudes
' so signal amplitude should as high as possible. The highest value for
' signed integer type is 0x7FFF but since we are adding 2 signals we must
' divide it by 2.
voltageH = $7FFF div 2 ' high-frequency square signal amplitude
voltageL = $7FFF div 2 ' low-frequency square signal amplitude
us_cntL = 0 ' low-frequency square signal microseconds counter
us_cntH = 0 ' high-frequency square signal microseconds counter
' start Timer T1
sending_ch_cnt = 1800 ' character tansmition lasts 90ms = 1800 samples * 50us
T1CON = $8000 ' enable Timer1 (TimerOn, prescaler 1:1)
end if
wend
end.