如何使用Arduino和DAC播放音频声音文件

电子说

1.3w人已加入

描述

第1步:要求

Arduino-我使用Mega,但是没有理由不能使Uno工作。

SdCard读卡器-该程序配置为:MicroSD Breakout Board受Logic Conversion V2规范

http://www.hobbytronics.co.uk/microsd-card-regula 。..。

请参阅此说明以进行SdCard设置详细信息:https://www.instructables.com/id/Arduino-Mega-Audio.。.

DAC0832 LCN-出色的8位数模转换器-A几磅。

LM386 N-1运算放大器-像芯片一样便宜

20路芯片插座

8路芯片插座

9伏电源-电池即可。/p》

LM336 2.5 V参考电压

10uF电容器* 3(任何9V以上的电压)

10欧姆电阻器

50nF电容器-(或在接近47nF,56nf,68nf的地方工作)

220uF电容器

64欧姆扬声器

10K线性电位器

电缆链接Arduino和电路之间的8条数据线-

在Uno上8条连接成一直线,在Mega上成对。

在我使用的Mega上带10路IDC接头的10路带状电缆。 (备用2条线)

用于0V,9V和DAC输出的插座连接器

铜排板,焊锡,电线,刀具等

步骤2:规格

dac

串行设置为115200波特。

使用Mega的Hobbytronics MicroSD Breakout Board支持到位。芯片选择和其他端口将在Mega和Uno之间改变。

Wav文件必须存在于名为adlog的目录中,请随意命名,并重新排列必要的编码。

wav文件必须为8位单声道。我已经测试了高达44KHz。

“串行”监视器在adlog文件夹中显示wav文件。文件名是从监视器输出行发送的。

文件大小仅受SdCard大小的限制。

步骤3:入门

连接SD卡读卡器。这些是Mega的连接。

0,5V

CLK到引脚52

D0到引脚50

D1到引脚51

CS到第53针

(有关Uno端口连接的信息,请参见供应商的网站)

您需要在此阶段测试卡是否正常工作-使用供应商提供的脚本。

我们需要做一个小电路。

我们要从Arduino发送音频字节流。

这些数字在0到255之间。它们代表电压。

沉默范围是127-128。

255是扬声器的一种锥形扬声器。

0是扬声器的一种锥形扬声器。

因此,音频被记录为已保存的数字,从而产生变化的电压

我们可以使用“端口”同时在Arduino的8行中发送数字。

如果我们将8条线馈入数模转换器,它会按照锡的指示进行操作,并产生与数字量成比例的模拟电压。

然后我们要做的是包装

第4步:小电路

dac

dac

dac

DAC0832 LCN

这是一款出色的廉价8位数模转换器。 (DAC)

它可以通过一系列数据保持,数据采样线进行完全控制。

或者可以将其设置为在“流经操作”中自动完成所有操作。

引用该手册:

仅将CS,WR1,WR2和XFER接地,并将ILE接地即可,这两个内部寄存器都可以直接跟随所应用的数字输入(直通)影响DAC模拟输出。

好,这是与芯片组的四个连接低端,一个设置为9V的连接-很容易。

我们不希望有任何负电压,因此手册说我们应该使用“电压切换模式”,并提供图表。

我们要做的就是替换一个小型音频放大器,而不是他们建议的那种。

LM386-N音频放大器

放大器的手册提供了最小的零件图-增益为20(对我们来说是太多了,但具有音量控制)。

我们需要做的是在DAC和放大器之间添加一个电容器,以便仅放大交流信号。

我们还必须添加一个电容应靠近我们每个芯片的电源引脚,否则我们将从9V电源中获得嗡嗡声。

步骤5:取出烙铁

dac

dac

由于电路很简单,所以我不打算一击即发。

以下是一些提示:

准备一块至少28 x 28孔的铜带板。 (是的,我知道脑外科医师可以使它变小)

如果您打算用螺钉安装它,请在开始时允许他们使用!

将芯片安装在插槽上。仅在检查完所有内容后才插入芯片。

将输入线远离输出。

注意电容器的正确极性。

有关LM336参考电压的基本视图,请参见该图。不使用调节脚,可以将其切开。

请注意直接连接到DAC的引脚8,这对于测试非常有用。

我使用带状电缆和10方向IDC连接器连接到Audino。

在Uno上,连接成一直线-您可能会发现,将8个输入连接成一条直线可以让您使用购买的现成的8路连接器链接到Arduino,

完成后-检查焊接情况并检查铜轨之间的间隙。

我找到了一个36 tpi的小型钢锯条对于清除碎片非常有用。我卸下刀片的定位销并将刀片的顶端滑入轨道-显然刀片不在框架中。

步骤6:测试DAC

断开电路与Arduino之间的连接。

将电路的音量控制设置为中途。

打开9V直流电源

检查电路是否正常-我对您的电路不承担任何责任!

关闭电源。

将电路连接到Arduino。

在Mega上使用22-29引脚。 (PORTA)不要弄错上面的两个5V引脚!

在Uno上使用0-7引脚。这是PORTD

将您的电源的0V连接到Arduino上的0V。

加电。

打开此测试程序DAC_TEST

对于UNO,将对PORTA的所有引用替换为PORTD

用DDRD替换DDRA-该指令将所有8行设置为一次性输出。这是数据方向寄存器。

将串行监视器设置为115200。

在DAC out和OV之间连接电压表

程序将设置输出到255-所有线路上-最大电压。

