基于FPGA的多功能电子琴设计与实现

基于FPGA的多功能电子琴设计与实现
基于FPGA的多功能电子琴设计与实现

西南科技大学

电子专业综合设计报告

设计名称:基于FPGA的多功能电子琴的设计与实现

姓名:

学号:

班级:

指导教师:

起止日期: 2013年11月22日-2013年12月10 日

西南科技大学信息工程学院制

综合设计任务书

学生班级:电子1001 学生姓名:学号:

设计名称:基于FPGA的多功能电子琴的设计与实现

起止日期:2013.11.22-2013.12.10 指导教师:

综合设计学生日志

基于FPGA的多功能电子琴的设计与实现

摘要:随着科学技术的日新月异,人们的生活也在发生在变化,电子产品也随之增多,比如

现在流行的电子琴,已经逐渐代替了曾经的手动风琴了。文章中所介绍的多功能电子琴的设计在Quartus II平台上,采用Verilog HDL 语言和模块化的设计方法,设计出一个能够通过按键控制不同的音符,同时也可以通过按键进行演奏已经存储的曲子的多功能电子琴。本系统主要由五个个模块组成:顶层模块,曲目1模块,曲目2模块,按键模块,曲目循环播放模块。

关键词: FPGA;电子琴; Verilog HDL;音符

FPGA-based design and implementation of multi-organ

Abstract:With the development of science and technology, also occurs in people's lives change, electronic products also increase, such as the now popular organ, has replaced the former manual organ. Multifunction keyboard design as described in the article on the Quartus II platform, using Verilog HDL language and modular design method, design a button control through different note, you can also play music already stored by keys multifunction keyboard. The system consists of five modules: the top-level module, a module tracks, track 2 modules, key module, track loop module.

Key words: FPGA, Keyboard, Verilog HDL, Note

一、设计目的和意义

目的:

1.1、在掌握计算机组成原理理论相关的基础上,了解 EDA技术,掌握 Verilog HDL 硬

件描述语言的设计方法和思想;

1.2、培养综合运用知识和独立开展实践创新的能力;

1.3、深入学习Verilog HDL,了解其编程环境;

1.4、学会运用Quartus II等编程仿真软件;

1.5将硬件语言编程与硬件实物功能演示相结合,加深理解Verilog HDL的学习。

意义:

电子琴由于操作相对比较简单,并且能够模拟几乎所有传统乐器的音色,因而深受广大消费者的喜爱。近年来,在数字系统的设计领域融入了一种新型的设计技术:数字系统设计的自动化技术EDA(Electronic Design Automation)。该技术优越之处在于系统设计的效率高、保密性强、集成度好、易于修改和实现等。因此,一跃成为当下数字系统设计领域的主流技术,并被越来越广泛地应用到相关领域中,其中,被应用到电子琴的设计与实现中去就是一个相当重要的尝试及应用。

二、控制要求

2.1、软件:Quartus II等编程仿真软件;

2.2、硬件:FPGA开发板。

三、设计方案论证

方案一:采用单片机实现,通过软件编程,仿真后将程序用编程器写入到单片机芯片上,该方案成本低,稳定度也比较好,但外围电路多,特别是播放音乐时需要用到大容量的外部存储器,这样就增加了编程难度,调试不够直观,也不够灵活方便。

方案二:采用可编程逻辑器件(FPGA)制作,将所有器件集成在一块芯片上,大大减小了电子琴的体积,用Verilog HDL编程实现时更加方便,而且易于进行功能扩展,并可调试仿真。

综上,本次课程设计选择方案二

四、系统设计

1、总体实现方案:

1.1简易电子琴的设计通过软硬件结合实现,硬件系统包括主控器芯片、9个按键、蜂鸣器等,软件资源包括编写Verilog HDL程序的仿真软件Quartus II。电子琴有按键代替琴键的弹奏功能、自动播放功能、循环播放功能。

1.2整个程序总共分5个模块:顶层模块,曲目1:bell模块,曲目2:bell2模块,按键模块:buzzer,曲目循环播放模块:bell_bell2,整个方案总共用了9个按键(k2-k8),按键k2-k8作为琴键,通过这七个按键键入不同的音阶。主模块中k9、k10两个按键用于选择是自动播放还是弹奏曲目,令mm=(k10、k9),用mm值的不同选择调用不同模块。如果mm=11,则程序调用按键模块;如果mm=01,则调用曲目1模块,播放曲目1;如果mm=10,则调用曲目2模块,播放曲目2;如果mm=00,则调用循环模块。

2、原理框图

out4

