搜索
bottom↓
回复: 14

[原创]AVR发送DTMF信号

[复制链接]

出0入0汤圆

发表于 2006-6-20 13:28:09 | 显示全部楼层 |阅读模式
虽然ATMEL的AVR314已经提供了一个DTMF发生器的实现,但是我这个实现方法和那个是不同的:

1.AD转换:AVR314使用PWM方式,我的使用6位R-2R电阻网络;

2.波形生成:AVR314使用查表方式,我的则使用一个著名的递归算法公式(我忘了名字了:)



程序使用嵌入式汇编编写,在M8上通过。

公式如图,实际实现中考虑8位定点运算做了些调整。





看程序吧。

出0入0汤圆

 楼主| 发表于 2006-6-20 13:30:08 | 显示全部楼层
常数定义,初始化。



////////////////////////////////////////////////////////////////

//  

//    DTMF/TONE发生器。使用定时中断1

//

//  输入参数:  

//  返回值:   

//  TIMER1 initialize - prescale:8

//  WGM: 0) Normal, TOP=0xFFFF

//  desired value: 10KHz

//  actual value: 10.000KHz (0.0%)

//

//  注释:

//

////////////////////////////////////////////////////////////////



// 定义号码0-9,*,#,A-D对应的低频、高频K值和y[n-2]的值。

#define K_L1 116

#define K_L2 113

#define K_L3 110

#define K_L4 106

#define K_H1 93

#define K_H2 85

#define K_H3 77

#define K_H4 66



#define Y2L1 111

#define Y2L2 110

#define Y2L3 108

#define Y2L4 106

#define Y2H1 100

#define Y2H2 98

#define Y2H3 95

#define Y2H4 93



// 定义单音信号的K值和y[n-2]的值。

#define TONE_K 123      //450Hz

#define TONE_Y2 118



unsigned char bEnableGen;

unsigned char k[2];

unsigned char y1[2];

unsigned char y2[2];



// 初始化定时器1

void timer1_init(void)

{

    TCCR1B = 0x00; //stop

    TCNT1H = 0xFF; //setup

    TCNT1L = 0x6A;

    OCR1AH = 0x00;

    OCR1AL = 0x96;

    OCR1BH = 0x00;

    OCR1BL = 0x96;

    ICR1H  = 0x00;

    ICR1L  = 0x96;

    TCCR1A = 0x00;

    TCCR1B = 0x02; //start Timer

   

    bEnableGen = DISABLE;

}

出0入0汤圆

 楼主| 发表于 2006-6-20 13:31:43 | 显示全部楼层
定时中断服务程序



#pragma interrupt_handler timer1_ovf_isr:9

void timer1_ovf_isr(void)

{

    //TIMER1 has overflowed

    TCNT1H = 0xFF; //reload counter high value

    TCNT1L = 0x6A; //reload counter low value

    if( bEnableGen == ENABLE )

    {

        asm(

            "st -y,r0
"

            "st -y,r1
"

            "st -y,r2
"

            "st -y,r3
"

            "st -y,r16
"

            

            "ldi r16,0x80
"

            );

        

        // compute sin signal. Use: y[n] = k*y[n-1] - y[n-2]

        //   with offset 128 and gain 64

        //   it to: y[n] = K*y[n-1]/64 - 2*K - y[n-2]

        //         K = k*64

        asm(

            "lds r2,%k+0
"

            "lds r3,%y1+0
"

            "mul r2,r3
"

            "rol r0
"

            "rol r1
"

            "rol r0
"

            "rol r1
"

            "sub r1,r2
"

            "sub r1,r2
"

            "lds r2,%y2+0
"

            "sts %y2+0,r3
"

            "sub r1,r2
"

            "sts %y1+0,r1
"

            "add r16,r1
"

            );

        asm(

            "lds r2,%k+1
"

            "lds r3,%y1+1
"

            "mul r2,r3
"

            "rol r0
"

            "rol r1
"

            "rol r0
"

            "rol r1
"

            "sub r1,r2
"

            "sub r1,r2
"

            "lds r2,%y2+1
"

            "sts %y2+1,r3
"

            "sub r1,r2
"

            "sts %y1+1,r1
"

            "add r16,r1
"

            );

        asm(

            "lsr r16
"

            "lsr r16
"

            "out 0x18,r16
"

            

            "ld r16,y+
"

            "ld r3,y+
"

            "ld r2,y+
"

            "ld r1,y+
"

            "ld r0,y+
"

            );

    }   

}

出0入0汤圆

 楼主| 发表于 2006-6-20 13:34:30 | 显示全部楼层
数据初始化,帮助函数



const unsigned char Tone_K = TONE_K;

const unsigned char Tone_Y2 = TONE_Y2;



////////////////////////////////////////////////////////////////

//  InitDTMFGenerator

