北邮数电实验电子琴.docx
《北邮数电实验电子琴.docx》由会员分享,可在线阅读,更多相关《北邮数电实验电子琴.docx(24页珍藏版)》请在冰豆网上搜索。
北邮数电实验电子琴
VHDL硬件描述语言程序设计
简易电子琴演奏器
姓名:
chi
一、设计课题的任务要求3
二、系统设计4
三、仿真波形及波形分析7
四、源程序9
五、功能说明2..0
六、元器件清单及资源利用情况2..1
七、故障及问题分析2..2
八、总结和结论2..3
设计课题的任务要求
基本要求:
1、用8×8点阵显示“1234567”七个音符构成的电子琴键盘。
其中点阵的第一列用一个LED点亮表示音符“1”,第二列用二个LED点亮表示音符“2”,依此类推,如下图所示。
1234567图1点阵显示的电子琴键盘
2、用BTN1~BTN7七个按键模拟电子琴手动演奏时的“1234567”七个音符。
当某个按键按下时,数码管显示相应的音符,点阵上与之对应的音符显示列全灭,同时蜂鸣器演奏相应的声音;当按键弹开时数码管显示的音符灭掉,点阵显示恢复,蜂鸣器停止声音的输出。
下图所示为按下BTN3按键时点阵的显示情况。
1234567图2按键按下后的点阵显示
3、由拨码开关切换选择高、中、低音,并用数码管进行相应的显示。
4、通过按键BTN0进行复位,控制点阵显示图1的初始状态。
提高要求:
1、可通过一个拨码开关进行手动/自动演奏的切换,并与点阵显示配合增加自动演奏乐曲的功能。
2、增加手动演奏的音符存储、播放功能。
系统设计
1.设计思路
简易电子琴的制作主要是利用不同频率的波来驱动蜂鸣器发出声响。
通过输入不同的音符来设置不同的分频系数,使得50MHz的主频分频出不同频率的波。
同时,演奏的音符还可以通过数码管和8*8点阵来动态显示。
根据系统设计要求,该电子琴设计采用自顶向下的设计方法。
整体的功能通过不同的底层模块配合来完成电子琴的功能。
底层模块主要包括乐曲自动演奏模块、分频预置值产生模块和数控分频模块,数码管显示模块,8*8点阵显示模块五部分组成。
用这种设计思路把整个系统分为了若干个模块,然后再在顶层文件中将各个模块组合在一起,从而体现出超、高速硬件描述语言VHDL的优势,
关于提高要求中通过一个拨码开关进行手动/自动演奏的切换,并与点阵显示配合增加自
动演奏乐曲的功能,我打算将一首曲子的音符储存在自动播放的数组里面,然后通过计数器来顺序播放储存的音符。
关于提高要求中的手动演奏的音符存储、播放功能,我打算通过编程实现类似数据结构中队列的模块,来储存手动输入的音符,然后在要播放的时候,队列里面的音符依次出队,从而实现音符储存播放的功能。
2.总体框图
图3简易电子琴总体结构框图
图4简易电子琴逻辑流程图
图5简易电子琴VHDL电路原理图
3.分块设计
(1)分频模块div0
由于实验电路板的主频是50Mhz,为了数码管和点阵的刷新显示,我们必须将50Mhz的频率进行分频。
分频的程序来自电路中心的网站上面。
在这个模块里,我设置分频系数为cnt=2499。
从实验结果看,这个分频对数码管和点阵的显示有很好的效果
(2)数码管显示模块shuma
我使用了2个数码管,第一个数码管显示1~7的音符,第二个数码管显示相关的信息,比如高音用H表示,低音用L表示,自动播放用A表示。
两个数码管分别刷新,但由于刷新频率太快,人眼不能察觉,以为是两个数码管是同时亮的。
在程序中我们通过duan:
outstd_logic_vector(7downto0)和cat:
outstd_logic_vector(5downto0)来控制数码管的显示。
当输入不同的音符和不同的控制信息时,duan和cat向量都有不同的值与之对应。
(3)8*8点阵显示模块dianzhen
8*8点阵的显示和数码管的显示运用了同样的原理,在程序中我们通过row:
outstd_logic_vector(7downto0)和col:
outstd_logic_vector(7downto0)这两个向量来控制点阵的显示。
当输入不同的音符时,点阵显示相应的形状。
(4)音符产生模块auto。
这个模块的功能是,选择的不同模式来产生不同的音符。
当选择自动播放模式时,随着计数器count的值增加,即地址值递增时,程序自动读取出事先储存的音符,并把这个音符输出。
当选择手动演奏模式时,直接将通过BTN1~BTN7输入的向量当做音符输出yin:
out
std_logic_vector(6downto0);。
(5)分频预置值产生模块该模块的功能是通过音符以及高低音选项来查表找到对应的频率值。
在程序中设置了全部音符对应的分频预置数。
通过判断音符产生模块输出的音符yin:
instd_logic_vector(6
downto0),以及拨码开关的高低音highlow:
instd_logic_vector(1downto0)控制键,来查找出该音符的频率值,然后将该频率赋值给tone:
outintegerrange0to2000000);。
(6)数控分频发声模块
从实验板上面输入的时钟是50MHz的,必须经过分频后由clk_out输出,驱动蜂鸣器发声。
Clk_out的输出频率就对应着音符的音调。
分频系数由来自分频预置值模块的tone:
out
integerrange0to2000000)。
由于直接从数控分频器中出来的输出信号是脉宽极窄的脉冲式信号。
为了利用驱动蜂鸣器,需要再增加一个进程,多波形进行整理,均衡占空比
三、仿真波形及波形分析
1.数码管显示模块仿真波形
波形分析:
不同的yin,和highlow组合,数码管显示不同的字符。
duan[0]~duan[7]对应着数码管的a段到h段,cat[0]~cat[5]控制不同的数码管
波形分析:
不同的yin输入,点阵的col和row会有不同的波形,利用clk_in的上升沿来动态扫描点阵。
从而得显示出指定的图形。
3.自动播放模块仿真波形
波形分析:
当auto置1,clear置0,yin_out输出储存在程序里面的曲子音符,这时候相当于自动播放。
当auto置0,clear置0,yin_out输出从BTN1~BTN7读取的手动输入的信号,这时候相当于手动演奏。
4.分频预置值产生模块仿真波形
波形分析:
输入不同的高低音highlow,和音符yin,输出不同的tone。
而tone将作为发声模
块的分频预置值
四、源程序
1.分频模块源程序libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entitydiv0isport(clk_in:
instd_logic;
clk_tmp:
outstd_logic);
end;
architecturebofdiv0is
signalclk:
std_logic;
begin
p0:
process(clk_in)
variablecnt:
integerrange0to2499;begin
if(clk_in'eventandclk_in='1')thenifcnt=2499thencnt:
=0;clk<=notclk;
elsecnt:
=cnt+1;
--输入时钟
--输出时钟
--分频系数为2499
--每个输入时钟上升沿到来时
cnt加1
endif;
endif;
endprocessp0;
clk_tmp<=clk;
endb;
2.数码管显示源程序libraryieee;useieee.std_logic_1164.all;useieee.std_logic_unsigned.all;
entityshumais
port(clk_in:
instd_logic;
--以分频的时钟输入
yin:
instd_logic_vector(6downto0);--输入音符
highlow:
instd_logic_vector(1downto0);--输入高低音
auto:
instd_logic;--自动播放auto1:
instd_logic;--自动播放1
duan:
outstd_logic_vector(7downto0);
cat:
outstd_logic_vector(5downto0)
);end;
architecturebofshumais
signalduant:
std_logic_vector(7downto0);signalcatt:
std_logic_vector(5downto0);
begin
p1:
process(clk_in,yin,highlow,auto,auto1)begin
ifauto='1'then
catt<="111101";duant<="00111111";elsifauto1='1'then
catt<="111101";duant<="01111111";elsifauto='0'then
--显示“8”表示自动播放
--显示“0”表示试音
if(clk_in='0')thencaseyinis
when"0000001"=>catt<="111110";duant<="00000110";--显示“1”
when"0000010"=>catt<="111110";duant<="01011011";--显示“2”
when"0000100"=>catt<="111110";duant<="01001111";--显示“3”
when"0001000"=>catt<="111110";duant<="01100110";--显示“4”
when"0010000"=>catt<="111110";duant<="01101101";--显
示“5”when"0100000"=>
catt<="111110";duant<="01111101";--显示“6”when"1000000"
=>catt<="111110";duant<="00000111";--显示“7”whenothers=>
catt<="111111";duant<="00000000";
endcase;
elsif(clk_in='1')then
casehighlowis
when"10"=>catt<="111101";duant<="01110100";--显示“L”
when"01"=>catt<="111101";duant<="00111000";--显示“H”whenothers=>catt<="111111";duant<="00000000";
endcase;
endif;
endif;
endprocessp1;
cat<=catt;
duan<=duant;
endb;
3.点阵显示源程序
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entitydianzhenis
port(clk_in:
instd_logic;
--时钟输入
yin:
instd_logic_vector(6downto0);
--输入音符
row:
outstd_logic_vector(7downto0);
--点阵行向量
col:
outstd_logic_vector(7downto0)
--点阵列向量
);end;
architecturebofdianzhenis
signalcount:
integerrange0to6;
signalrowt:
std_logic_vector(7downto0);
signalcolt:
std_logic_vector(7downto0);
begin
p1:
process(clk_in)
begin
if(clk_in'eventandclk_in='1')then
ifcount=6thencount<=0;
elsecount<=count+1;--用count来记数
endif;
endif;
endprocessp1;
p2:
process(count,yin)beginif(yin="0000001")then
casecountis--点阵显示,表示“1”音符
when0=>rowt<="11111110";colt<="01111110";
when1=>rowt<="11111101";colt<="01111110";
when2=>rowt<="11111011";colt<="01111100";
when3=>rowt<="11110111";colt<="01111000";
when4=>rowt<="11101111";colt<="01110000";
when5=>rowt<="11011111";colt<="01100000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
elsif(yin="0000010")then
casecountis--点阵显示,表示“2”音符
when0=>rowt<="11111110";colt<="01111101";
when1=>rowt<="11111101";colt<="01111100";
when2=>rowt<="11111011";colt<="01111100";
when3=>rowt<="11110111";colt<="01111000";
when4=>rowt<="11101111";colt<="01110000";
when5=>rowt<="11011111";colt<="01100000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
elsif(yin="0000100")then
casecountis--点阵显示,表示“3”音符
when0=>rowt<="11111110";colt<="01111011";
when1=>rowt<="11111101";colt<="01111010";
when2=>rowt<="11111011";colt<="01111000";
when3=>rowt<="11110111";colt<="01111000";
when4=>rowt<="11101111";colt<="01110000";
when5=>rowt<="11011111";colt<="01100000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
--点阵显示,表示“4”音符
elsif(yin="0001000")thencasecountiswhen0=>rowt<="11111110";colt<="01110111";
when1=>rowt<="11111101";colt<="01110110";
when2=>rowt<="11111011";colt<="01110100";
when3=>rowt<="11110111";colt<="01110000";
when4=>rowt<="11101111";colt<="01110000";
when5=>rowt<="11011111";colt<="01100000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
elsif(yin="0010000")then
casecountis--点阵显示,表示“5”音符
when0=>rowt<="11111110";colt<="01101111";
when1=>rowt<="11111101";colt<="01101110";
when2=>rowt<="11111011";colt<="01101100";
when3=>rowt<="11110111";colt<="01101000";
when4=>rowt<="11101111";colt<="01100000";
when5=>rowt<="11011111";colt<="01100000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
elsif(yin="0100000")then
casecountis--点阵显示,表示“6”音符
when0=>rowt<="11111110";colt<="01011111";
when1=>rowt<="11111101";colt<="01011110";
when2=>rowt<="11111011";colt<="01011100";
when3=>rowt<="11110111";colt<="01011000";
when4=>rowt<="11101111";colt<="01010000";
when5=>rowt<="11011111";colt<="01000000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
elsif(yin="1000000")then
casecountis--点阵显示,表示“7”音符
when0=>rowt<="11111110";colt<="00111111";
when1=>rowt<="11111101";colt<="00111110";
when2=>rowt<="11111011";colt<="00111100";
when3=>rowt<="11110111";colt<="00111000";
when4=>rowt<="11101111";colt<="00110000";
when5=>rowt<="11011111";colt<="00100000";
when6=>rowt<="10111111";colt<="00000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
else
casecountis--点阵显示,表示不输入音符when0=>rowt<="11111110";colt<="01111111";
when1=>rowt<="11111101";colt<="01111110";
when2=>rowt<="11111011";colt<="01111100";
when3=>rowt<="11110111";colt<="01111000";
when4=>rowt<="11101111";colt<="01110000";
when5=>rowt<="11011111";colt<="01100000";
when6=>rowt<="10111111";colt<="01000000";
whenothers=>rowt<="11111111";colt<="00000000";
endcase;
endif;
endprocessp2;
row<=rowt;
col<=colt;
endb;
4.选择音符及自动播放源程序
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityautois
port(clk_in
:
instd_logic;
--输入时钟
auto
:
instd_logic;
--自动播放
auto1
:
instd_logic;
--试音播放
clear
:
instd_logic;
--复位
yin_in
:
instd_logic_vector(6downto0);
--输入音符
yin_out
:
outstd_logic_vector(6downto0));
--输出音符
endauto;
architectureaofautois
signalcount:
integerrange0to35;
sign