Ansifa 发表于 2011-11-27 14:22:13

Arduino学习笔记A9 - Arduino自制电话拨号器

Arduino自制电话拨号器

怎么拨打电话?也许这个问题很简单:拿起话筒,按话机的数字键盘拨号码。
但是,有没想过,我们可以拿起电话,不需要碰话机键盘就能拨通电话?答案是肯定的。
下面就介绍如何用Arduino生成双音多频信号。

用法介绍:
使用时候,我们拿起电话话筒,将喇叭贴近话筒麦克风位置。在串口发送需要拨号的电话号码(比如10000),稍等片刻即可拨通。

扩展用法:
驱动开关模拟电话摘机事件,用此电路拨号,再由Arduino按照事件控制语音模块(WT588D等)发出不同的语音到电话线。即可完成一个整体的自动拨号机,可以制作报警器,或者电话提醒器。

材料清单:
Arduino一块,
喇叭1个,
100Ω电阻1个(可以选择100Ω~1kΩ),
1uF电容两个(可以选择0.1uF~10uF)。

硬件连接:

程序代码:

1. 下载Tone库,并且解压到arduino-0022\libraries文件夹:
http://rogue-code.googlecode.com/files/Arduino-Library-Tone.zip
此Tone库相比自带的tone函数特点是,可以同时在多个输出脚输出不同频率的波形,但是自带tone函数在一段时间内只能在一个引脚输出。

2.写入下面代码到Arduino:
/*
使用Arduino生成双音多频
Ansifa        2011/11/27

* 软件:需要Tone库,下载地址:http://rogue-code.googlecode.com/files/Arduino-Library-Tone.zip
* 材料:喇叭1个,100Ω电阻1个,1uF电容两个
* 硬件连接:在D11,D12引脚各接一个1uF电容,之后合并到100Ω电阻一端,
100Ω电阻另一端接喇叭,然后喇叭另一端接地。

用法,将喇叭贴近电话机话筒,然后发送要拨的电话号码到串口,比如10000,即可拨通电话10000
*/

#include <Tone.h>

String Phone_Number = "";
int i = 0, mark = 0;

//定义freq1,freq2为Tone实例,并且定义双音多频的频率
//DTMF频率定义参见:http://zh.wikipedia.org/zh/%E5%8F%8C%E9%9F%B3%E5%A4%9A%E9%A2%91
Tone freq1;
Tone freq2;
const int DTMF_freq1[] = {1336, 1209, 1336, 1477, 1209, 1336, 1477, 1209, 1336, 1477};
const int DTMF_freq2[] = {941,697,697,697,770,770,770,852,852,852};

void setup()
{
    Serial.begin(9600);
    //定义声音产生引脚在Arduino的D11,D12
    freq1.begin(11);
    freq2.begin(12);
}

void loop()
{
    //读出串口数据,串接成Phone_Number字符串
    while (Serial.available() > 0)
    {
      Phone_Number += char(Serial.read());
      delay(2);
      mark = 1;
    }
    //播放DTMF音频,电话号码来自Phone_Number,持续长度200ms,间隔长度300ms
    PlayDTMF(Phone_Number, 200, 300);
       
        //如果刚才接收到串口的电话号码,因为号码已经在喇叭输出了,清空电话号码并且重置mark
    if(mark == 1)
    {
      Phone_Number = "";
      Serial.println();
      mark = 0;
    }
}

/*
DTMF播放函数
调用格式:playDTMF(数字(0~9), 持续时间)。
*/
void PlayDTMF(String Number, long duration, long pause)
{
        //如果输入数字为空,或者持续时间不为正数,或者暂停时间不为正数
        //则视作错误,立即停止执行返回主程序。
    if(Number.length() == 0 || duration <= 0 || pause <= 0) return;
    //将Number逐个文字分离,
    for(i = 0; i < Number.length(); i++)
    {
      //如果Number属于0~9的数字字符,
      if(Number >= '0' && Number <= '9')
      {
            //则将它ASCII码减去‘0’,得到纯数字,
            Number -= '0';
            //然后在串口输出一份,便于查看
            Serial.print(Number, DEC);
            //输出双音多频之一
            freq1.play(DTMF_freq1], duration);
            //输出双音多频之二
            freq2.play(DTMF_freq2], duration);
            delay(pause);
      }
    }


}打包下载:

实物效果:

1. 电路连接

2. 喇叭靠近电话拨号

3. 串口端发电话号码

4. 等待喇叭响完拨号音之后,即可听到10000号的应答


弘毅 发表于 2011-11-27 14:51:16

{:soso_e103:}好高级

wali 发表于 2011-11-27 23:37:55

神奇啊 这什么原理啊 手机也行么{:soso_e103:} 太牛了

沧海笑1122 发表于 2012-2-25 00:35:51

本帖最后由 沧海笑1122 于 2012-2-25 00:39 编辑