//    初始化音调发生器。

//

//  输入参数:  无

//  返回值:    无

//

//  注释:

//

////////////////////////////////////////////////////////////////

void InitDTMFGenerator( void )

{

    bEnableGen = DISABLE;

    k[0] = k[1] = 0;

    y1[0] = y1[1] = 128;

    y2[0] = y2[1] = 128;

    bEnableGen = ENABLE;

   

}



////////////////////////////////////////////////////////////////

//  SendDTMF

//    发送DTMF信号。

//

//  输入参数:  code    发送的符号,1-10代表数字1-9,0,11=*,

//                  12=#,13-15=ABC,0=D,其他则关闭DTMF信号。

//                  也可以直接输入字符'0'-'9','*','#','A'-'D'

//                  其他值则关闭发送

//  返回值:    无

//

//  注意:二进制0发送DTMF信号'D',二进制10才发送信号'0'。

//

////////////////////////////////////////////////////////////////

void SendDTMF( unsigned char code ) // Code = D1234567890*#ABC ~0-15

{

    static const unsigned char aCodeMap[] = "D1234567890*#ABC";

    static const unsigned char K_L[] = { K_L4, K_L1, K_L1, K_L1, K_L2, K_L2, K_L2, K_L3, K_L3, K_L3, K_L4, K_L4, K_L4, K_L1, K_L2, K_L3, 0 };

    static const unsigned char Y2L[] = { Y2L4, Y2L1, Y2L1, Y2L1, Y2L2, Y2L2, Y2L2, Y2L3, Y2L3, Y2L3, Y2L4, Y2L4, Y2L4, Y2L1, Y2L2, Y2L3, 128 };

    static const unsigned char K_H[] = { K_H4, K_H1, K_H2, K_H3, K_H1, K_H2, K_H3, K_H1, K_H2, K_H3, K_H2, K_H1, K_H3, K_H4, K_H4, K_H4, 0 };

    static const unsigned char Y2H[] = { Y2H4, Y2H1, Y2H2, Y2H3, Y2H1, Y2H2, Y2H3, Y2H1, Y2H2, Y2H3, Y2H2, Y2H1, Y2H3, Y2H4, Y2H4, Y2H4, 128 };

   

    unsigned char n;

   

    if( code < 16 )

    {

        n = code;

    }

    else

    {

        for( n = 0; n < 16; ++n )

        {

            if( code == aCodeMap[ n ] )

                break;

        }

    }

   

    bEnableGen = DISABLE;

    k[0] = K_L[ n ];

    k[1] = K_H[ n ];

    y2[0]= Y2L[ n ];

    y2[1]= Y2H[ n ];

    y1[0] = y1[1] = 128;

    bEnableGen = ENABLE;

   

}



////////////////////////////////////////////////////////////////

//  SendTone

//    发送单音信号

//

//  输入参数:  tone    当tone=ENABLE时,发送450Hz的单音信号,

//                  其他值则关闭发送。

//  返回值:    无

//

//  注释:

//

////////////////////////////////////////////////////////////////

void SendTone( unsigned char tone )



{

    bEnableGen = DISABLE;

    if( tone == ENABLE )

    {

        k[0] = Tone_K;

        y2[0] = Tone_Y2;

    }

    else

    {

        k[0] = 0;

        y2[0] = 128;

    }

    y1[0] = 128;

   

    k[1] = 0;

    y2[1] = 128;

    y1[1] = 128;

    bEnableGen = ENABLE;

   

}


-----此内容被mored于2006-06-20,13:38:04编辑过

出0入0汤圆

发表于 2006-6-20 14:12:36 | 显示全部楼层
太高深了,我的盲区太宽了!

出0入0汤圆

发表于 2006-6-20 17:10:56 | 显示全部楼层
牛!

出0入0汤圆

发表于 2006-6-20 23:03:55 | 显示全部楼层
太长了,看不下啦

出0入0汤圆

发表于 2006-6-20 23:10:19 | 显示全部楼层
有创意

不知道能不能用AVR解DTMF码呢?

出0入0汤圆

发表于 2006-6-21 07:41:34 | 显示全部楼层
解DTMF码,可以参考: "Generation and Recognition of DTMF Signals with the Microcontroller MSP430"

http://focus.ti.com/lit/an/slaae16/slaae16.pdf

出0入0汤圆

发表于 2006-6-22 00:42:03 | 显示全部楼层
thanks

出0入0汤圆

发表于 2006-6-28 13:55:22 | 显示全部楼层
大哥!

传个原理图!

谢谢

出0入0汤圆

发表于 2006-6-29 08:04:41 | 显示全部楼层
朋友,上个电路。

出0入0汤圆

发表于 2010-6-8 07:46:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-8 14:03:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-14 15:08:09 | 显示全部楼层
mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-7 13:01

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表