EDA技术及应用课程设计说明书
2013 届 电子信息工程 专业 1班级
题 目 音乐播放器 学 号 姓 名 指导教师
二О一 五 年 6 月 25 日
1
一、 音乐播放器基本原理
1 硬件电子琴设计原理
乐曲演奏的原理是:由于组成乐曲的每个音符的频率值(音调)及其持续时间(音长)是乐曲演奏的2个基本数据,因此需要控制输出到扬声器的激励信号的频率高低和该频率信号持续的时间。频率的高低决定了音调的高低,而乐曲的简谱与各音名的频率对应关系在后面将给出。所有不同频率的信号都是从一基准频率分频而得来的,由于音阶频率多为非整数,而分频系数有不能为小数,故必须将计算得到的分频数进行向下取整,基准频率和分频系数应综合考虑加以选择,从而保证音乐不会走调。如在48MHz 时钟下,中音1(对应的频率值是523.3Hz)的分频系数应该为:48000000/(2*523.3)=45863,这样只需对系统时钟进行45863次分频即可得到所要的中音M1(分频系数计算公式为D=F/2K,由于F/2K之后,会使分频系数D变小,所以功能模块中语句:beep_r<=!beep_r,使得输出取反,K=F/2count_end,消除了前面除以2K的影响) 。 2 乐曲自动演奏设计原理
硬件电路和自动演奏的原理同硬件电子琴实验原理类似。至于其他音符,同样可由一式求出对应的分频系数。在程序中设置一个状态机,每250ms改变一个状态(即一个节拍),组成乐曲的每个音符的频率值(音调)相对应于状态机的每一个状态。只要让状态机的状态按顺序转换,就可以自动演奏播放音乐了。《欢乐颂》乐曲的简
2
谱如图所示:
3 消抖原理
作为机械开关的键盘,在按键操作时,由于机械触点的弹性及电压突跳等原因,在触点闭合或开启的瞬间会出现电压抖动,实际应用中如果不进行处理将会造成误触发。
由于这里是低电平表示按键按下,所以按键去抖动的关键在于提取稳定的低电平状态,虑除前沿、后沿抖动毛刺。对于一个按键信号,可以用一个脉冲对他进行取样,如果连续三次取样为低电平,可以认为信号已经处于键稳定状态,这时输出一个低电平按键信号。继续取样的过程中如果不能满足连续三次取样为低,则认为键稳定状态结束,这时输出变为高电平。
二、 音乐播放器的硬件设计
1顶层模块输入输出:
3
管脚说明:
输入:时钟信号——clk ,按键——[6:0]key ,功能切换键——key7 输出:LED灯——[6:0]led ,蜂鸣器——beep; Key0: DO key1: RE key2: ME key3:FA key4: SOL key5: LA key6: SI key7:功能切换键 2 按键消抖模块
输入:时钟信号——clk, 功能切换键——key7 输出:稳定脉冲信号 3 电子琴模块
4
输入:时钟信号——clk ,按键——[6:0]key , 输出:LED灯——[6:0]led ,蜂鸣器——beep; Key0: DO key1: RE key2: ME key3:FA key4: SOL key5: LA key6: SI
按下相应的键有对应LED灯指示。 4乐曲自动演奏模块
输入:时钟信号——clk; 输出:蜂鸣器——beep
三 元器件列表:
5
序号 1 2 耗材名称 PCB制版 型号/规格 10cm*8cm EPM7064AELC44-10N SR420401K 1107 通用 方形 通用 通用 通用 通用 104独石电容 电解电容 通用 通用 通用 通用 通用 通用
技术要求与参数 2层板 44引脚,PLCC封装 数量 单位 1 1 块 个 个 个 个 只 只 只 只 只 只 只 只 只 只 个 对 CPLD 3 数码管 4 PLCC-44 底座 5 钟振 6 电阻 7 电阻 8 电阻 9 电阻 4位,共阴极,40mm*15mm 2 44引脚 12MHz,4引脚 200欧姆 1K欧姆 10K欧姆 50欧姆 0.1uF 50V,10uF 4引脚 红色 绿色 NPN 10针 含20cm电源线 1 1 8 14 10 1 6 1 4 3 3 9 1 1 10 电容 11 电容 12 按键 13 发光二极管 14 发光二极管 15 三极管 16 双排插头 17 电源接插线 三、 音乐播放器的Verilog实现
1电子琴程序
module beep1(clk,key,beep,led); //模块名称beep
input clk; //系统时钟48MHz input[6:0]key; //按键输入 output beep; //蜂鸣器输出端 output[6:0]led; //LED输出 reg beep_r; //寄存器 reg[15:0]count,count_end; reg[6:0]key_r; reg [13:0]a; //消抖寄存器 always@(posedge clk) begin count <= count + 1'b1; //计数器加1 if((count == count_end)&(!(count_end == 16'hffff))) begin
6
count <= 16'h0; //计数器清零 beep_r <= !beep_r; //取反输出信号 end end
always @(key) begin a=2000; //消抖等待时间 key_r = key; //取键值 case(key_r) 7'b1111110:begin while(a>0) begin a=a-1; end count_end = 16'hb327; while(a>0) begin a=a-1; end end
7'b1111101:begin while(a>0)begin a=a-1 ;end count_end =
16'h9fa0;while(a>0)begin a=a-1; end end //中音2的分频系数值
7'b1111011:begin while(a>0)begin a=a-1 ;end count_end =
16'h8e32;while(a>0)begin a=a-1; end end //中音3的分频系数值
7'b1110111:begin while(a>0)begin a=a-1 ;end count_end = 16'h8637;while(a>0)begin a=a-1; end end //中音4的分频系数值 7'b1101111:begin while(a>0)begin a=a-1 ;end count_end = 16'h7794;while(a>0)begin a=a-1; end end //中音5的分频系数值 7'b1011111:begin while(a>0)begin a=a-1 ;end count_end = 16'h6a88;while(a>0)begin a=a-1; end end //中音6的分频系数值 7'b0111111:begin while(a>0)begin a=a-1 ;end count_end = 16'h5ee8;while(a>0)begin a=a-1; end end //中音7的分频系数值 default: begin while(a>0)begin a=a-1 ;end count_end = 16'hffff;while(a>0)begin a=a-1; end end endcase end
assign beep =beep_r; //输出音乐 assign led =key_r; //输出按键状态 Endmodule
2 乐曲自动演奏程序
module song(clk,beep,led); //模块名称 input clk; //系统时钟48Mhz output beep; //蜂鸣器输出端 output[7:0] led; reg beep_r; //寄存器 reg[7:0] state; //乐谱状态机 reg[15:0]count,count_end; reg[23:0]count1;
//乐谱参数:D=F/2K (D:参数,F:时钟频率,K:音高频率) //以下是12MHZ晶振状态下的各音高对应的参数 /*parameter L_5 = 16'h3bca, //低音5
7
M_1 = 16'h2cc9, //中音1 M_2 = 16'h27f8, //中音2 M_3 = 16'h238c, //中音3 M_4 = 16'h218d, //中音4 M_5 = 16'h1de5, //中音5 M_6 = 16'h1aa2; //中音6 parameterTIME = 3000000; //控制每一个音的长短(250ms)*/
//乐谱参数:D=F/2K (D:参数,F:时钟频率,K:音高频率) parameter L_5 = 16'd61224, //低音5 M_1 = 16'd45863, //中音1 M_2 = 16'd40864, //中音2 M_3 = 16'd36402, //中音3 M_4 = 16'd34359, //中音4 M_5 = 16'd30612; //中音5 parameterTIME = 12000000; //控制每一个音的长短(250ms) assign beep = beep_r; //输出音乐 ,蜂鸣器 always@(posedge clk) begin count <= count + 1'b1; //计数器加1 if(count == count_end) begin count <= 16'h0; //计数器清零 beep_r <= !beep_r; //输出取反 end end always @(posedge clk) begin if(count1 < TIME) //一个节拍250mS count1 = count1 + 1'b1; else begin count1 = 24'd0; if(state == 8'd125) //控制歌曲循环播放时间 state = 8'd0; //循环从头开始 else state = state + 1'b1; //循环结构体 begin case(state) 8'd0,8'd1: count_end = M_3;//中音\"3\持续2个节拍 8'd2,8'd3: count_end = M_3;//中音\"3\持续2个节拍 8'd4,8'd5: count_end = M_4;//中音\"4\持续2个节拍
8
8'd6,8'd7: count_end = M_5; 8'd8,8'd9: count_end = M_5; 8'd10,8'd11: count_end = M_4; 8'd12,8'd13: count_end = M_3; 8'd14,8'd15: count_end = M_2; 8'd16,8'd17: count_end = M_1; 8'd18,8'd19: count_end = M_1; 8'd20,8'd21: count_end = M_2; 8'd22,8'd23: count_end = M_3; 8'd24,8'd25,8'd26: 8'd27: 8'd28,8'd29,8'd30,8'd31: 8'd32,8'd33: 8'd34,8'd35: 8'd36,8'd37: 8'd38,8'd39: 8'd40,8'd41: 8'd42,8'd43: 8'd44,8'd45: 8'd46,8'd47: 8'd48,8'd49: 8'd50,8'd51: 8'd52,8'd53: 8'd54,8'd55: 8'd56,8'd57,8'd58: 8'd59: 8'd60,8'd61,8'd62,8'd63: 8'd64,8'd65: 8'd66,8'd67: 8'd68,8'd69: 8'd70,8'd71: 8'd72,8'd73: 8'd74: 8'd75: 8'd76,8'd77: 8'd78,8'd79: 8'd80,8'd81: 8'd82: 8'd83: 8'd84,8'd85: 8'd86,8'd87: 8'd88,8'd89: 8'd90,8'd91: //8'd92,8'd93:
count_end = M_3; count_end = M_2; count_end = M_2; count_end = M_3; count_end = M_3; count_end = M_4; count_end = M_5; count_end = M_5; count_end = M_4; count_end = M_3; count_end = M_2; count_end = M_1; count_end = M_1; count_end = M_2; count_end = M_3; count_end = M_2; count_end = M_1; count_end = M_1; count_end = M_2; count_end = M_2; count_end = M_3; count_end = M_1; count_end = M_2; count_end = M_3; count_end = M_4; count_end = M_3; count_end = M_1; count_end = M_2; count_end = M_3; count_end = M_4; count_end = M_3; count_end = M_2; count_end = M_1; count_end = M_2; count_end = L_5;
9
8'd92,8'd93,8'd94,8'd95: count_end = L_5; //8'd94,8'd95: count_end = M_3; 8'd96,8'd97: count_end = M_3; 8'd98,8'd99: count_end = M_3; 8'd100,8'd101: count_end = M_4; 8'd102,8'd103: count_end = M_5; 8'd104,8'd105: count_end = M_5; 8'd106,8'd107: count_end = M_4; 8'd108: count_end = M_3; 8'd109: count_end = M_2; 8'd110,8'd111: count_end = M_1; 8'd112,8'd113: count_end = M_1; 8'd114,8'd115: count_end = M_2; 8'd116,8'd117: count_end = M_3; 8'd118,8'd119,8'd120: count_end = M_2; 8'd121: count_end = M_1; 8'd122,8'd123,8'd124,8'd125: count_end = M_1; default:count_end = 16'hffff; endcase end end end
assign led[0]=(count_end == M_1)?0:1; //控制LED灯的语言 assign led[1]=(count_end == M_2)?0:1; assign led[2]=(count_end == M_3)?0:1; assign led[3]=(count_end == M_4)?0:1; assign led[4]=(count_end == M_5)?0:1; assign led[5]=(count_end == L_5)?0:1; assign led[6]=1; assign led[7]=1;
3选择模块程序
module select(key,beep1,beep2,led1,led2,beep,led); input key,beep1,beep2; input [6:0]led1; input [6:0]led2; output beep; output [6:0]led; reg key_r;
always @(negedge key) begin key_r = ~key_r; //将琴键开关转换为乒乓开关 end
10
assign beep=(key_r)?beep2:beep1; assign led=(key_r)?led2:led1; Endmodule
4顶层文件程序
module dzq(key,key7,beep,led,clk); input key7; input [6:0]key; input clk;
output [6:0]led; output beep;
reg dout1; reg dout2; reg dout3; reg led; reg key_r; wire a,b,key_l; wire [6:0]c; wire [6:0]d;
assign key_l = (dout1 | dout2 | dout3); //按键消抖输出 always @(posedge clk) begin dout1 <= key7; dout2 <= dout1; dout3 <= dout2; end song (.clk(clk),.beep(b),.led(c)); beep1 (.clk(clk),.key(key),.beep(a),.led(d)); select (.key(key_l),.beep1(a),.beep2(b),.beep(beep),.led(led),.led1(d),.led2(c)); endmodule
11
四、 课程设计总结
本课程设计中,音乐播放器这一对我们来说比较难的作业,但做完之后我们可谓是受益匪浅。这门课与其他的课不同,需要课下自己学习很多东西,不能完全依赖老师,我认为这对学习能力的锻炼是十分有益的,也让我对EDA有了基本的认识亦掌握了初级的编程方式。尤其是在调试阶段,考验耐心和细心的同时也初步掌握了这类工程调试的方法,特别是编译错误之后慢慢明白了大部分错误提示的意思,还有遇到问题后老师的讲解与同学的帮助,让我有了不小的进步,收获颇丰。 在管脚分配上也遇见一些问题,经过查阅资料,完成了整体编译。还有在进行电路板的焊做过程中,有些元件的安装和焊接出现一些问题,有管脚正负和方向不易区别,要小心分别才能焊好。看到历时一周多的音乐播放器终于完成了。在实验中出现问题很正常,重要的是努力克服困难,发现问题,解决问题,最终提升自己的能力。 还有往电路板上下载程序时,遇到正负极接反问题还有数据线接反问题,和实验电压,5v其实是过高的,经验证3.8v才是合适的输入电压。 所以我们知道,在实验过程中不能少了耐心和细心,虚心接受指导才是正确的选择。
12
五、 指导教师评语
成绩 指导教师签名
13
因篇幅问题不能全部显示,请点此查看更多更全内容