@Ansifa
你好,你写得很清楚,这个程序很好理解,一部分是将串口送下去的一串数字生成双音频;另一个部分就是使用喇叭播放双音频。

我的问题是,摘机后,听筒里面的拨号音仍然长鸣。这时我也能听到喇叭播放的“10000”已经在受话器旁响起,可是拨号音同时也在听筒里响着,因此拨号后,没有反应啊。何解?希望指点一二。
谢谢

沧海笑1122 发表于 2012-2-25 18:29:13

本帖最后由 沧海笑1122 于 2012-2-25 18:52 编辑

感谢Ansifa的指导。
问题的提出:昨晚按照原图测试,的确出现喇叭播放的“10000”已经在受话器旁响起,可是拨号音同时也在听筒里响着的现象,受话器没有识别拨号音。
增大音量的尝试:今天在Ansifa的指导下,做了以下尝试。
(1)甩开两只电容,因为我使用的电容是0.1uf的,参数小,因此甩开。原设计是为了保护喇叭。(这两个电容后来我又加上去,也拨号成功了。)
(2)11、12pin每个支路增加一只电阻,整个回路电阻是降低的。改后喇叭音量增大。
改后拨打10000号成功,第一个音响起后,话机里的等待拨号音就中止了,10000号拨完,就听到了电脑话务员的声音。

启示:
这个实验的目的是用arduino的PWM脚(11、12)合成不同频率的声音,并且输出至喇叭。
Ansifa介绍为保证成功率,应该是直接接到电话线里面的。如果你感兴趣,也可以分别甩开11、12pin,感受一下单音频与双音频的不同。
注意:受环境,受话器质量、喇叭与受话器距离的影响,拨号识别不是每次都成功,需要多拨几次,但证明这个方案是可行的。

再次感谢Ansifa。

(附图:按照Ansifa的指导改后的图)

Ansifa 发表于 2012-2-26 22:30:37

沧海笑1122 发表于 2012-2-25 18:29 static/image/common/back.gif
感谢Ansifa的指导。
问题的提出:昨晚按照原图测试,的确出现喇叭播放的“10000”已经在受话器旁响起,可是 ...

哈哈,支持沧海笑1122的亲自试验,反映的问题我也遇到了,的确成功率不是100%,规范的使用应该是通过电路直接接到电话线上的。这样就成了拨号机了

zhanggang1971 发表于 2012-2-27 10:02:27

Ansifa 发表于 2012-2-26 22:30 static/image/common/back.gif
哈哈,支持沧海笑1122的亲自试验,反映的问题我也遇到了,的确成功率不是100%,规范的使用应该是通过电路 ...

遇到脉冲拨号的线路就没辙了,呵呵,好在脉冲都已经淘汰了。 :)

黑马 发表于 2012-3-3 15:12:00

zhanggang1971 发表于 2012-2-27 10:02 static/image/common/back.gif
遇到脉冲拨号的线路就没辙了,呵呵,好在脉冲都已经淘汰了。

脉冲拨号拍挂机键就行了:lol

Randy 发表于 2012-4-16 22:03:04

好高级的东西,有时间试一试!

loneress 发表于 2012-4-19 15:39:31

很有创意的东西。

能不能想办法在拔号键盘那里接线呢。

文具盒 发表于 2012-4-26 00:37:45

得试试看,做个好学生

wetnt 发表于 2012-6-15 10:40:04

有没有能够来电显示的?那样就酷了!

xzmoji 发表于 2012-7-13 15:43:41

Tone::stop()':
F:\arduino-1.0.1\libraries\Tone\Tone.cpp:361: error: 'digitalWrite' was not declared in this scope

我复制的是原程序,下载程序到arduino出现错误,求解。

smfox10 发表于 2012-7-15 00:14:55

本帖最后由 smfox10 于 2012-7-15 00:18 编辑

科普一下“电话线同样只能传送声音。我们不能对着机器念电话号码,机器听不懂,所以电话机必须用一个统一的格式,把数字转变为声音来传送。每次当你按下数字键,电话机就会发出一个声音。这个声音的频率是事先约定的,不同数字各不相同(其实就是你按键时听到的那种高低不同的“滴滴”声)。机器收到这个频率的声音,就知道你要拨什么号码了。
正因为如此,我们在拨号的这段时间,用嘴或者用任何音响设备发出的声音,都有可能传到电信局,成为一次拨号——但是这种情况太难发生了。每一个数字键发出的声音,其实是两个频率声音的组合(频率的组合表见图)。而且机器对频率的认定非常严格,差一点点都不行,这样做就能有效地避免杂音被误当成了拨号。”

也就解释了为什么要用Tone库 而不用自带的tone,因为每个数字键需要两个频率声音合成!超版的每个帖子技术含量都是非常的高!感谢超版!

星夜幻 发表于 2012-9-12 14:46:30

那个扩展的Tone很厉害啊,
页: [1] 2 3
查看完整版本: Arduino学习笔记A9 - Arduino自制电话拨号器