当前位置:首页 > 开发板 > 开发板
[导读]比如本文要介绍的Adafruit Wave Shield,就能是专门为Arduino设计的音频模块.确切的说是为AVR这一类的8位机而设计的音频模块.下文将从硬件到软件详细介绍一下子此模块的设计细节与使用方法.

前言

 

图 最终组装图之一

图 最终组装图之二

曾几何时,玩音频曾经是搞DIY中的高大上.不说DSP也得上ARM,至于DAC与运放更是一度成为土豪们展示经济实力的舞台.不过随着单片机等器件的进化,开源软件的蓬勃发展,玩音频的门槛早就下来了.比如本文要介绍的Adafruit Wave Shield,就能是专门为Arduino设计的音频模块.确切的说是为AVR这一类的8位机而设计的音频模块.下文将从硬件到软件详细介绍一下子此模块的设计细节与使用方法.

硬件介绍+焊接

熟悉Arduino的同学们都了解,这种模块一般都是以元器件形式提供给大家的,元器件也大多是插件形式的,为的是锻炼大家的动手能力.当然对作者这种习惯了贴片和钢网的人来讲,只能说怀怀旧了.

图 一包元器件

图 模块包含的所有材料

拿到手真有点眼泪汪汪的,前几天玩了个TI的MSP430的板子,那板子只有主控属于DIP,当时都感概了一番.如今拿到这板子除了实在没法插件的SD卡座之外,居然全都是插件的,插件电容,插件电阻,插件运放,插件DAC...结果是逼迫着又怀了一把旧.记忆中上次玩这种全插件的板子肯定是大学时代了,而且绝对是大三之前.好在这种板子焊接起来也快,三下五除二就焊接好了.

图 官方的焊接图

图 作者焊接好的图片

[!--empirenews.page--]

图 插在Arduino Uno板子上

图 带上耳机

也懒得去追求美观了,只求扎实与连接可靠.有几个件没有焊接的属于套件中没有包含的器件,是些指示,接口之类的, 并不影响主要功能.

下面看看原理图:

图 板子的原理图

原理同总共就这一页.不难看出,板子是通过DAC片(MCP4921)来播放音频的,这是个12bit的单通道,参数上与大多数有DAC的片如STM32的内置DAC类似. 但是分立的DAC肯定效果要好点. DAC过了之后加了两级运放进行放大, 运放电路也是简单粗暴, 仅仅进行电流加强, 这是因为DAC输出的幅度已经足够. 另外使用74125隔离后使用SPI来读取SD卡. 这个SD卡才是这板子较为重要的部分. 因为SD卡意味着能播放的数据源超级大了. 相比而言,12bit的DAC虽然性能还说的过去, 但不是那么必要, 因为Arduino板子几乎都有通过PWM+滤波器来播放音频的选项. 但是这板子不仅仅是个SD卡扩展kit,分立DAC+运放的组合起码在教育意义上较大. 很多人能够通过这板子来理解基本的音频播放电路的原理. Arduino是通过SPI接口来读取SD卡的.

安装Arduino库

Arduino的一大特点是能利用的库函数很丰富. 如何使用这个模块, 当然自己来写FAT读取,再进行DAC操作也是可以的. 但那样做之前不妨试试别人写好的库来评估一下子硬件也是很好的. 作者相信这也是Arduino这种开源硬件这么流行的原因: 方便快捷评估硬件.这一点效率在真正的开发中很重要.在DIY中也是如此,因为可以参考别人成果,激发你的创作灵感. 当没有库的时候也要发挥自己动手的开创精神, 有库的时候就要先去利用.

以下这个库函数封装了读取SD卡与通过MCP4921来播放wav文件的功能:

https://github.com/adafruit/WaveHC

通过git下载也好,直接下载zip也好. 总之下载好解压之后把WaveHC这个文件夹拷贝到你的Arduino的库文件夹中. 系统中Arduino的库文件夹这样查看:

图 Arduino的库文件夹

转换音频

首先找个SD卡, 用TF+卡套也可以. 本人使用的是16G的SDHC卡, 最好是先进行格式化成FAT32格式. 再到你电脑上找几个想听的歌曲要转成单通道44.1KHz或以下, 16bit或以下的wav文件. 这里面我们使用Audacity来进行:

http://www.audacityteam.org/

这软件本人在其他文章中写了不少, 这里从简, 不清楚的可以留言或翻之前的文章.

比如要转化某mp3文件,首先当然是打开该文件:[!--empirenews.page--]

图 打开某mp3文件

上面显示的是两通道, 首先合并为单通道. 因为板子上只有一路DAC, 不合并也可以, 只是要改库函数稍稍麻烦, 这里合并一下子以求简洁.

图 合并命令菜单

图 此时看起来是单通道

下一步要进行重采样到低一点, 这一步可选, 因为Arduio Uno的主控较弱,要播放的采样率太高了会失真,如果你转换的原文件如果高于44.1KHz则建议重采样为至多44.1KHz.

图 重采样命令

图 设定工程采样率也就是导出采样率

最后就是导出了,注意选择格式:

图 导出菜单命令

图 导出格式

把导出的文件放到你刚刚格式化的SD卡内,如果卡够大的话,不妨多放几首,可以循环播放.

