首页  编辑  

DTMF生成

Tags: /超级猛料/Network.网络通讯/Modem/   Date Created:

下面为DSP中生成DTMF的代码:

DTMF Generation

The tone generator is suitable for multi channel operation as defined by DTMF_CHAN_MAX.  This allows us to use the same code to generate DTMF tones for a whole bunch of phone lines.

The actual tone is generated by a routine called dtmf_play(), which could be called at regular intervals from somewhere in your application to fill up a buffer with a block of DTMF samples.  Every time this routine runs, it decrements the play timer, until it eventually becomes zero.

Typically, one will either send telephone voice, or DTMF, so you need to add a call to dtmf_play() somewhere in your voice processing handler to generate one or more DTMF samples.  Bear in mind that you also need to zero the gaps between the tones, with a constant value (the last one generated by dtmf_play()), so there is some work for you to do to use this generator.

 

Sample Code

Example 2 is a multi channel DTMF modulator.  For debugging, it is best to play a single tone, e.g. 1kHz continuously, then look at it on an oscilloscope.  The tone should be clean, without discontinuities or sudden phase changes.  As soon as one tries to play two tones simultaneously, the 'scope picture becomes muddled.

 

 Example 2. Multi Channel DTMF Modulator

/*********************************************************************

* Filename:    dtmf.dsp

* Description: Multi channel DTMF modulator

*

* Copyright Aerospace Software Ltd., 1996

*

* Version      Author

* -------------------------------------------------------------------

* Feb 96       Herman Oosthuysen

*********************************************************************/

.MODULE DTMF;

#include "macro.h"

#define  DTMF_CHAN_MAX        4

#define  DTMF_CHAN_MASK       (DTMF_CHAN_MAX - 1)

#define  DTMF_TONE_SIZE       20

#if 1

#define  DTMF_PLAY_TIME       400   /* 400 = 50ms, 600 = 75ms */

#else

#define  DTMF_PLAY_TIME       4000  /* 4000 = 500ms for test and measuring */

#endif

#define  DTMF_SYMBOL_TIME     800   /* 100ms symbol time */

#define  DTMF_SIN_MASK        0x0FFF

#define  DTMF_NUMSTR_LENGTH   32

#define  DTMF_NUMSTR_MAX      (DTMF_NUMSTR_LENGTH * DTMF_CHAN_MAX)

/*

* DTMF global variables

*/

.VAR/DM

  dtmf_playtmr[DTMF_CHAN_MAX],

  dtmf_step1[DTMF_CHAN_MAX],

  dtmf_step2[DTMF_CHAN_MAX],

  dtmf_phase1[DTMF_CHAN_MAX],

  dtmf_phase2[DTMF_CHAN_MAX],

  dtmf_strtmr[DTMF_CHAN_MAX],

  dtmf_numstr[DTMF_NUMSTR_MAX],

  dtmf_numptr[DTMF_CHAN_MAX];

/*

* DTMF lookup tables in PM

*/  

.VAR/PM   DTMF_STEP1_TBL[DTMF_TONE_SIZE];

.INIT DTMF_STEP1_TBL:

  0x01e100,   /* 0 = 941Hz */

  0x016500,   /* 1 = 697Hz */

  0x016500,   /* 2 = 697Hz */

  0x016500,   /* 3 = 697Hz */

  0x018a00,   /* 4 = 770Hz */

  0x018a00,   /* 5 = 770Hz */

  0x018a00,   /* 6 = 770Hz */

  0x01b400,   /* 7 = 852Hz */

  0x01b400,   /* 8 = 852Hz */

  0x01b400,   /* 9 = 852Hz */

  0x01e100,   /* * = 941Hz */

  0x01e100,   /* # = 941Hz */

  0x016500,   /* A = 697Hz */

  0x018a00,   /* B = 770Hz */

  0x01b400,   /* C = 852Hz */

  0x01e100,   /* D = 941Hz */

  0x00b300,   /* dial tone = 350Hz */

  0x000000,   /* toot = 0Hz */

  0x000000,   /* beep = 0Hz */

  0x000000;   /* tweet = 0Hz */

 

.VAR/PM   DTMF_STEP2_TBL[DTMF_TONE_SIZE];

.INIT DTMF_STEP2_TBL:

  0x02ac00,   /* 0 = 1336Hz */

  0x026b00,   /* 1 = 1209Hz */

  0x02ac00,   /* 2 = 1336Hz */

  0x02f400,   /* 3 = 1477Hz */

  0x026b00,   /* 4 = 1209Hz */

  0x02ac00,   /* 5 = 1336Hz */

  0x02f400,   /* 6 = 1447Hz */

  0x026b00,   /* 7 = 1209Hz */

  0x02ac00,   /* 8 = 1336Hz */

  0x02f400,   /* 9 = 1447Hz */

  0x026b00,   /* * = 1209Hz */

  0x02f400,   /* # = 1477Hz */

  0x034400,   /* A = 1633Hz */

  0x034400,   /* B = 1633Hz */

  0x034400,   /* C = 1633Hz */

  0x034400,   /* D = 1633Hz */

  0x00e100,   /* dial tone = 440Hz */

  0x010000,   /* toot = 500Hz */

  0x020000,   /* beep = 1000Hz */

  0x040000;   /* tweet = 2000Hz */

 