输出128-最大电压的一半。

输出0-零电压(或可能接近零)。

然后它将按位步进:1、2、4、8、16、32、64、128

电压应稳定增加。

如果电压回落而数量增加您可能将两根互连线颠倒了。

您还应该听到扬声器随着电压的变化而悄悄地发出咔嗒声

步骤7 :读取Wav标头

dac

Wav文件以指定的频率和数据大小保存。

此信息包含在以下位置的44字节标头中一个wav文件的开头。

尽管某些软件扩展了标头(在字节35之后),但使数据大小的位置更难定位。

要读取标头,我们创建一个buff er并复制文件的开头。

频率从文件的24个字节开始以4个字节存储。

//读取wav文件头中指定的频率

字节头文件[60]

tempfile.seek(0);

tempfile.read(headbuf,60);

RETVAL = headbuf [27];

retval =(retval 《《8)| headbuf [26];

retval =(retval 《《8)| headbuf [25];

retval =(retval 《《8)| headbuf [24];

Serial.print(F(“ File Frequency”));

Serial.print( retval);

查找数据大小信息的最佳方法是在标题中搜索单词“ data”。

然后提取紧随其后的4个字节,这些字节构成了长值

无符号长检索;

int mypos = 40 ;

用于(int i = 36; i 《60; i ++){

如果(headbuf [i] = =‘d’){

if(headbuf [i + 1] ==‘a’){

如果(headbuf [i + 2] ==‘t’){

if(headbuf [i + 3] ==‘a’){

//终于有了

mypos = i + 4;

i = 60;

}

}

} 》

}

}

tempfile.seek(mypos);

RETVAL = headbuf [mypos + 3];

RETVAL =(RETVAL 《《8) | headbuf [mypos + 2];

retval =(retval 《《8)| headbuf [mypos + 1];

retval =(retval 《《8)| headbuf [mypos];

确定数据长度和频率!

音频数据紧跟着构成数据长度值的4个字节。

步骤8:中断,中断。..。

频率信息,以在所需频率处或附近创建软件中断。

虽然不一定总是精确地设置中断,但已足够。从文件读取的频率将传递给setintrupt子例程。

void setintrupt(float freq){

float bitval = 8;//8表示8位定时器0和2,1024表示定时器1字节

setocroa =(16000000/(freq * bitval))-0.5;

//setocroa值需要减去-1。但是,将0.5个回合加到最接近的0.5

//计时器的分辨率有限

//由位值的大小确定

cli();//禁用中断

//设置 timer2 中断

TCCR2A = 0;//将整个TCCR2A寄存器设置为0

TCCR2B = 0;//与TCCR2B相同

TCNT2 = 0;//将计数器值初始化为0

//设置比较匹配寄存器的频率(hz)增量

OCR2A = setocroa ;//=(16 * 10 ^ 6)/(频率* 8)-1(必须为《256)

//开启CTC模式

TCCR2A | =(1 《

TCCR2B | =(1 《

//TIMSK2 | =(1 《

sbi(TIMSK2,OCIE2A);//在定时器2上启用中断

sei();//启用中断

关注读者的读者会发现 sbi(TIMSK2,OCIE2A)

我已设置几个用于设置和清除寄存器位的功能(获取互联网):

//定义用于清除寄存器位的方法

#ifndef cbi

#define cbi(sfr,bit)(_SFR_BYTE(sfr)&=〜_BV(bit))

#endif

//定义用于设置寄存器位

#ifndef sbi

#define sbi(sfr,bit)( _SFR_BYTE(sfr)| = _BV(位))

#endif

这些函数可轻松调用以设置或清除中断

所以中断正在运行,我们该怎么办?

步骤9:中断和双缓冲

dac

在22 Khz时,每0.045 ms输出一个字节的音频数据

在2.08中读取512字节(缓冲区大小) ms。

因此无法在一秒内从SDCard读取缓冲区

然而,在23.22ms内将512字节写入端口。

所以我们要做的就是设置每次缓冲区清空时读取一个新文件。需要一个新的数据块之前获取数据的时间。..假设我们使用两个缓冲区,在填充另一个缓冲区时将其清空。

这是双缓冲。

读取的文件

我已经设置了两个512字节的缓冲区,分别称为bufa和bufb。

标志 aready 是true,我们从porta读取,否则从portb读取

当缓冲区位置(bufcount)达到缓冲区大小(BUF_SIZE 512)时,我们设置一个名为的标志

void循环例程会寻找此标志并开始读取块:

if(readit){

if(! Aready){

//启动SD卡读取到bufa

tempfile.read(bufa,BUF_SIZE);

}否则{

//启动读取到bufb的SDCard块

tempfile.read(bufb,BUF_SIZE);

}

readit = false;

}

完成后,例程标志readit = false。

在中断例程中,我们必须检查void循环通过检查readit == false是否结束。

在这种情况下,我们发出信号,要求再次读取并切换Aready标志以切换缓冲区。

如果SD卡仍在读取我们必须回溯一个读数(counter--; bufcount--;)并退出中断以稍后再试。 (单击音频输出信号表示已发生这种情况。)

读取所有数据后,中断被取消,端口重置为中间电压值128,音频文件关闭。

在首次运行dac2.ino脚本之前,请将音量设置为50%。这会太大声,但是比100%更好!

如果您的音量控制反向工作,则将10K电位器两端的引线互换。

让我知道如何听起来。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分