9个按键:k2-k10;k2-k8控制按键buzzer模块,k10、k9是选择按键,当k10k9=11,选择buzzer模块,输出out3;当k10k9=01,选择bell模块,输出out1;当k10k9=10,选择bell2模块,输出out2;当k10k9=00,选择bell_bell2模块,输出out4。

3、输入输出

4、音符与音频

乐曲中不同的音符实质上表示的是不同频率的声音。只要产生不同频率的脉冲,再通过喇叭等播放出来即可。又由于方波容易用定时器产生,故使用方波脉冲。

4.1要产生音频脉冲:

1、算出某一音频的脉冲的周期(1/频率)

2、然后将此周期除以2,即为半周期的时间。

3、利用定时器,计时这个半周期的时间,每当计时到后,就将输出脉冲的I/O反相。

4、重复计时此半周期的时间再对I/O反相,就可以在I/O脚上得到此频率的脉冲。

例如,频率为523Hz,其周期为1/523 S=1912uS,因此只要令计数器计时956,在每计数956次时就将I/O反接,就可得到中音Do(532Hz)。

4.2音阶及其对应频率

五、设计结果及分析

5.1功能仿真

5.2所有引脚锁定

5.3总体电路图

5.3分析

仿真结果;设置输入信号k2-k10为低电平有效,因此,当不按下按键时,所有的按键均为高电平。此时k10~key9=11,即mm=11,即在按键模块,输出out3连接输出端outclk;当按下k10时,即mm=01,此时选择曲目1模块,输出out1连接到输出端outclk;当按下k9时,

即mm=10,此时选择曲目2模块,输出out2连接输出端outclk;当同时按下k9k10时,输出

out4连接输出端outclk。

5.3.1硬件测试结果:

在时序验证后下载,通过硬件测试,实验达到预期效果,当mm(k10-k9)=11时,通过k2-k8这7个按键的键入蜂鸣器可以发出Do、re、mi、fa、so、la、xi的七个音阶的音,即表示了电子琴的按键弹奏功能;当mm=01时,播放了第一首歌;mm=10时,播放了第二首歌;当mm=00时,循环播放。通过硬件的测试,所有的设计目标均实现。

5.3.2对结果和结论的问题讨论:

实验过程中,程序刚一下载,蜂鸣器就开始发声音,后来,经过查证,蜂鸣器的驱动是低电平有效,因此,最开始时,将蜂鸣器初始化为高电平。实验结果中七个音节的区分不是特别明显,因为音节的频率都相差不是很大。

结束语

通过这近一个月天的学习和努力,让我收获颇多。刚开始的时候还不知道如何下手,并且对所用的软件QuartusⅡ不熟悉,因为之前所用的软件是Xilinx ISE,但是通过一次次的努力和摸索,发现其实这两款软件还是有很多共同的地方,自己对新的软件应用也越来越得心应手了。此外,在这次的课程设计中,我越来越认识到一点,编程对项目实现有着至关重要的作用,我们在硬件开发的过程中必须重视编程,将编程看作是完善开发的不可缺少的一部分。在一次次的反复设计、论证和测试中,不仅提高了逻辑分析能力、全面分析问题的能力,还提升了发现问题、解决问题的能力,不懂的地方在经过思考还是无果的情况下,就要向他人请教了,他人一点小小的点拨,会为你带来灵感,这也将是问题的解决方法。虽然设计过程比较繁琐,大大小小也出现了许多问题,但这却磨练了我的意志。通过各方面的学习,使我的知识面进一步拓宽了。通过这次课程设计,我不但熟悉了quartusII软件,也了解了开发的最基本流程和方法,也进一步加深了对Verilog HDL编程语言的理解,最重要的是锻炼了我独立思考和分析的逻辑能力,通过至顶向下的设计方法,一步步实现,然后将整个设计串套起来,是我对设计的流程以及编程有了很大的提高。同时,通过本次课程设计,我也发现了自己的不足,例如:逻辑分析能力不突出,编程能力不足,解决问题的能力不足,不是特别细心,这些使我认识到在以后的学习中在这些方面要多加努力,加以改进,提升自我能力。我相信通过这次课程设计的学习,对我以后的学习和工作都有着十分重要的影响和作用。

参考文献(递增引用,引用相关内容)

【1】刘桂华. 《基于FPGA的现代数字系统设计》. 西安电子科技大学出版社第1-101页

【2】袁海林. 基于FPGA的具有存储功能的电子琴的设计[J]. 中国信息科技,2007.19:88-89

【3】曹曼. 基于FPGA的电子琴设计. 科技传播, 2012-03-08