.VAR/PM  DTMF_SIN_TBL[256];

.INIT    DTMF_SIN_TBL:

  0x000000, 0x032300, 0x064700, 0x096900, 0x0C8A00, 0x0FA900, 0x12C500, 0x15DF00,

  0x18F500, 0x1C0800, 0x1F1600, 0x221F00, 0x252300, 0x282100, 0x2B1900, 0x2E0B00,

  0x30F500, 0x33D800, 0x36B300, 0x398500, 0x3C4F00, 0x3F0F00, 0x41C500, 0x447200,

  0x471400, 0x49AA00, 0x4C3600, 0x4EB600, 0x512900, 0x539000, 0x55EA00, 0x583700,

  0x5A7700, 0x5CA800, 0x5ECB00, 0x60E000, 0x62E500, 0x64DB00, 0x66C200, 0x689900,

  0x6A6000, 0x6C1600, 0x6DBC00, 0x6F5100, 0x70D400, 0x724600, 0x73A700, 0x74F600,

  0x763200, 0x775D00, 0x787500, 0x797A00, 0x7A6D00, 0x7B4D00, 0x7C1A00, 0x7CD400,

  0x7D7A00, 0x7E0D00, 0x7E8D00, 0x7EF900, 0x7F5200, 0x7F9700, 0x7FC800, 0x7FE600,

  0x7FF000, 0x7FE600, 0x7FC800, 0x7F9700, 0x7F5200, 0x7EF900, 0x7E8D00, 0x7E0D00,

  0x7D7A00, 0x7CD400, 0x7C1A00, 0x7B4D00, 0x7A6D00, 0x797A00, 0x787500, 0x775D00,

  0x763200, 0x74F600, 0x73A700, 0x724600, 0x70D400, 0x6F5100, 0x6DBC00, 0x6C1600,

  0x6A6000, 0x689900, 0x66C200, 0x64DB00, 0x62E500, 0x60E000, 0x5ECB00, 0x5CA800,

  0x5A7700, 0x583700, 0x55EA00, 0x539000, 0x512900, 0x4EB600, 0x4C3600, 0x49AA00,

  0x471400, 0x447200, 0x41C500, 0x3F0F00, 0x3C4F00, 0x398500, 0x36B300, 0x33D800,

  0x30F500, 0x2E0B00, 0x2B1900, 0x282100, 0x252300, 0x221F00, 0x1F1600, 0x1C0800,

  0x18F500, 0x15DF00, 0x12C500, 0x0FA900, 0x0C8A00, 0x096900, 0x064700, 0x032300,

  0x000000, 0xFCDD00, 0xF9B900, 0xF69700, 0xF37600, 0xF05700, 0xED3B00, 0xEA2100,

  0xE70B00, 0xE3F800, 0xE0EA00, 0xDDE100, 0xDADD00, 0xD7DF00, 0xD4E700, 0xD1F500,

  0xCF0B00, 0xCC2800, 0xC94D00, 0xC67B00, 0xC3B100, 0xC0F100, 0xBE3B00, 0xBB8E00,

  0xB8EC00, 0xB65600, 0xB3CA00, 0xB14A00, 0xAED700, 0xAC7000, 0xAA1600, 0xA7C900,

  0xA58900, 0xA35800, 0xA13500, 0x9F2000, 0x9D1B00, 0x9B2500, 0x993E00, 0x976700,

  0x95A000, 0x93EA00, 0x924400, 0x90AF00, 0x8F2C00, 0x8DBA00, 0x8C5900, 0x8B0A00,

  0x89CE00, 0x88A300, 0x878B00, 0x868600, 0x859300, 0x84B300, 0x83E600, 0x832C00,

  0x828600, 0x81F300, 0x817300, 0x810700, 0x80AE00, 0x806900, 0x803800, 0x801A00,

  0x801000, 0x801A00, 0x803800, 0x806900, 0x80AE00, 0x810700, 0x817300, 0x81F300,

  0x828600, 0x832C00, 0x83E600, 0x84B300, 0x859300, 0x868600, 0x878B00, 0x88A300,

  0x89CE00, 0x8B0A00, 0x8C5900, 0x8DBA00, 0x8F2C00, 0x90AF00, 0x924400, 0x93EA00,

  0x95A000, 0x976700, 0x993E00, 0x9B2500, 0x9D1B00, 0x9F2000, 0xA13500, 0xA35800,

  0xA58900, 0xA7C900, 0xAA1600, 0xAC7000, 0xAED700, 0xB14A00, 0xB3CA00, 0xB65600,

  0xB8EC00, 0xBB8E00, 0xBE3B00, 0xC0F100, 0xC3B100, 0xC67B00, 0xC94D00, 0xCC2800,

  0xCF0B00, 0xD1F500, 0xD4E700, 0xD7DF00, 0xDADD00, 0xDDE100, 0xE0EA00, 0xE3F800,

  0xE70B00, 0xEA2100, 0xED3B00, 0xF05700, 0xF37600, 0xF69700, 0xF9B900, 0xFCDD00;

