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.