播放程序

一个简单的循环播放程序,这也是WaveHC中的示例之一.简单走一下子这程序的流程:

//首先包含这两个头文件, 注意如果提示找不到这两个文件请退回去看如何安装库文件.

#include

#include

//定义几个全局对象: 卡,文件系统,音频播放对象. 以及其他几个全局变量

SdReader card; // This object holds the information for the card

FatVolume vol; // This holds the information for the partition on the card[!--empirenews.page--]

FatReader root; // This holds the information for the volumes root directory

WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time

uint8_t dirLevel; // indent level for file/dir names (for prettyprinting)

dir_t dirBuf; // buffer for directory reads

/*

* Define macro to put error messages in flash memory

*/

#define error(msg) error_P(PSTR(msg))

// Function definitions (we define them here, but the code is below)

void play(FatReader &dir);

//Arduino程序的初始化函数,主要是加载文件系统

void setup() {

Serial.begin(9600); // set up Serial library at 9600 bps for debugging

putstring_nl("\nWave test!"); // say we woke up!

putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad

Serial.println(FreeRam());

// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you

if (!card.init()) { //play with 8 MHz spi (default faster!)

error("Card init. failed!"); // Something went wrong, lets print out why

}

// enable optimize read - some cards may timeout. Disable if you're having problems

card.partialBlockRead(true);

// Now we will look for a FAT partition!

uint8_t part;

for (part = 0; part < 5; part++) { // we have up to 5 slots to look in

if (vol.init(card, part))

break; // we found one, lets bail

}

if (part == 5) { // if we ended up not finding one :(

error("No valid FAT partition!"); // Something went wrong, lets print out why

}

// Lets tell the user about what we found

putstring("Using partition ");

Serial.print(part, DEC);

putstring(", type is FAT");

Serial.println(vol.fatType(), DEC); // FAT16 or FAT32?

// Try to open the root directory

if (!root.openRoot(vol)) {

error("Can't open root dir!"); // Something went wrong,

}

// Whew! We got past the tough parts.

putstring_nl("Files found (* = fragmented):");

// Print out all of the files in all the directories.

root.ls(LS_R | LS_FLAG_FRAGMENTED);

}

//主循环就是播放,播放是通过中断来进行的,所以也可以同时做其他操作

void loop() {

root.rewind();

play(root);

}

//一些出错报告函数

/*

* print error message and halt

*/

void error_P(const char *str) {

PgmPrint("Error: ");

SerialPrint_P(str);

sdErrorCheck();

while(1);

}

/*

* print error message and halt if SD I/O error, great for debugging!

*/

void sdErrorCheck(void) {

if (!card.errorCode()) return;

PgmPrint("\r\nSD I/O error: ");

Serial.print(card.errorCode(), HEX);[!--empirenews.page--]

PgmPrint(", ");

Serial.println(card.errorData(), HEX);

while(1);

}

/*

* play recursively - possible stack overflow if subdirectories too nested

*/

void play(FatReader &dir) {

FatReader file;

while (dir.readDir(dirBuf) > 0) { // Read every file in the directory one at a time

// Skip it if not a subdirectory and not a .WAV file

if (!DIR_IS_SUBDIR(dirBuf)

&& strncmp_P((char *)&dirBuf.name[8], PSTR("WAV"), 3)) {

continue;

}

Serial.println(); // clear out a new line

for (uint8_t i = 0; i < dirLevel; i++) {

Serial.write(' '); // this is for prettyprinting, put spaces in front

}

if (!file.open(vol, dirBuf)) { // open the file in the directory

error("file.open failed"); // something went wrong

}

if (file.isDir()) { // check if we opened a new directory

putstring("Subdir: ");

printEntryName(dirBuf);

Serial.println();

dirLevel += 2; // add more spaces

// play files in subdirectory

play(file); // recursive!

dirLevel -= 2;

}

else {

// Aha! we found a file that isnt a directory

putstring("Playing ");

printEntryName(dirBuf); // print it out

if (!wave.create(file)) { // Figure out, is it a WAV proper?

putstring(" Not a valid WAV"); // ok skip it

} else {

Serial.println(); // Hooray it IS a WAV proper!

wave.play(); // make some noise!

uint8_t n = 0;

while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime

putstring(".");

if (!(++n % 32))Serial.println();

delay(100);

}

sdErrorCheck(); // everything OK?

// if (wave.errors)Serial.println(wave.errors); // wave decoding errors

}

}

}

}

如果一切正常的话,下载此程序后即可开始播放.如果你一时没有合适的资源,请下载本文后面的附件中本人的资源进行播放.

总结与参考

这个Arduino的Shield模块具备了音频播放器的种种功能,因为配备了SD卡, 使得资源不成问题.受限于主控性能, 不能解码一些流行格式如MP3,AAC,但是转换也是个一次性的工作,也不显得非常麻烦.笔者自己转换了几十集的评书, 准备每天回来听一集. 总体来说,这个模块很有味道, 值得喜欢音频的同学买一块或者DIY一块.

此模块的官方连接: https://www.adafruit.com/product/94

本人的资源供参考使用: 链接: https://pan.baidu.com/s/1caYUvG 密码: enfw

(注意要放在SD卡的根目录)

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