/*********************************************************************

* Name:        dtmf_init

* Description: initialize the DTMF modulator

* Constraints: none

*********************************************************************/

dtmf_init:

  MAC_ENTER

 

  ar = 0;

  cntr = DTMF_CHAN_MAX;

  do dtmf_init_loop until ce;

     MAC_WR_DM(0, ^dtmf_step1, ar)

     MAC_WR_DM(0, ^dtmf_step2, ar)

     MAC_WR_DM(0, ^dtmf_phase1, ar)

     MAC_WR_DM(0, ^dtmf_phase2, ar)

     MAC_WR_DM(0, ^dtmf_playtmr, ar)

     ar = ar + 1;

dtmf_init_loop: nop;

 

  MAC_EXIT

  rts;

 

 

/*********************************************************************

* Name:        dtmf_dial

* Description: lookup the step sizes for the two DTMF tones

* Constraints: ar = channel, ay1 = digit

*********************************************************************/

dtmf_dial:

  MAC_ENTER

  dis ints;

 

  ay0 = DTMF_CHAN_MAX;

  af = ar - ay0;

  if gt jump dtmf_dial_exit;

  ax0 = ar;

 

  ax1 = DTMF_TONE_SIZE;

  af = ax1 - ay1;

  if lt jump dtmf_dial_exit;

 

  /*

   * if a tone is already playing then

   *    it will be disrupted

   */

  MAC_RD_PM(ar, ^DTMF_STEP1_TBL, ay1)

  MAC_WR_DM(ar, ^dtmf_step1, ax0)

  MAC_RD_PM(ar, ^DTMF_STEP2_TBL, ay1)

  MAC_WR_DM(ar, ^dtmf_step2, ax0)

 

  MAC_WR_DM(0, ^dtmf_phase1, ax0)

  MAC_WR_DM(0, ^dtmf_phase2, ax0)

 

  ar = DTMF_PLAY_TIME;

  MAC_WR_DM(ar, ^dtmf_playtmr, ax0)

dtmf_dial_exit:

  ena ints;

  MAC_EXIT

  rts;

/*********************************************************************

* Name:        dtmf_play

* Description: play the tones until the timer expires

* Constraints: ar = channel

*********************************************************************/

dtmf_play:

  MAC_ENTER

     

  ay0 = ar;

 

  /*

   * if playtimer > 0 then

   *    decrement playtimer

   */

  MAC_RD_DM(ar, ^dtmf_playtmr, ay0)

  ar = pass ar;

  if eq jump dtmf_play_exit;

     ar = ar - 1;

     MAC_WR_DM(ar, ^dtmf_playtmr, ay0)

     

     /*

      * lookup two tone samples

      * mix tones

      * convert to 12 bit value

      */

     MAC_RD_DM(ay1, ^dtmf_step1, ay0)

     MAC_RD_DM(ar, ^dtmf_phase1, ay0)

     call dtmf_tone;

     

     ax1 = ar;

     ar = pass af;

     MAC_WR_DM(ar, ^dtmf_phase1, ay0)

     

     MAC_RD_DM(ay1, ^dtmf_step2, ay0)

     MAC_RD_DM(ar, ^dtmf_phase2, ay0)

     call dtmf_tone;

     

     ay1 = ar;

     ar = pass af;

     MAC_WR_DM(ar, ^dtmf_phase2, ay0)

     

     ar = ax1 + ay1;

     sr = ashift ar by -4 (lo);

     ar = sr0;

     /*

      * Compress Output

      * convert signed value to log value

      */

     tx1 = ar;

     nop;                                     /* one clock cycle needed for conversion */

     ar = tx1;

dtmf_play_exit:  

  MAC_EXIT

  rts;

/*********************************************************************

* Name:        dtmf_tone

* Description: DTMF tone generator

* Constraints: ar = step, ay1 = phase

*              returns ar = tone, af = phase

*********************************************************************/

dtmf_tone:

  MAC_QUICK_ENTER

  /*

   * calc new phase

   * lookup tone sample in sine table

   * drop level by 3dB

   * (Alternatively one can change the table for a lower level)

   */

  ar = ar + ay1;

  ay1 = DTMF_SIN_MASK;

  ar = ar AND ay1;

  af = pass ar;

 

  sr = lshift ar by -4 (lo);

  MAC_RD_PM(ar, ^DTMF_SIN_TBL, sr0)

 

  sr = ashift ar by -1 (lo);

  ar = sr0;

 

  MAC_QUICK_EXIT

  rts;

.ENDMOD;

/********************************************************************/