EDA简易电子琴的设计.docx
《EDA简易电子琴的设计.docx》由会员分享,可在线阅读,更多相关《EDA简易电子琴的设计.docx(14页珍藏版)》请在冰豆网上搜索。
EDA简易电子琴的设计
EDA课程设计
设计题目:
简易电子琴的设计
专业:
电子信息工程
班级:
姓名:
学号:
2014年6月18日
基于VHDL原理图及文本输入法
的简单电子琴电路的设计
一.课程设计
1.1课程设计目的
本课程设计主要是基于VHDL文本输入法设计乐曲演奏电路,该系统基于计算机中时钟分频器的原理,采用自顶向下的设计方法来实现,通过按键输入来控制音响或者自动演奏已存入的歌曲。
系统由乐曲自动演奏模块、音调发生模块和数控分频模块三个部分组成。
系统实现是用硬件描述语言VHDL按模块化方式进行设计,然后进行编程、时序仿真、电路功能验证,奏出美妙的乐曲(当然由于条件限制,暂不进行功能验证,只进行编程和时序仿真)。
该设计最重要的一点就是通过按键控制不同的音调发生,每一个音调对应不同的频率,从而输出对应频率的声音。
1.2课程设计内容
(1)设计一个简易的二十四音符电子琴,它可通过按键输入来控制音响。
(2)系统演奏时可以选择是手动演奏(由键盘输入)还是自动演奏已存入的乐曲。
(3)能够自动演奏乐曲,且乐曲可重复演奏。
1.3课程设计原理
本课程设计目的在于灵活运用EDA技术编程实现一个简易电子琴的乐曲演奏,它要求在实验箱上构造一个电子琴电路,不同的音阶对应不同频率的正弦波。
按下每个代表不同音阶的按键时,能够发出对应频率的声音。
故系统可分为乐曲自动演奏模块(AUTO)、音调发生模块(TONE)和数控分频模块(FENPIN)三部分。
每一个模块由一个或者多个PROCESS组成,最后形成一个完整的程序。
上一个模块的输出传送到下一个模块作为输入,并行结构形成一个完整的系统。
另外,时钟脉冲信号在本课程设计中用的最多,用处也最大,一般情况下时钟信号处上升沿有效,判断和控制各个计数器计数多少。
1.4设计框图
驱动扬声器发出乐曲
乐曲选择音调和音符的模块
乐曲自动演奏文本的编辑
二.简易电子琴的设计过程
根据系统设计要求,系统该系统基于计算机中时钟分频器的原理,设计采用自顶向下的设计方法,通过按键输入来控制音响或者自动演奏已存入的歌曲。
它由乐曲自动演奏模块、音调发生模块和数控分频模块三部分组成。
2.1乐曲自动演奏模块
乐曲自动演奏模块的作用是产生8位发生控制输入信号以及选择高低中三个八度的音。
当进行自动演奏时,由存储在此模块的三个拨码开关的数据选择高低中音和8位二进制数作为发声控制输入,从而自动演奏乐曲。
该模块的VHDL源程序主要由3个工作进程组成,分别为FP,JISHU和COM1。
PULSE0的作用是根据键盘输入(自动演奏)的值(0或1)来判断计数器COUNT以及脉冲CLK2的输出值。
部分源程序如下:
FP:
process(clk,auto)
begin
if(auto='1')then--键盘输入为1
count<="0000000000000000000000000";--计数器值指0,时钟信号为0
elsif(clk'eventandclk='1')then--时钟信号到来
count<=count+1;--计数器+1
if(count="111111111111111111111111")then
clk2<='1';--计数次数到分频分为1s左右时钟
count<="0000000000000000000000000";
else
clk2<='0';
endif;
endif;
endprocess;--结束分频
当确定了时钟信号输出的值后,在第二个PROCESS用于计数中,可以由它控制8位发声控制输入信号,对所要进行演奏的音符进行顺序发声。
JISHU:
process(clk2)--开始进程
begin
if(clk2'eventandclk2='1')then--1S的分频信号到来
if(count0="100100")then
count0<="000000";--计数到达最后一个音符,从头开始
else
count0<=count0+1;--每一个信号进行一次计数和输出
endif;
endif;
endprocess;--结束
最后的MUSIC便是由前两个PROCESS所确定的count0、auto和键盘输入信号值index0将8位的二进制数转化为音符信号的输出,同时使用一排LED灯进行演示有音符过来就循环移动,达到自动演奏的目的。
部分源程序如下:
MUSIC:
process(count0,auto,index0)
begin
if(auto='0')then
casecount0is
when"000000"=>index0<="00000001";LCD<="00000001";--1音符1的编码
when"000001"=>index0<="00000001";LCD<="00000001";--1
when"000010"=>index0<="00010000";LCD<="00000100";--5
when"000011"=>index0<="00010000";LCD<="00001000";--5
--------------
endcase;
else
index0<=index;--如果auto为1这是选择手动演奏,跳过自动演奏模块
endif;
endprocess;
该模块最主要的用途就是将输入二进制数转化为发声控制输入和led管示意是否正常工作,是产生音符的重要步骤
2.2音调发生模块:
首先把前一个模块的设定的高中低音符选择的二进制数传过来,以及index0的数据,为音符的正确发声做准备。
mid2<=mid;
low2<=low;
hig2<=hig;--选择高低中音符的数的传输
index1<=index0;--音符编码的传输
yd<=hig2&mid2&low2;--高中低三个数进行合并判断
SH:
process(index1,yd)
begin
if(yd="001")then--选择为低音部
caseindex1is
when"00000001"=>tone0<="0000010111001";code<="11111001";--音符1
when"00000010"=>tone0<="0010000100010";code<="10100100";
when"00000100"=>tone0<="0011100101100";code<="10110000";
when"00001000"=>tone0<="0100010010001";code<="10011001";
when"00010000"=>tone0<="0101100011111";code<="10010010";
when"00100000"=>tone0<="0110101100111";code<="10000010";
when"01000000"=>tone0<="0111101101110";code<="11111000";
when"10000000"=>tone0<="1000001011100";code<="10000000";
whenothers=>tone0<="1111111111111";code<="00000000";--选择音符的不同的频率,为下一步的发声做准备,以及在数码管上显示出当前选择的音符。
elsif(yd="010")then--选择为中音部
caseindex1is
when"00000001"=>tone0<="1000001011100";code<="11111001";
when"00000010"=>tone0<="1001000010001";code<="10100100";
when"00000100"=>tone0<="1001110010110";code<="10110000";
when"00001000"=>tone0<="1010001001001";code<="10011001";
when"00010000"=>tone0<="1010110010000";code<="10010010";
when"00100000"=>tone0<="1011010110011";code<="10000010";
when"01000000"=>tone0<="1011110110111";code<="11111000";
when"10000000"=>tone0<="1100000101110";code<="10000000";
whenothers=>tone0<="1111111111111";code<="00000000";
endcase;
elsif(yd="100")then--选择为低音部
caseindex1is
when"00000001"=>tone0<="1100000101110";code<="11111001";
when"00000010"=>tone0<="1100100001001";code<="10100100";
when"00000100"=>tone0<="1100111011011";code<="10110000";
when"00001000"=>tone0<="1101000100100";code<="10011001";
when"00010000"=>tone0<="1101011001000";code<="10010010";
when"00100000"=>tone0<="1101101011010";code<="10000010";
when"01000000"=>tone0<="1101111011100";code<="11111000";
when"10000000"=>tone0<="0000010111001";code<="10000000";
whenothers=>tone0<="1111111111111";code<="00000000";
endcase;
endif;
endprocess;
选择为自动时,系统的index1值和yd值对音符进行定位,从而输出正确的音符。
选择为手动是,每一次改变index0的值和yd值,系统都会做好一次判断,选择一个正确的音符。
2.3数控分频模块
数控分频模块是对时基脉冲进行分频,得到与0、1、2、3、4、5、6、7八个音符相对应的频率。
首先先把时钟信号给第三个模块,把第二个模块所得的音符的频率计数值给这个模块用于驱动扬声器发声。
clk1<=clk;
tone1<=tone0;
该模块主要由三个工作进程组成。
第一个进程,先对时钟进行分频,分为4Mhz的时钟preclk
JZ:
process(clk1)
variablecount:
STD_LOGIC_VECTOR(2downto0);
begin
if(clk1'eventandclk1='1')then
count:
=count+1;
if(count="010")then
preclk<='1';
elsif(count="100")then
preclk<='0';
count:
="001";
endif;
endif;
endprocess;
第二个PROCESS是此模块的核心,即由时基脉冲值转化为音符的频率。
部分源程序如下:
get:
process(preclk,tone1)
begin
if(preclk'eventandpreclk='1')then
if(count13="1111111111111")then
count13<=tone1;--通过上一个模块所得的tone1的值获得音符频率
fout<='1';
elsecount13<=count13+1;
fout<='0';
endif;
endif;
endprocess;
最后一个PROCESS则是用来设置扬声器输出信号的,扬声器信号由0和1控制,当且仅当前一个PROCESS中的FULLSPKS输出为1时,扬声器才有输出,再根据计数器取值来确定输出是1还是0。
delay:
process(fout)
variablecount2:
STD_LOGIC;
begin
if(fout'eventandfout='1')then
count2:
=notcount2;
if(count2='1')then
dout<='1';
else
dout<='0';
endif;
endif;
endprocess;
enddzq1;
这样就完成了一个二十四音简易电子琴的制作。
三.设计源代码
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
----Uncommentthefollowinglibrarydeclarationifinstantiating
----anyXilinxprimitivesinthiscode.
--libraryUNISIM;
--useUNISIM.VComponents.all;
entitydzqis
Port(mid:
inSTD_LOGIC;
low:
inSTD_LOGIC;
hig:
inSTD_LOGIC;
auto:
inSTD_LOGIC;
clk:
inSTD_LOGIC;
LCD:
outSTD_LOGIC_VECTOR(7downto0);
index:
inSTD_LOGIC_VECTOR(7downto0);
code:
outSTD_LOGIC_VECTOR(7downto0);
dout:
outSTD_LOGIC);
enddzq;
architecturedzq1ofdzqis
signalyd:
STD_LOGIC_VECTOR(2downto0);
signalcount0:
STD_LOGIC_VECTOR(5downto0);
signalcount:
STD_LOGIC_VECTOR(24downto0);
signalclk2:
STD_LOGIC;
signalclk1:
STD_LOGIC;
signalhig2,hig3:
STD_LOGIC;
signalmid2,mid3:
STD_LOGIC;
signallow2,low3:
STD_LOGIC;
signalpreclk:
STD_LOGIC;
signalfout:
STD_LOGIC;
signalcount13:
STD_LOGIC_VECTOR(12downto0);
signalmid4,low4,hig4:
STD_LOGIC;
signaltone1:
STD_LOGIC_VECTOR(12downto0);
signaltone0:
STD_LOGIC_VECTOR(12downto0);
signalindex0:
STD_LOGIC_VECTOR(7downto0);
signalindex1:
STD_LOGIC_VECTOR(7downto0);
begin
FP:
process(clk,auto)
begin
if(auto='1')then
count<="0000000000000000000000000";
elsif(clk'eventandclk='1')then
count<=count+1;
if(count="0100000000000000000000000")then
clk2<='1';
count<="0000000000000000000000000";
else
clk2<='0';
endif;
endif;
endprocess;
JISHU:
process(clk2)
begin
if(clk2'eventandclk2='1')then
if(count0="101000")then
count0<="000000";
else
count0<=count0+1;
endif;
endif;
endprocess;
MUSIC:
process(count0,auto,index0)
begin
if(auto='0')then
casecount0is
when"000000"=>index0<="00000001";LCD<="11111110";--1
when"000001"=>index0<="00000001";LCD<="11111101";--1
when"000010"=>index0<="00010000";LCD<="11111011";--5
when"000011"=>index0<="00010000";LCD<="11110111";--5
when"000100"=>index0<="00100000";LCD<="11101111";--6
when"000101"=>index0<="00100000";LCD<="11011111";--6
when"000110"=>index0<="00010000";LCD<="10111111";--5
when"000111"=>index0<="00010000";LCD<="01111111";--5
when"001000"=>index0<="00001000";LCD<="10111111";--4
when"001001"=>index0<="00001000";LCD<="11011111";--4
when"001010"=>index0<="00000100";LCD<="11101111";--3
when"001011"=>index0<="00000100";LCD<="11110111";--3
when"001100"=>index0<="00000010";LCD<="11111011";--2
when"001101"=>index0<="00000010";LCD<="11111101";--2
when"001110"=>index0<="00000001";LCD<="11111110";--1
when"001111"=>index0<="00000001";LCD<="11111101";--1
when"010000"=>index0<="00010000";LCD<="11111011";--5
when"010001"=>index0<="00010000";LCD<="11110111";--5
when"010010"=>index0<="00001000";LCD<="11101111";--4
when"010011"=>index0<="00001000";LCD<="11011111";--4
when"010100"=>index0<="00000100";LCD<="10111111";--3
when"010101"=>index0<="00000100";LCD<="01111111";--3
when"010110"=>index0<="00000010";LCD<="10111111";--2
when"010111"=>index0<="00000010";LCD<="11011111";--2
when"011000"=>index0<="00000001";LCD<="11101111";--1
when"011001"=>index0<="00000001";LCD<="11110111";--1
when"011010"=>index0<="00010000";LCD<="11111011";--5
when"011011"=>index0<="00010000";LCD<="11111101";--5
when"011100"=>index0<="00100000";LCD<="11111110";--6
when"011101"=>index0<="00100000";LCD<="11111101";--6
when"011110"=>index0<="00010000";LCD<="11111011";--5
when"011111"=>index0<="00010000";LCD<="11110111";--5
when"100000"=>index0<="00001000";LCD<="11101111";--4
when"100001"=>index0<="00001000";LCD<="11011111";--4
when"100010"=>index0<="00000100";LCD<="10111111";--3
when"100011"=>index0<="00000100";LCD<="01111111";--3
when"100100"=>index0<="00000010";LCD<="10111111";--2
when"100101"=>index0<="00000010";LCD<="11011111";--2
when"100110"=>index0<="00000001";LCD<="11101111";--1
when"100111"=>index0<="00000001";LCD<="11110111";--1
when"101000"=>index0<="00000001";LCD<="11111011";--1
whenothers=>index0<="00000000";LCD<="11111111";
endcase;
else
index0<=index;
endif;
endprocess;
mid2<=mid;
low2<=low;
hig2<=hig;
index1<=index0;
yd<=hig2&mid2&low2;
SH:
process(index1,yd)
begin
if(yd="001")then
caseindex1is