******************************************************************** * DTMF.C - example program for generating DTMF tones using Direct * * Digital Synthesis. * **********************************************************************/ #include #include #define SAMPLE_RATE 10000 //10 kHz sample rate #define MAX_PHASE_ACCUM 0x10000 //16-bit phase accumulator overflow value /* Enumeration to identify DTMF characters */ enum DTMF_CHAR { DTMF_0, // digit 0 DTMF_1, // digit 1 DTMF_2, // digit 2 DTMF_3, // digit 3 DTMF_4, // digit 4 DTMF_5, // digit 5 DTMF_6, // digit 6 DTMF_7, // digit 7 DTMF_8, // digit 8 DTMF_9, // digit 9 DTMF_STAR, // char * DTMF_POUND, // char # DTMF_A, // char A DTMF_B, // char B DTMF_C, // char C DTMF_D // char D }; /* Table of sine waveform points. These are unsigned integers that vary */ /* around 128 and range as high as 255 and as low as 1. Values in this */ /* range are suitable for an 8-bit PWM register or unipolar DAC. For */ /* a bipolar DAC use signed values in whatever format works best. Bear */ /* in mind that you may need to average the two tones' sample values */ /* together to keep from overranging the DAC with the sum of both */ /* signals. */ /* The number of entries in this table corresponds to the number of */ /* bits of the phase accumulator used to index it. */ unsigned char sine_table[] = { 0x80, 0x83, 0x86, 0x89, 0x8C, 0x8F, 0x92, 0x95, 0x98, 0x9B, 0x9E, 0xA1, 0xA4, 0xA7, 0xAA, 0xAD, 0xB0, 0xB3, 0xB6, 0xB9, 0xBB, 0xBE, 0xC1, 0xC3, 0xC6, 0xC9, 0xCB, 0xCE, 0xD0, 0xD2, 0xD5, 0xD7, 0xD9, 0xDB, 0xDE, 0xE0, 0xE2, 0xE4, 0xE6, 0xE7, 0xE9, 0xEB, 0xEC, 0xEE, 0xF0, 0xF1, 0xF2, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF2, 0xF1, 0xF0, 0xEE, 0xEC, 0xEB, 0xE9, 0xE7, 0xE6, 0xE4, 0xE2, 0xE0, 0xDE, 0xDB, 0xD9, 0xD7, 0xD5, 0xD2, 0xD0, 0xCE, 0xCB, 0xC9, 0xC6, 0xC3, 0xC1, 0xBE, 0xBB, 0xB9, 0xB6, 0xB3, 0xB0, 0xAD, 0xAA, 0xA7, 0xA4, 0xA1, 0x9E, 0x9B, 0x98, 0x95, 0x92, 0x8F, 0x8C, 0x89, 0x86, 0x83, 0x80, 0x7C, 0x79, 0x76, 0x73, 0x70, 0x6D, 0x6A, 0x67, 0x64, 0x61, 0x5E, 0x5B, 0x58, 0x55, 0x52, 0x4F, 0x4C, 0x49, 0x46, 0x44, 0x41, 0x3E, 0x3C, 0x39, 0x36, 0x34, 0x31, 0x2F, 0x2D, 0x2A, 0x28, 0x26, 0x24, 0x21, 0x1F, 0x1D, 0x1B, 0x19, 0x18, 0x16, 0x14, 0x13, 0x11, 0x0F, 0x0E, 0x0D, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x11, 0x13, 0x14, 0x16, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x21, 0x24, 0x26, 0x28, 0x2A, 0x2D, 0x2F, 0x31, 0x34, 0x36, 0x39, 0x3C, 0x3E, 0x41, 0x44, 0x46, 0x49, 0x4C, 0x4F, 0x52, 0x55, 0x58, 0x5B, 0x5E, 0x61, 0x64, 0x67, 0x6A, 0x6D, 0x70, 0x73, 0x76, 0x79, 0x7C }; /* Tone pairs that correspond to DTMF characters in enumeration above */ struct DTMF_FREQ { unsigned short low_tone; unsigned short high_tone; } dtmf_freq[] = { 941, 1336, //digit 0 697, 1209, //digit 1 697, 1336, //digit 2 697, 1477, //digit 3 770, 1209, //digit 4 770, 1336, //digit 5 770, 1477, //digit 6 852, 1209, //digit 7 852, 1336, //digit 8 852, 1477, //digit 9 941, 1209, //char * 941, 1477, //char # 697, 1633, //char A 770, 1633, //char B 852, 1633, //char C 941, 1633 //char D }; /* Structure containing phase accumulators and phase increment */ /* values for the desired tone pair. Once this structure is */ /* initialized for a given DTMF digit or character, it can be */ /* used to keep generating tones indefinitely. */ struct DTMF_TONE { unsigned short low_phase_accum; //low tone phase accumulator unsigned short high_phase_accum; //high tone phase accumulator unsigned short low_phase_incr; //low tone phase increment unsigned short high_phase_incr; //high tone phase increment } dtmf_tone; /* Initialize DTMF tone structure with new character */ void new_tone(enum DTMF_CHAR dtmf_char) { unsigned long temp_increment; /* Zeroing phase accumulators makes both sine waves start at zero. */ /* If you want to transition smoothly from one tone to the next */ /* without the glitch caused by dropping to zero at the end of the */ /* previous tone, don't clear the phase accumulators. */ dtmf_tone.low_phase_accum = 0; dtmf_tone.high_phase_accum = 0; /* Calculate phase increments for low and high tones based on */ /* frequencies of each tone, phase accumulator size, and */ /* sample rate: */ /* phase increment = frequency * accumulator size / sample rate */ /* Use a long temporary because the max phase accumulator size */ /* is already 16 bits. */ temp_increment = dtmf_freq[dtmf_char].low_tone * MAX_PHASE_ACCUM; dtmf_tone.low_phase_incr = temp_increment / SAMPLE_RATE; temp_increment = dtmf_freq[dtmf_char].high_tone * MAX_PHASE_ACCUM; dtmf_tone.high_phase_incr = temp_increment / SAMPLE_RATE; } /* Get the next sample of the combined tone signal for the most */ /* recent DTMF character. Ordinarily this would be executed in */ /* a 10 kHz periodic interrupt and the returned value would be */ /* written to a DAC. */ unsigned short next_dtmf_sample(void) { unsigned short temp_sample; //for combining both tones' sample values /* Advance the low tone phase accumulator */ dtmf_tone.low_phase_accum += dtmf_tone.low_phase_incr; /* Look up the next sample of the sine wave using the upper 8 bits */ /* of the phase accumulator */ temp_sample = sine_table[dtmf_tone.low_phase_accum >> 8]; /* Now repeat the process for the high tone, adding the sample */ /* value to that for the low tone */ dtmf_tone.high_phase_accum += dtmf_tone.high_phase_incr; temp_sample += sine_table[dtmf_tone.high_phase_accum >> 8]; /* Average the two sample values so it won't overrange an 8-bit DAC */ return (temp_sample / 2); } void main(void) { int i; printf("Waveform sample set for DTMF Digit 1.\n"); printf("Redirect output to a file and graph to view waveform.\n"); /* Initialize DTMF generator for Digit 1 output. */ new_tone(DTMF_1); /* Assuming a sample rate of 10 kHz, issue 100 ms of tone samples */ for (i = 0; i < 1000; i++) { printf("%d\n", next_dtmf_sample()); } exit(0); }