【4】张亮. 基于FPGA的电子琴的设计[J]. 电子技术,2007,(2)

【5】华清远见嵌入式培训中心编著《FPGA应用开发入门与典型实例》人民邮电出版社第145-161页

附录(程序、电路图等)

1、顶层模块程序:

module dianziqin(inclk,outclk,k2,k3,k4,k5,k6,k7,k8,k9,k10);

input inclk;

input k2,k3,k4,k5,k6,k7,k8,k9,k10;

output outclk;

reg outclk,clk_6M;

reg [3:0]c;

wire out1,out2,out3;

wire[1:0] key;

reg [1:0]mm;

assign key = {k10,k9}; //由按键拼键为变量key

//调用子调块

buzzer m1(

.inclk(inclk),

.k2(k2),

.k3(k3),

.k4(k4),

.k5(k5),

.k6(k6),

.k7(k7),

.k8(k8),

.beep3(out3)

);

bell m2(

.inclk(inclk),

.beep1(out1)

);

bell2 m3(

.inclk(inclk),

.beep2(out2)

);

bell_bell2 m4( .inclk(inclk),

.beep4(out4)

);

always@(posedge inclk)

begin

if(c<4'd8)

c<=c+4'd1;

else

begin

c <= 4'd0;

clk_6M <= ~clk_6M;

end

end

always @(posedge clk_6M) //在时钟的上升沿检测是否有按键按下begin

if(key == 2'b01)

mm <= 2'b01;

else if(key==2'b10)

mm <= 2'b10;

else if(key==2'b11)

mm <= 2'b11;

else if(key==2’b00)

mm <= 2'b00;

else mm<=2’bzz;

end

always @(mm) //按键响应

begin

if(mm == 2'b01)

outclk <= out1;

else if(mm == 2'b10)

outclk <= out2;

else if (mm==2'b11)

outclk <= out3;

else if (mm==2’b00)

outclk<=out4;

else outclk<=0;

end

endmodule

2、按键模块:

module buzzer(inclk,k2,k3,k4,k5,k6,k7,k8,beep3);

input inclk, k2,k3,k4,k5,k6,k7,k8;

output beep3;

wire [6:0] key_code;

reg [3:0] c;

reg clk_6M;

reg beep_r;

reg [15:0] count;

reg [15:0] count_end;

parameter Do = 7'b1111110;

re = 7'b1111101;

mi = 7'b1111011;

fa = 7'b1110111;

so = 7'b1101111;

la = 7'b1011111;

si = 7'b0111111;

assign ke y_code ={k8,k7,k6,k5,k4,k3,k2};

assign beep3 = beep_r; //输出音乐

always@(posedge inclk)

begin

if(c<4'd8)

c<=c+4'd1;

else

begin

c <= 4'd0;

clk_6M <= ~clk_6M;

end

end

always@(posedge clk_6M) //分频模块,得出乐谱begin

count <= count + 16'd1;

if (count_end==0)

beep_r<=1; //计数器加1

else if(count == count_end)

begin

count <=16'd0; //计数器清零

beep_r <= !beep_r;

end

end

always@(posedge clk_6M) //状态机,根据按键状态,选择不同的音符输出begin

case(key_code)

Do: count_end <= 16'd3822;

re: count_end <= 16'd3405;

mi: count_end <= 16'd3034;

fa: count_end <= 16'd2865;

so: count_end <= 16'd7802;

la: count_end <= 16'd6802;

si: count_end <= 16'd6060;

default:count_end <= 16'h0;

endcase

end

endmodule

3、曲目1模块:

module bell(inclk,beep1);

input inclk; //系统时钟

output beep1; //蜂鸣器输出端

reg [3:0]high,med,low;

reg [15:0]origin;

reg beep_r; //寄存器

reg [7:0]state;

reg [15:0]count;

assign beep1=beep_r; //输出音乐

reg clk_6MHz; //时钟频率6MHz

reg [2:0] cnt1;

always@(posedge inclk)

begin

if(cnt1<3'd8)

cnt1<=cnt1+3'b1;

else

begin

cnt1<=3'b0;

clk_6MHz<=~clk_6MHz;

end

end

reg clk_4Hz; //时钟频率4Hz

reg [24:0] cnt2;

always@(posedge inclk)

begin

if(cnt2<25'd1*******)//

cnt2<=cnt2+25'b1;

else

begin

cnt2<=25'b0;

clk_4Hz<=~clk_4Hz;

end

end

always @(posedge clk_6MHz)

begin

count <= count + 1'b1; //计数器加1

if(count == origin)

begin

count <= 16'h0; //计数器清零

beep_r <= !beep_r; //输出取反

end

end

always@(posedge clk_4Hz)

begin

case({high,med,low})

12'b000000010000:origin=11466;//mid1

12'b000000100000:origin=10216;//mid2

12'b000000110000:origin=9101; //mid3

12'b000001000000:origin=8590; //mid4

12'b000001010000:origin=7653; //mid5

12'b000001100000:origin=6818; //mid6

12'b000000000101:origin=14447;//low5

endcase

end

always @(posedge clk_4Hz) //歌曲1

begin

if(state ==63) state = 0;//计时,以实现循环演奏

else

state = state + 1;

case(state)

0,1: {high,med,low}=12'b000000010000;//mid1 2,3: {high,med,low}=12'b000000100000;//mid2 4,5: {high,med,low}=12'b000000110000;//mid3 6,7: {high,med,low}=12'b000000010000;//mid1 8,9: {high,med,low}=12'b000000010000;//mid1 10,11: {high,med,low}=12'b000000100000;//mid2 12,13: {high,med,low}=12'b000000110000;//mid3 14,15: {high,med,low}=12'b000000010000;//mid1 16,17: {high,med,low}=12'b000000110000;//mid3 18,19: {high,med,low}=12'b000001000000;//mid4

20,21,22,23: {high,med,low}=12'b000001010000;//mid5 24,25: {high,med,low}=12'b000000110000;//mid3 26,27: {high,med,low}=12'b000001000000;//mid4 28,29,30,31: {high,med,low}=12'b000001010000;//mid5 32: {high,med,low}=12'b000001010000;//mid5 33: {high,med,low}=12'b000001100000;//mid6 34: {high,med,low}=12'b000001010000;//mid5 35: {high,med,low}=12'b000001000000;//mid4 36,37: {high,med,low}=12'b000000110000;//mid3 38,39: {high,med,low}=12'b000000010000;//mid1 40: {high,med,low}=12'b000001010000;//mid5 41: {high,med,low}=12'b000001100000;//mid6 42: {high,med,low}=12'b000001010000;//mid5 43: {high,med,low}=12'b000001000000;//mid4 44,45: {high,med,low}=12'b000000110000;//mid3 46,47: {high,med,low}=12'b000000010000;//mid1 48,49: {high,med,low}=12'b000000100000;//mid2 50,51: {high,med,low}=12'b000000000101;//low5 52,53,54,55: {high,med,low}=12'b000000010000;//mid1 56,56: {high,med,low}=12'b000000100000;//mid2 57,58: {high,med,low}=12'b000000000101;//low5 59,60,61,62,63: {high,med,low}=12'b000000010000;//mid1 default : {high,med,low}=12'bx;

endcase

end

endmodule

4、曲目2模块:

module bell2 (inclk,beep2);

input inclk; //系统时钟

output beep2; //蜂鸣器输出端

reg [3:0]high,med,low;

reg [15:0]origin;

reg beep_r; //寄存器

reg [7:0]state;

reg [15:0]count;

assign beep2=beep_r; //输出音乐

//时钟频率6MHz

reg clk_6MHz;

reg [2:0] cnt1;

always@(posedge inclk)

begin

if(cnt1<3'd8)

cnt1<=cnt1+3'b1;

else

begin

cnt1<=3'b0;

clk_6MHz<=~clk_6MHz;

end

end

//时钟频率4MHz

reg clk_4Hz;

reg [24:0] cnt2;

always@(posedge inclk)

begin

if(cnt2<25'd1*******)//

cnt2<=cnt2+25'b1;

else

begin

cnt2<=25'b0;

clk_4Hz<=~clk_4Hz;

end

end

always @(posedge clk_6MHz)

begin

count <= count + 1'b1; //计数器加1 if(count == origin)

begin

count <= 16'h0; //计数器清零

beep_r <= !beep_r; //输出取反end

end

always@(posedge clk_4Hz)

begin

case({high,med,low})

'b000000000001:origin=22900; //低1

'b000000000010:origin=20408; //低2

'b000000000011:origin=18181; //低3

'b000000000100:origin=17142; //低4

'b000000000101:origin=15267; //低5

'b000000000110:origin=13605; //低6

'b000000000111:origin=12121; //低7

'b000000000111:origin=11472; //中1

'b000000100000:origin=10216; //中2

'b000000110000:origin=9101; //中3

'b000000111000:origin=8571; //中4

'b000001010000:origin=7653; //中5

'b000001100000:origin=6818; //中6

'b000010000000:origin=6060; //中7

'b000100000000:origin=5733; //高1

'b001000000000:origin=5108; //高2

'b001100000000:origin=4551; //高3

'b001010000000:origin=4294; //高4

'b010*********:origin=3826; //高5

'b011000000000:origin=3409; //高6

'b010*********:origin=3050; //高7

endcase

end

always @(posedge clk_4Hz)

begin

if(state ==195)state = 0;

else

state = state + 1; //kang ding qing ge

case(state)

0: {high,med,low}='b000001100000;//中6 1: {high,med,low}='b000010000000;//中7 2,3,4: {high,med,low}='b000100000000;//高1 5: {high,med,low}='b000010000000;//中7 6,7: {high,med,low}='b000100000000;//高1 8,9: {high,med,low}='b001100000000;//高3 10,11,12,13,14,15: {high,med,low}='b000010000000;//中7 16,17: {high,med,low}='b000000110000;//中3 18,19,20: {high,med,low}='b000001100000;//中6 21: {high,med,low}='b000001010000;//中5 22,23: {high,med,low}='b000001100000;//中6 24,25: {high,med,low}='b000000000111;//中1 26,27,28,29,30,31: {high,med,low}='b000001010000;//中5 32: {high,med,low}='b000000110000;//中3 33: {high,med,low}='b000000110000;//中3 34,35,36: {high,med,low}='b000000111000;//中4 37: {high,med,low}='b000000110000;//中3 38: {high,med,low}='b000000111000;//中4 39,40,41: {high,med,low}='b000100000000;//高1 42,43,44: {high,med,low}='b000000110000;//中3 45,46,47: {high,med,low}='b000100000000;//高1 48,49,50: {high,med,low}='b000010000000;//中7 51,52,53: {high,med,low}='b000000111000;//中4 54,55,56,57,58,59,60,61: {high,med,low}='b000010000000;//中7 62: {high,med,low}='b000001100000;//中6 63: {high,med,low}='b000010000000;//中7 64,65,66: {high,med,low}='b000100000000;//高1 67: {high,med,low}='b010*********;//高7

68,69: {high,med,low}='b000100000000;//高1

70,71: {high,med,low}='b001100000000;//高3

72,73,74: {high,med,low}='b000010000000;//中7

75,76: {high,med,low}='b000000110000;//中3

77,78,79: {high,med,low}='b000001100000;//中6

80: {high,med,low}='b000000000101;//中5

81,82: {high,med,low}='b000001100000;//中6

83,84: {high,med,low}='b000000000111;//中1

85,86,87,88,89,90: {high,med,low}='b000001010000;//中5

91: {high,med,low}='b000000110000;//中3 92: {high,med,low}='b000000110000;//中3 93,94: {high,med,low}='b000000111000;//中4 95: {high,med,low}='b000100000000;//高1 96,97,98: {high,med,low}='b000010000000;//中7 99,100: {high,med,low}='b000100000000;//高1 101,102: high,med,low}='b001000000000;//高2 103: {high,med,low}='b001100000000;//高3 104,105,106,107,108,109: {high,med,low}='b000100000000;//高1 110: {high,med,low}='b000010000000;//中7 111,112: {high,med,low}='b000001100000;//中6 113,114: {high,med,low}='b000010000000;//中7 115,116: {high,med,low}='b000001010000;//中5 117,118,119,120,121,122: {high,med,low}='b000001100000;//中6 123,124: {high,med,low}='b000000000111;//中1 125: {high,med,low}='b001000000000;//高2 126,127,128: {high,med,low}='b001100000000;//高3 129: {high,med,low}='b001000000000;//高2 130,131: {high,med,low}='b001100000000;//高3 132,133: {high,med,low}='b010*********;//高5 134,135,136,137,138,139: {high,med,low}='b001000000000;//高2 140,141: {high,med,low}='b000001010000;//中5 142,143,144: {high,med,low}='b000100000000;//高1 145: {high,med,low}='b000010000000;//中7 146,147: {high,med,low}='b000100000000;//高1 148,149,150,151,152,153,154,155:{high,med,low}='b001100000000;//高3 156,157: {high,med,low}='b000001100000;//中6 158,159: {high,med,low}='b000010000000;//中7 160,161,162,163: {high,med,low}='b000100000000;//高1 164,165: {high,med,low}='b000010000000;//中7 166,167: {high,med,low}='b000100000000;//高1 168,169: {high,med,low}='b001000000000;//高2 170,171,172: {high,med,low}='b000100000000;//高1 173,174,175,176,177,178: {high,med,low}='b000001010000;//中5 179,180: {high,med,low}='b001010000000;//高4

相关主题
相关文档
最新文档