第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.。.
。
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:规格
串行设置为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步:小电路
DAC0832 LCN
这是一款出色的廉价8位数模转换器。 (DAC)
它可以通过一系列数据保持,数据采样线进行完全控制。
或者可以将其设置为在“流经操作”中自动完成所有操作。
引用该手册:
仅将CS,WR1,WR2和XFER接地,并将ILE接地即可,这两个内部寄存器都可以直接跟随所应用的数字输入(直通)影响DAC模拟输出。
好,这是与芯片组的四个连接低端,一个设置为9V的连接-很容易。
我们不希望有任何负电压,因此手册说我们应该使用“电压切换模式”,并提供图表。
我们要做的就是替换一个小型音频放大器,而不是他们建议的那种。
LM386-N音频放大器
放大器的手册提供了最小的零件图-增益为20(对我们来说是太多了,但具有音量控制)。
我们需要做的是在DAC和放大器之间添加一个电容器,以便仅放大交流信号。
我们还必须添加一个电容应靠近我们每个芯片的电源引脚,否则我们将从9V电源中获得嗡嗡声。
步骤5:取出烙铁
由于电路很简单,所以我不打算一击即发。
以下是一些提示:
准备一块至少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标头
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:中断和双缓冲
在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电位器两端的引线互换。
让我知道如何听起来。
-
dac
+关注
关注
43文章
2268浏览量
190810 -
Arduino
+关注
关注
187文章
6462浏览量
186599
发布评论请先 登录
相关推荐
评论