这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » DTMF,DTMF,PWM 双龙DTMF演示程序的两点疑问,做过DTMF(软件P

共3条 1/1 1 跳转至

DTMF,DTMF,PWM 双龙DTMF演示程序的两点疑问,做过DTMF(软件PWM方法)的请进

院士
2006-09-17 18:14:16     打赏
DTMF,DTMF,PWM 双龙DTMF演示程序的两点疑问,做过DTMF(软件PWM方法)的请进



关键词: 双龙     演示     程序     两点     疑问     做过     软件     方法         

院士
2006-12-22 22:43:00     打赏
2楼
问 这是双龙DTMF演示程序

#include <io8515v.h>
#include <macros.h>
#define  Xtal       8000000          // 系统时钟频率
#define  prescaler  1                // T1预分频系数
#define  N_samples  128              // 在查找表中的样本数
#define  Fck        Xtal/prescaler   // T1工作频率
#define  delaycyc   10               // 读取port C口延时循环数
#pragma interrupt_handler ISR_T1_Overflow:7
/*************************** 正弦表 *****************************
       样本表: 一个周期分成128个点,每点按7位进行量化
****************************************************************/
flash unsigned char auc_SinParam [128] =
{64,67,70,73,76,79,82,85,88,91,94,96,99,102,104,106,109,111,113,115,117,
118,120,121,123,124,125,126,126,127,127,127,127,127,127,127,126,126,125,
124,123,121,120,118,117,115,113,111,109,106,104,102,99,96,94,91,88,85,82,
79,76,73,70,67,64,60,57,54,51,48,45,42,39,36,33,31,28,25,23,21,18,16,14,
12,10,9,7,6,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,6,7,9,10,12,14,16,18,21,23,
25,28,31,33,36,39,42,45,48,51,54,57,60};
//***************************  x_SW  *************************
//   x_SW 表(8倍): x_SW = ROUND(8*N_samples*f*510/Fck)
//************************************************************
const unsigned char auc_frequencyH [4] = {
107,96,
87,79};
const unsigned char auc_frequencyL [4] = {
61,56,
50,46};


//**************************  全局变量 ****************************
unsigned char x_SWa = 0x00;               // 高频信号脉冲宽度
unsigned char x_SWb = 0x00;               // 低频信号脉冲宽度
unsigned int  X_LUTaExt = 0;                 
unsigned int  X_LUTbExt = 0;              
unsigned int  X_LUTa;                   
unsigned int  X_LUTb;                     

/*****************************************************************
                    定时器溢出中断服务程序
******************************************************************/
void ISR_T1_Overflow (void)
{
  X_LUTaExt += x_SWa;       
  X_LUTbExt += x_SWb;
  X_LUTa  =  (char)(((X_LUTaExt+4) >> 3)&(0x007F));
  X_LUTb  =  (char)(((X_LUTbExt+4) >> 3)&(0x007F));
           // 计算 PWM 值: 高频值 + 3/4 低频值
  OCR1A = (auc_SinParam[X_LUTa] + (auc_SinParam[X_LUTb]-(auc_SinParam[X_LUTb]>>2)));
}

/***********************************************************
                        初始化
***********************************************************/
void init (void)
{
  MCUCR=0x00;
  TIMSK  = 0x80;                     // T1 溢出中断使能
  TCCR1A = (1<<COM1A1)+(1<<PWM10);   // 不翻转、8位PWM
  TCCR1B = (1<<CS10);                // 预分频系数为1、即CLK/1
  DDRD   = (1 <<PD5);               // PD5 (OC1A)用作输出
  _SEI();                              // 全局中断使能
}
/*********************************************************************
      为从PORT C口读取稳定的按键数据,所必须的延时程序(消抖延时)
*********************************************************************/
void Delay (void)
{
  int i;
  for (i = 0; i < delaycyc; i++) _NOP();
}

/********************************************************************
                            主程序
      从PORT C口读取按键数据(如:SL+ AVR实验板) ,来确定产生哪个
      高频(列)和低频(行)信号的混合信号,并且修正 x_SWa 和 x_SWb。
                   行  -> PINC 高四位
                   列  -> PINC 低四位
*********************************************************************/

void main (void)
{
  unsigned char uc_Input;
  unsigned char uc_Counter = 0;
  init();
  for(;;){
     // 高四位 - 行
    DDRC  = 0x0F;           // 高四位输入、低四位输出
    PORTC = 0xF0;           // 高四位打开上位、低四位输出低电平
    uc_Counter = 0;
    Delay();                          // 延时等待 Port C 电平稳定
    uc_Input = PINC;                  // 读取 Port C
    do
    {
      if(!(uc_Input & 0x80))          // 检查MSB是否为低
      {
                                      // 取低音脉冲宽度并结束循环
        x_SWb = auc_frequencyL[uc_Counter];  
        uc_Counter = 4;
      }
      else
      {
        x_SWb = 0;                    // 没有频率调制要求
      }
      uc_Counter++;
      uc_Input = uc_Input << 1;       // 左移一位
    }
    while ((uc_Counter < 4));
    // 低四位 - 列
    DDRC  = 0xF0;          // 高四位输出、低四位输入
    PORTC = 0x0F;          // 高四位输出低电平、低四位打开上拉
    uc_Counter = 0;
    Delay();               // 延时等待 Port C 电平稳定
    uc_Input = PINC;
    uc_Input = uc_Input << 4;     
    do
    {
      if(!(uc_Input & 0x80))    // 检查 MSB 是否为低
      {
                                
        x_SWa = auc_frequencyH[uc_Counter];//取高音脉冲宽度并结束循环
        uc_Counter = 4;
      }
      else
      {
        x_SWa = 0;                 
      }
      uc_Counter++;
      uc_Input = uc_Input<< 1;
    }
     while (uc_Counter < 4);
  }
}


1: 关于两点疑问1:
DTMF音频矩阵的高频组为:
1209,1336,1477,1633
低频组为:697,770,852,941(Hz)
为什么在程序中定义为:
const unsigned char auc_frequencyH [4] = {
107,96,
87,79};
const unsigned char auc_frequencyL [4] = {
61,56,
50,46};
2:
atmel官方网站提供的查表算法为
X_LUTa=ROUND( (X_LUTaExt+8*N_samples*f*510/Fck) /8 )
程序中相应语句为:
x_SW = ROUND(8*N_samples*f*510/Fck)
X_LUTaExt += x_SWa;
X_LUTa  =  (char)(((X_LUTaExt+4) >> 3)&(0x007F));
其中的
((X_LUTaExt+4) >> 3)
怎么理解?
2: 第一个问题已经解决定义中
const unsigned char auc_frequencyH [4] = {
107,96,
87,79};
不是频率,是步长,是经过x_SW = ROUND(8*N_samples*f*510/Fck)
计算过的,如107=(8*128*1633*510)/8 000 000
我主观地认为auc_frequency就是频率的定义了
见笑了 3: 这么久了,都没有高人指点?我该怎么办呢? 4: 眼睁睁的看着它沉下去了,伤心 5: 请 把电路图  粘贴出来请 把电路图  粘贴出来
不然很难 解决 问题 6: 没有认真分析,简单提供一个想法而已atmel官方网站提供的查表算法为
X_LUTa=ROUND( (X_LUTaExt+8*N_samples*f*510/Fck) /8 )
程序中相应语句为:
x_SW = ROUND(8*N_samples*f*510/Fck)
X_LUTaExt += x_SWa;
X_LUTa  =  (char)(((X_LUTaExt+4) >> 3)&(0x007F));
其中的
((X_LUTaExt+4) >> 3)
怎么理解?

简单判断,仅为提供思路!
其中的(X_LUTaExt + 4)>>3有点象除以8!
7: TO:mylovetus AND 123654789TO:mylovetus
其中的(X_LUTaExt + 4)>>3其中>>3除以8很容易理解
但是+ 4的涵义我一直搞不懂
TO:123654789
电路图我也没有,我仅仅是研究算法,我觉得这跟硬件关系不大,很显然是个4*4键盘扫描电路,我觉得这跟硬件关系不大,关键是产生DTMF信号的算法实现
不过,要谢谢两位热心人
等待再有高人指点 8: 我自己顶! 9: 我再顶... 10: TO 94+4应该是为了调整进位,用来划分比例查表,N=x*1/4的关系。
比例对应0-3对应0
       4-7对应1
       。。。。
11: 若有所悟!但是划分查表的意义何在?划分比例查表到底是怎么回事?都在什么地方有应用?还请极限大哥好人做到底,再点化一下小弟,不胜感激! 12: 呵呵到ATMEL 网站上去看看 那里又详细介绍

不过该程序产生的软件DTMF波还不能用于电话网,需要外加电路

如果真要发DTMF还是用硬件(HT9200)比较可靠 13: 我做过用5个I/O再加R-2R电阻网络做D/A的DTMF发生。我用的51,没PWM,但我想软件上核心是一样的。我的东西已经做成产品了,在省内各偏僻农村用做小数据传输,效果很好。
我没看你写的代码,我也看不懂,跟你讲讲思路,可能更有效。
Fdtmf=Fh+0.9Fl;这里的系数0.9我记不太清了标准是多少了,只告诉你原因:高频群在传输时衰减较大,所以发送时做大点,这样到达交换机时和低频群信号强度差不多,试验时可忽略这系数,程序简单点,城里用没一点问题。
好了说正题,显然你应该知道了基本思路就是用一个较高的采样频率,计算每个采样时刻的Fdtmf值,然后送到I/O口或刷新PWM寄存器。我做的5位D/A采样周期小于60US,我没条件做试验,据我另一个朋友讲,采样频率比DA分辨率更重要,当然分辨率高点,采样率可低点。
f=sin(2*pi*f*t),设采样周期为T,则
f=sin(2*pi*f*T*n),其中,2*pi*f*T是一个随f不同而不同的纯小数,n=0,1,2,,,,,,,N.对应各采样时刻。DTMF持续时间=N*T。显然为了不算SIN,我们就需要一个SIN表。
我们只需每时刻把2*pi*f*T加上上次的值(初始值显然是零),然后查表就可以得到当前时刻得频率幅度了。

基本原理就这么简单,也许难理解的是技巧。
技巧如下:
如果是51,它有10进制加法指令,这样,最直观的,我们把2*pi*f*T保留两个字节(考虑误差允许),每时刻做十进制累加就可以了。理解最关键的一点(个人认为,呵呵),这样的双字节加法正好不要考虑溢出,也就是正好不要考虑累加的整数部分。整数部分的物理意义是什么?它表示正弦波的周期数,而正弦波是周期函数,计算幅度时不用考虑的。查表的时候取累加和的第一个字节就可以了,记住,这时SIN表是分成100等份的。
这样,每时刻高频群算一次SIN幅度值,低频群算一次SIN幅度值,加起来就是DTMF当前幅度值了。
当用的单片机没有十进制加法时,用其他指令去模拟也是可以的,有没有更好的办法呢?有。
令1.0000(十进制)=10000H(16进制)则2*pi*f*T=?
这样我们就可以用最基本的2进制加法了,每个单片机都有的指令,而且更方便。这时,SIN表是256等份的。
其他:T原则上是随便取的,当然应该是定时器的整数值,而且越小越好;
      如果用0.9的系数,最简单的是做个0.9*sin的表;
      如果嫌表大,可以再利用对称性把表做小点;
      效果是相当好的,我做的软DTMF指标在仪器上测比硬件做的还好。
14: 好人啊,感激涕零!!! 15: 顶teddeng ,好! 16: 我的道理是说清楚了,但有个明显的错误不更正了,正好让你想想,呵呵。 17: 由于发现了我解释中的错误谨慎起见,还是看了ATMEL的文档。结论:放心,思路是一样的,我解释得直观点,精度保守起见高点(代价应该是多两个字节RAM)。
+4的意思费好大劲才想通,这个例子里不加也没关系,但这样才是严谨的。想通了很简单,就是+0.5的意思。即算出是10.5XX时,按11查表,而不是按10查表。从表达式看不影响长期累加精度。 18: teddeng大哥太热心了,我太感动了

高工
2022-08-20 16:03:09     打赏
3楼

学习学习


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]