基于FPGA的音乐播放器
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于FPGA的音乐播放器
姓名:陆波
学号:09090323
指导老师:周爱军
•音乐硬件演奏电路基本原理
•硬件电路的发声原理,声音的频谱范围约在几十到几千赫兹,若能利用程序来控制FPGA芯片某个引脚输出一定频率的矩形波,接上扬声器就能发出相应频率的声音。乐曲中的每一音符对应着一个确定的频率,要想FPGA发出不同音符的音调,实际上只要控制它输出相应音符的频率即可。乐曲都是由一连串的音符组成,因此按照乐曲的乐谱依次输出这些音符所对应的频,就可以在扬声器上连续地发出各个音符的音调。而要准确地演奏出一首乐曲,仅仅让扬声器能够发生是不够的,还必须准确地控制乐曲的节奏,即乐曲中每个音符的发生频率及其持续时间是乐曲能够连续演奏的两个关键因素。
•音调的控制:
频率的高低决定了音调的高低。通过查阅资料,得到下面的音符名与频率的关系表:音符名频率
/hz
音符名频率
/hz
音符名频率
/hz 低音1262中音1523高音11046低音2294中音2587高音21175低音3330中音3659高音31318低音4349中音4698高音41397低音5392中音5784高音51568低音6440中音6880高音61760低音7494中音7988高音71976
•分频比预置数的计算:
•分频比就是从6Mhz基准频率通过二分频得到的3Mhz频率
基础上计算得到的。对于乐曲
中的休止符,只需将其分频系
数设为0,将分频预置数设为
16383即可。例如:低音3的频
率为330hz,分频比为
3M/330hz=3000000/330=9091,则其分频预置数为:16383-
9091=7292。其他的音符对应
的分频比和分频比预置数均按
此法计算可得到。依次计算出
低、中、高3X7=21个音的预置
数。
•各音阶对应的预置数如右表:音符名预置数音符名预置数音符名预置数低音14933中音110647高音113515低音26179中音211272高音213830低音37292中音311831高音314107低音47787中音412085高音414236低音58730中音512556高音514470低音69565中音612974高音614678低音710310中音713347高音714858
•音长的控制:
•音符的持续时间必须根据乐曲的速度及每个音符的节拍数来确定。本
试验中,设定最短的音符为4分音符,若将全音符的持续时间设为1s的话,
则需要提供一个4Hz的时钟频率即可
产生4分音符的时间,每1/4个节拍的
时间为0.25s,一个完整的节拍为1s。•右图即为音乐播放器的原理框图。控制音调通过设置计数器的预置数来实
现,预置不同的数可以使计数器产生
不同频率的信号,从而产生不同的音
调。控制音长则是通过控制计数器预
置数的停留时间来实现的,预置数停
留的时间越长,则该音符演奏的时间
越长。每个音符的演奏时间都是0.25s 的整数倍,对于节拍较长的音符,例
如2分音符,占了2/4个节拍,在记谱
的时候将其连续记录2次即可。
•乐曲产生模块:
•核心模块就在这里,这里:(1)首先罗列了低、中、高21个音的分频比预置数(还有休止符的预置数16383),通过6Mhz的基准频率,在其上升沿的时候,计数器累加,当计满到16383之后就取反speaker(speaker<=~speaker非阻塞赋值),产生对应音符的频率,这里和单片机的定时计数器溢出中断差不多。
•产生了21个音调之后,我们要产生流畅的歌曲,还必须根据歌曲的谱子,调用相应音符并且根据节拍控制其持续的时间,例如:若一个音持续4个1/4节拍,则在clk_4hz的上升沿,连续调用4次它的音符就可以了。用counter来计数,计满了(何时计满取决于歌曲长度)就将counter返回为0,这样就可以实现循环演奏了。
•分频产生4hz的节拍控制频率:
•module div_clk4hz(clk24m,clk4);
•input clk24m;
•output clk4;
•reg clk4;
•reg [21:0]cnt;
•always @(posedge clk24m)
•if(cnt<2999999)cnt=cnt+1;//(24m/4hz=60000 00,cnt<[6000000/2-1=2999999])
•else begin cnt=0;clk4=!clk4;end
•分频产生6Mz的基准频率:
•module div_clk6mhz(clk24m,clk6m);
•input clk24m;
•output clk6m;
•reg clk6m;
•reg cnt;
•always @(posedge clk24m)
•if(cnt<1)cnt=cnt+1; //(24m/6m=4分
频,cnt<[4/2-1=1]即可)•else begin cnt=0;clk6m=!clk6m;end •endmodule
•主程序大致:
•module song(clk_6mhz,clk_4hz,speaker);
•input clk_6mhz,clk_4hz;
•output speaker;
•reg [3:0]high,med,low;
•reg [13:0]divider,origin;
•reg [7:0]counter;
•reg speaker;
•wire carry;
•reg speaker;
•wire carry;
•assign carry=(divider==16383);
•always @(posedge clk_6mhz)
•begin if(carry)divider<=origin;
•else divider<=divider+1;
•end
•always @(posedge clk_4hz)
•begin
•if(counter==113)counter<=0;
•else counter=counter+1;
•case(counter)
•0: {high,med,low}<='b000000000101;•1: {high,med,low}<='b000000000101;//•2: {high,med,low}<='b000000000110;•3: {high,med,low}<='b000000000110;//•4: {high,med,low}<='b000000000101;•5: {high,med,low}<='b000000000101;//•6: {high,med,low}<='b000100000000;•7: {high,med,low}<='b000100000000;//•8: {high,med,low}<='b000001110000;
endcase