CurieNano 直接播放声音-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 10888|回复: 7

CurieNano 直接播放声音

[复制链接]
发表于 2017-6-9 22:08 | 显示全部楼层 |阅读模式
本帖最后由 Zoologist 于 2017-6-9 22:12 编辑

今天收到了 DFRobotCurieNano控制板。除了控制器,还有两个徽章以及多功能便携工具卡:
image001.jpg

可以看到这次的主角 Curie Nano 非常小巧,但是功能和全尺寸的  Arduino 101 相比毫不逊色。接下来我就使用这块小板子完成直接播放声音的功能,之前我在【参考1】中介绍过。 唯一的问题是直接寄存器仿佛古文一般面目可憎,又好比英文小说,每一个字母都认识,但是放在一起变成了天书。 仔细捋了一下原理,重新编写了一次。
从原理出发,声音播放就是在特定的频率下(通常大于8000Hz),将数字量化后的信号按照模拟的方式输出。而对于Arduino 来说,最简单的模拟输出就是用PWM。参考1的代码用了一个定时器,8000Hz触发一次,这样整体的代码非常复杂。我们修改为循环,输出之后做足够的延时(1/8000=125us),实际上的输出也是8000Hz,但是整体变得直观和容易理解多了。此外,默认的 PWM输出频率过小(关于 CuriePWM我会另外介绍),这会导致analogWrite输出的PWM还没有来得及输出完整的一个周期下面的数据就过来。因此,需要升高PWM的频率。对于101 来说,使用analogWriteFrequency(Pin,Frequency);即可指定输出的 PWM 频率(意想不到的简单)。
首先,我们要大概估计一下空间,编写下面这样的简单代码:
void setup() {
analogWriteFrequency(OUTPIN, 64000);
}
void loop() {
}[kenrobot_code]void setup()
{
        analogWriteFrequency(OUTPIN, 64000);
}
void loop()
{
} [/kenrobot_code]
剩余空间差不多有 155648-48016=107632 Bytes,大概可以存放107632/8000=13.4秒的声音(实际上还有额外库函数的开销,实际写代码根据编译结果删除了很多数据)。
image002.png

硬件连接上非常简单:Uno 的地接在喇叭负极标志处上,然后随便选一个 支持PWM的引脚作为输出,这里我选择的是Pin9接在喇叭的正极标记处。
image003.jpg

播放的内容是罗大佑的《恋曲1990》,首先用工具将音频转化为 8000Hz8Bits,然后用【参考4】的工具转化数据为 C的格式,放置在代码中即可。
不完整的程序如下:
[kenrobot_code]#define OUTPIN 9

const unsigned char sample[] PROGMEM =
{
        0x80, 0x80, 0x84, 0x85, 0x85, 0x83, 0x83, 0x81, 0x82, 0x83, 0x85, 0x82, 0x80, 0x7F, 0x7F, 0x80, 0x83, 0x81, 0x81, 0x80, 0x7F, 0x85, 0x87, 0x87, 0x86, 0x84, 0x84, 0x87, 0x84, 0x82, 0x81, 0x80,
        0x82, 0x87, 0x88, 0x88, 0x89, 0x84, 0x80, 0x7F, 0x80, 0x81, 0x82, 0x82, 0x83, 0x82, 0x83, 0x84, 0x83, 0x82, 0x80, 0x7F, 0x7D, 0x7A, 0x78, 0x75, 0x74, 0x72, 0x72, 0x74, 0x75, 0x73, 0x70, 0x70,
//很多很多数据
        0x7C, 0x76, 0x76, 0x7C, 0x76, 0x72, 0x77, 0x79, 0x77, 0x7B, 0x7F, 0x84, 0x87, 0x85, 0x7F, 0x85, 0x88, 0x86, 0x82, 0x81, 0x83, 0x82, 0x80, 0x7F, 0x82, 0x80, 0x7A, 0x74, 0x73, 0x74, 0x77, 0x7A,
        0x84, 0x88, 0x87, 0x83, 0x85, 0x8B, 0x90, 0x91, 0x8F, 0x8A, 0x8A, 0x88, 0x88, 0x82, 0x7F, 0x7D, 0x74, 0x6D, 0x6A, 0x67, 0x6B, 0x6E, 0x74, 0x75, 0x74, 0x6F, 0x70, 0x73, 0x77, 0x7B, 0x7B, 0x7B,
        }
        void setup()
        {
                analogWriteFrequency(OUTPIN, 64000);
        }

        void loop()
        {
                for (unsigned int i = 0; i < sizeof(sample); i++)
                {
                        analogWrite(OUTPIN, pgm_read_byte(&sample));
                        delayMicroseconds(125);
                }
        }
        [/kenrobot_code]
整个程序源代码500K
image004.png

工作的视频如下。感觉美中不足的是声音似乎有些小,这个可能和IO驱动只有3.3V有关。



针对这种代码的调试上有一些建议:
1.     最好使用歌曲作为素材,理由是单纯的音乐通常无法分清楚当前的播放是否正常。当然,如果你的喇叭质量不好,使用<<月亮之上>>这样的也可以掩盖破音(这也是为什么山寨机最喜欢放这首曲子的原因);
2.     为了安全起见,建议在喇叭上串联一个电阻,防止电流超过40ma;
3.     因为数据被定义在 Flash中,所以一定要使用pgm_read_byte(&sample)这种形式读取出来,切忌直接使用sample.这个问题让我头晕了很久.
4.      
有了这样的方法, 你可以尝试在自己的作品中加入声音的功能。 后面我还会尝试使用板载SPI芯片来扩展存储更多的音频。
参考:
1. http://www.lab-z.com/arduinosound/使用Arduino直接发声
2. http://www.diy-robots.com/?p=852Arduino系列教程之 PWM的秘密(下)
3. http://www.diy-robots.com/?p=814Arduino系列教程之 PWM的秘密(上)
4. http://www.arduino.cn/thread-46025-1-1.html一个wave h 文件的工具

发表于 2017-6-9 22:24 | 显示全部楼层
5883使用正常吗?
 楼主| 发表于 2017-6-10 06:48 | 显示全部楼层
奈何col 发表于 2017-6-9 22:24
5883使用正常吗?

这是啥?
发表于 2017-6-10 08:57 | 显示全部楼层

CurieNano上面集成的那个3轴的电子罗盘,输出你测过正常嘛?
 楼主| 发表于 2017-6-10 10:54 | 显示全部楼层
我刚刚测试过了,也是不好用的

我用I2c 扫描代码扫了一下无法发现设备

应该是 hw问题,需要 dfrobot帮忙啦
发表于 2019-7-7 23:24 | 显示全部楼层
楼主arduino Uno提示analogWriteFrequency函数未声明,用analogWrite函数又达不到效果,怎么解?

点评

因为这个设计是给 intel curieNano的,不支持 uno  发表于 2019-7-8 08:10
发表于 2019-7-10 14:35 | 显示全部楼层
无忧WithYou 发表于 2019-7-7 23:24
楼主arduino Uno提示analogWriteFrequency函数未声明,用analogWrite函数又达不到效果,怎么解? ...

那Uno有办法直接发声而不用定时器吗,我有个模块把11脚占用了,用PCM库老是报错,想把定时器2的引脚从11改到3,但是貌似难度有些大
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-1 01:05 , Processed in 0.092813 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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