当前位置:文档之家› 北邮数电实验电子琴

北邮数电实验电子琴

VHDL 硬件描述语言程序设计简易电子琴演奏器姓名:chi目录设计课题的任务要求 (4)系统设计 (5)三、仿真波形及波形分析.................................................. 1..0四、源程序.............................................................. 1.3.五、功能说明............................................................ 3.7.六、元器件清单及资源利用情况 (37)七、故障及问题分析 (39)八、总结和结论.......................................................... 4.0设计课题的任务要求基本要求:1、用8 X8点阵显示“ 1 2 3 4 5 6 7 ”七个音符构成的电子琴键盘。

其中点阵的第一列用一个LED点亮表示音符“ 1 ”,第二列用二个LED点亮表示音符“ 2”,依此类推, 如下图所示。

ooo o ooo O oooeeee* ooooatae oooooeee ooooooee ooooooo*图1点阵显示的电子琴键盘2、用BTN1〜BTN7七个按键模拟电子琴手动演奏时的“ 1 2 3 4 5 6 7 ”七个音符。

当某个按键按下时,数码管显示相应的音符,点阵上与之对应的音符显示列全灭,同时蜂鸣器演奏相应的声音;当按键弹开时数码管显示的音符灭掉,点阵显示恢复,蜂鸣器停止声音的输出。

下图所示为按下BTN3按键时点阵的显示情况。

图2 按键按下后的点阵显示3、由拨码开关切换选择高、中、低音,并用数码管进行相应的显示。

4、通过按键BTNO进行复位,控制点阵显示图1的初始状态。

提高要求:1、可通过一个拨码开关进行手动/自动演奏的切换,并与点阵显示配合增加自动演奏乐曲的功能。

2、增加手动演奏的音符存储、播放功能。

二、系统设计1.设计思路简易电子琴的制作主要是利用不同频率的波来驱动蜂鸣器发出声响。

通过输入不同的音符来设置不同的分频系数,使得50MHz的主频分频出不同频率的波。

同时,演奏的音符还可以通过数码管和8*8点阵来动态显示。

根据系统设计要求,该电子琴设计采用自顶向下的设计方法。

整体的功能通过不同的底层模块配合来完成电子琴的功能。

底层模块主要包括乐曲自动演奏模块、分频预置值产生模块和数控分频模块,数码管显示模块,8*8点阵显示模块五部分组成。

用这种设计思路把整个系统分为了若干个模块,然后再在顶层文件中将各个模块组合在一起,从而体现出超、高速硬件描述语言VHDL的优势,关于提高要求中通过一个拨码开关进行手动/自动演奏的切换,并与点阵显示配合增加自动演奏乐曲的功能,我打算将一首曲子的音符储存在自动播放的数组里面,然后通过计数器来顺序播放储存的音符。

关于提高要求中的手动演奏的音符存储、播放功能,我打算通过编程实现类似数据结构中队列的模块,来储存手动输入的音符,然后在要播放的时候,队列里面的音符依次出队,从而实现音符储存播放的功能。

2.总体框图图3 简易电子琴总体结构框图图4 简易电子琴逻辑流程图std_logic_vector(7 dow nto 0) 禾口cat : out std_logic_vector(5 downto 0) 来控制数码管图5 简易电子琴VHDL电路原理图3. 分块设计(1)分频模块divO由于实验电路板的主频是50Mhz,为了数码管和点阵的刷新显示,我们必须将50Mhz的频率进行分频。

分频的程序来自电路中心的网站上面。

在这个模块里,我设置分频系数为cnt=2499 。

从实验结果看,这个分频对数码管和点阵的显示有很好的效果(2)数码管显示模块shuma我使用了2个数码管,第一个数码管显示1~7的音符,第二个数码管显示相关的信息,比如高音用H表示,低音用L表示,自动播放用A表示。

两个数码管分别刷新,但由于刷新频率太快,人眼不能察觉,以为是两个数码管是同时亮的。

在程序中我们通过duan : out的显示。

当输入不同的音符和不同的控制信息时,duan和cat向量都有不同的值与之对应。

(3)8*8点阵显示模块dianzhen8*8点阵的显示和数码管的显示运用了同样的原理,在程序中我们通过row : outstd_logic_vector(7 downto 0) 和col : out std」ogic_vector(7 downto 0) 这两个向量来控制点阵的显示。

当输入不同的音符时,点阵显示相应的形状。

(4)音符产生模块auto。

这个模块的功能是,选择的不同模式来产生不同的音符。

当选择自动播放模式时,随着计数器count的值增加,即地址值递增时,程序自动读取出事先储存的音符,并把这个音符输出。

当选择手动演奏模式时,直接将通过BTN1~BTN7输入的向量当做音符输出yin :out std_logic_vector(6 dow nto 0); 。

(5)分频预置值产生模块该模块的功能是通过音符以及高低音选项来查表找到对应的频率值。

在程序中设置了全部音符对应的分频预置数。

通过判断音符产生模块输出的音符yin :in std」ogic_vector(6 down to 0),以及拨码开关的高低音highlow :in std」o gic_vector(1 dow nto 0) 控制键,来查找出该音符的频率值,然后将该频率赋值给tone :out in teger range 0 to 2000000);。

(6)数控分频发声模块std_logic_vector(7 dow nto 0) 禾口cat : out std_logic_vector(5 downto 0) 来控制数码管从实验板上面输入的时钟是50MHz的,必须经过分频后由clk_out输出,驱动蜂鸣器发声。

Clk_out的输出频率就对应着音符的音调。

分频系数由来自分频预置值模块的tone :out integer range 0 to 2000000) 。

由于直接从数控分频器中出来的输出信号是脉宽极窄的脉冲式信号。

为了利用驱动蜂鸣器,需要再增加一个进程,多波形进行整理,均衡占空比三、仿真波形及波形分析1. 数码管显示模块仿真波形波形分析:不同的yin,和highlow 组合,数码管显示不同的字符。

duan[0]~duan[7] 对应着数码管的a段到h段,cat[0]~cat[5] 控制不同的数码管2.点阵显示模块仿真波形波形分析:不同的yin输入,点阵的col和row会有不同的波形,利用clk_in的上升沿来动态扫描点阵。

从而得显示出指定的图形。

3.自动播放模块仿真波形波形分析:当auto 置1 , clear 置0, yin_out 输出储存在程序里面的曲子音符,这时候相当于自动播放。

当auto 置0, clear 置0,yin_out 输出从BTN1~BTN7 读取的手动输入的 信号,这时候相当于手动演奏。

4.分频预置值产生模块仿真波形模块的分频预置值四、源程序1.分频模块源程序library ieee;use ieee.std 」o gic_1164.all; use ieee.std_logic_ un sig ned.all;en tity div0 isport(clk_ in :in std_logic; clk_tmp :out std_logic);end;architecture b of div0 issig nal clk : std_logic;Mascer irre Bar: 1 SI 7E ns,Porker17.5- us Inter /a:17.4S s Start:波形分析:输入不同的高低音 highlow,和音符yin ,输出不同的tone 。

而tone 将作为发声--输入时钟 --输出时钟beginpO:process(clk_ in)variable ent : in teger range 0 to 2499; beginif (clk_i n'event and clk_in='1') the n if cn t=2499 the ncnt:=0;clk<= not clk;elsecn t:=c nt+1;来时cnt加1end if;end if;end process p0;clk_tmp<=clk;end b ;2. 数码管显示源程序library ieee;use ieee.std」o gic_1164.all;use ieee.std_logic_ un sig ned.all; --分频系数为2499--每个输入时钟上升沿到en tity shuma isport(clk_ in : in std_logic; --以分频的时钟输入yin : in std_logic_vector(6 dow nto 0); --输入音符highlow :in std_logic_vector(1 dow nto 0); --输入高低音auto in std_logic; --自动播放auto1 :in std」o gic; --自动播放1dua n : out std_logic_vector(7 dow nto 0);cat : out std_logic_vector(5 dow nto 0));en d;architecture b of shuma issig nal dua nt : std_logic_vector(7 dow nto 0);sig nal catt : std_logic_vector(5 dow nto 0);beginp1: process(clk_i n,yin ,highlow,auto,auto1)beginif auto ='1' then--显示“ 8”表示自catt<="111101";dua nt<="00111111";动播放elsif autol ='1' thencatt<="111101";duant<="01111111"; --显示“ 0 ” 表示试音elsif auto ='0' the nif(clk_in ='0') the ncase yin iswhen "0000001" => catt<="111110";duant<="00000110";--显示“1 ”when "0000010" => catt<="111110";duant<="01011011";--显示“ 2 ”whe n "0000100" => catt<="111110";dua nt<="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”when others=> catt<="111111";duant<="00000000";end case;elsif (clk_in ='1') the ncase highlow iswhen "10" => catt<="111101";duant<="01110100";--显示when "01" => catt<="111101";duant<="00111000";“H ”when others=> catt<="111111";duant<="00000000";end case;end if;end if;end process p1;cat<= catt;dua n<= dua nt;end b;3. 点阵显示源程序library ieee;use ieee.std」o gic_1164.all;use ieee.std_logic_ un sig ned.all;en tity dia nzhe n isport(clk_ in : in std_logic;yin : in std_logic_vector(6 dow nto 0);row : out std_logic_vector(7 dow nto0); --点阵行向--显示--时钟输入--输入音符col : out std_logic_vector(7 dow nto 0) --点阵列向量);en d;architecture b of dia nzhe n issig nal count : in teger range 0 to 6;sig nal rowt : std_logic_vector(7 dow nto 0);sig nal colt : std_logic_vector(7 dow nto 0);beginp1:process(clk_ in)beginif (clk_i n'event and clk_in='1') the nif count = 6 the ncoun t<=0;elsecount<=count+1; --用count 来记数end if;end if;elsif (yin = "0000010") the nend process p1;p2: process(co un t,y in) beginif (yin = "0000001") thencase count is--点阵显示,表示" 1 ”音符when 0=> rowt<="11111110";colt<="01111110"; when 1=> rowt<="11111101";colt<="01111110"; when 2=> rowt<="11111011";colt<="01111100"; when 3=> rowt<="11110111";colt<="01111000"; when 4=> rowt<="11101111";colt<="01110000"; when 5=> rowt<="11011111";colt<="01100000"; when 6=> rowt<="10111111";colt<="01000000"; when others=> rowt<="11111111";colt<="00000000"; end case;--点阵显示,表示"2 ”音case count iswhen 0=> rowt<="11111110";colt<="01111101";when 1=> rowt<="11111101";colt<="01111100";when 2=> rowt<="11111011";colt<="01111100";when 3=> rowt<="11110111";colt<="01111000";when 4=> rowt<="11101111";colt<="01110000";when 5=> rowt<="11011111";colt<="01100000";when 6=> rowt<="10111111";colt<="01000000";when others=> rowt<="11111111";colt<="00000000";end case;elsif (yin = "0000100") thencase count is --点阵显示,表示" 3”音符when 0=> rowt<="11111110";colt<="01111011";when 1=> rowt<="11111101";colt<="01111010";when 2=> rowt<="11111011";colt<="01111000";when 3=> rowt<="11110111";colt<="01111000";when 4=> rowt<="11101111";colt<="01110000";when 5=> rowt<="11011111";colt<="01100000";when 6=> rowt<="10111111";colt<="01000000";when others=> rowt<="11111111";colt<="00000000";end case;elsif (yin = "0001000") thencase count is --点阵显示,表示" 4”音符when 0=> rowt<="11111110";colt<="01110111";when 1=> rowt<="11111101";colt<="01110110";when 2=> rowt<="11111011";colt<="01110100";when 3=> rowt<="11110111";colt<="01110000";when 4=> rowt<="11101111";colt<="01110000";when 5=> rowt<="11011111";colt<="01100000";when 6=> rowt<="10111111";colt<="01000000";when others=> rowt<="11111111";colt<="00000000";end case;elsif (yin = "0010000") the ncase count is --点阵显示,表示" 5”音符when 0=> rowt<="11111110";colt<="01101111";when 1=> rowt<="11111101";colt<="01101110";when 2=> rowt<="11111011";colt<="01101100";when 3=> rowt<="11110111";colt<="01101000";when 4=> rowt<="11101111";colt<="01100000";when 5=> rowt<="11011111";colt<="01100000";when 6=> rowt<="10111111";colt<="01000000"; --点阵显示,表示"7 ”音when 0=> rowt<="11111110";colt<="00111111"; when others=> rowt<="11111111";colt<="00000000"; end case;elsif (yin = "0100000") the ncase count is--点阵显示,表示" 6”音符when 0=> rowt<="11111110";colt<="01011111"; when 1=> rowt<="11111101";colt<="01011110"; when 2=> rowt<="11111011";colt<="01011100"; when 3=> rowt<="11110111";colt<="01011000"; when 4=> rowt<="11101111";colt<="01010000"; when 5=> rowt<="11011111";colt<="01000000"; when 6=> rowt<="10111111";colt<="01000000"; when others=> rowt<="11111111";colt<="00000000"; end case;elsif (yin = "1000000") thencase count is符when 1=> rowt<="11111101";colt<="00111110";when 2=> rowt<="11111011";colt<="00111100";when 3=> rowt<="11110111";colt<="00111000";when 4=> rowt<="11101111";colt<="00110000";when 5=> rowt<="11011111";colt<="00100000";when 6=> rowt<="10111111";colt<="00000000";when others=> rowt<="11111111";colt<="00000000";end case;elsecase count is --点阵显示,表示不输入音符when 0=> rowt<="11111110";colt<="01111111";when 1=> rowt<="11111101";colt<="01111110";when 2=> rowt<="11111011";colt<="01111100";when 3=> rowt<="11110111";colt<="01111000";when 4=> rowt<="11101111";colt<="01110000";when 5=> rowt<="11011111";colt<="01100000";when 6=> rowt<="10111111";colt<="01000000";when others=> rowt<="11111111";colt<="00000000";end case;end if;end process p2;row<= rowt;col<= colt;end b;4. 选择音符及自动播放源程序library ieee;use ieee.std」o gic_1164.all;use ieee.std_logic_ un sig ned.all;en tity auto isport( clk_in :in std_logic; --输入时钟auto :in std_logic; --自动播放auto1 :in std_logic; --试音播放clear :in std_logic; --复位yin」n :in std」o gic_vector(6 dow nto 0); --输入音符yin _out :out std」o gic_vector(6 dow nto 0)); --输出音符end auto;architecture a of auto issig nal count : in teger range 0 to 35;sig nal n: in teger range 0 to 6;n <=n+1;end if;sig nal yin : std_logic_vector(6 dow nto 0); beginp1:process(clk_i n, clear):integer range 0 to 63000000;beginif clear ='1' the ncoun t<=0;elsif (clk_i n'eve nt and clk_i n='1') the n if (i=20000000) theni:=0; if count =15the n--自动播放cou nt 记数elseelsecount <=count+1; end if; if n =6the nn <=0; else--试音播放n 记数variable i count <=0;i:=i+1;end if;end if;end process p1;p2:process(co un t,auto, yin_in, clear)beginif clear='1' the nyin<="0000000"; --音符清零elseif auto ='1' then --自动播放歌曲case count iswhe n 1 => yi*="0000100"; --3when 2 => yin<="1000000"; --7when 3 => yi*="0000100"; --3when 4 => yi*="0100000"; --6when 5 => yi*="0010000"; --5when 6=> yin<="0100000"; --6when 7 => yi*="0000001"; --1when 8 => yi*="0000100"; --3when 9 => yi*="0010000"; --5when 10 => yi*="0000100"; --3end if;whe n 11 => yi n<="0000100"; --3 when 12 => yi*="0001000"; --4 whe n 13 => yi n<="0000100"; --2 when 14 => yi*="0001000"; --4 whe n others => yi*="0000000";end case;elsif auto1 ='1' the ncase n is --试音播放when 0 => yi*="0000001"; --1whe n 1 => yi*="0000010"; --2when 2 => yi*="0000100"; --3when 3 => yi*="0001000"; --4when 4 => yi*="0010000"; --5when 5 => yi*="0100000"; --6when 6 => yin<="1000000"; --7whe n others => yi*="0000000";end case;elseyin<=yi n_in; --动手演奏end if;end process p2;yin _out<=yin;end a;5. 预置分频系数模块源代码library ieee;use ieee.std _lo gic_1164.all; use ieee.std_logic_ un sig ned.all;en tity selet one is:in std_logic_vector(1 dow nto 0); yin:in std_logic_vector(6 dow nto 0);tone :out in teger range 0 to 2000000);end selet one;architecture a of selet one issignal tone0 :integer range 0 to 2000000; begin process(highlow, yin) beginif highlow ="00" thenport( highlow--高低音 --要演奏的音符--预置分频系数end case;when "0000001"=〉tone0<=523; whe n "0000010"=〉ton e0<=587; whe n "0000100"=〉ton e0<=659; when "0001000"=〉ton e0<=698; when "0010000"=> ton e0<=784; when "0100000"=> ton e0<=880; when "1000000"=> ton e0<=988; when others => ton e0<=2000000;end case;elsif highlow ="10" the ncase yin iswhen "0000001"=> ton e0<=1045; when "0000010"=> ton e0<=1174; when "0000100"=> ton e0<=1318; when "0001000"=> ton e0<=1396; when "0010000"=> ton e0<=1568; when "0100000"=> ton e0<=1760; whe n "1000000"=> ton e0<=1975; when others => ton e0<=2000000;case yin is--中音部分--高音部分elsif highlow ="01" then--低音部分case yin iswhen "0000001"=〉tone0<=261;when "0000010"=〉ton e0<=293;when "0000100"=〉ton e0<=329;when "0001000"=〉ton e0<=349;whe n "0010000"=> ton e0<=392;when "0100000"=> ton e0<=440;when "1000000"=> ton e0<=494;when others =〉tone0<=2000000; end case;end if;end process ;tone <=t on e0;end a;6. 分频发音模块源代码library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_ un sig ned.all;en tity divisport(clk_i n : in std」ogic;--输入时钟tone : in in teger range 0 to 2000000; --预置频率clk_out : out std_logic); --输出时钟end div;architecture a of div issig nal clk_tmp0 : std_logic;sig nal clk_tmp1: std_logic;beginp0:process(clk_ in, tone)variable cnt : integer range 0 to 49999999;beginif (clk_ in'event and clk_in='1') thenif cnt <12999999/t onethen--分频系数else cn t:=cnt+1;clk_tmp0<='1'; cnt:=0;clk_tmpO<='O:end if;end if;end process p0;p1:process(clk_tmp0)variable count :std_logic;beginif(clk_tmpO'eve nt and clk_tmp0='1') then coun t:=not count;if count ='1' the n--输出平稳的波形clk_tmp1 <='1';elseclk_tmp1 <='0';end if;end if;end process p1;clk_out<=clk_tmp1;end a;7. 电子琴顶层设计library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_ un sig ned.all;en tity dia nzq isport(clk in std_logic; --时钟输入yin : in std_logic_vector(6 dow nto 0); --音符输入highlow: in std_logic_vector(1 dow nto 0); --高低音输入auto_i n: in std_logic; --自动播放auto1 in std_logic; --试音播放clear : in std_logic; --复位clk_out: out std_logic; --输出时钟row : out std_logic_vector(7 dow nto 0); --点阵显示col : out std_logic_vector(7 dow nto 0); --点阵显示dua n out std_logic_vector(7 dow nto 0); --数码管显示cat : out std_logic_vector(5 dow nto 0)); --数码管显示end dia nzq;architecture a of dia nzq iscomp onent div0 is --分频模块port(clk_i n : in std_logic;clk_tmp : out std_logic);end comp onent;comp onent dia nzhe n is --点阵显示模块port(clk_i n in std_logic;yin : in std_logic_vector(6 dow nto 0);row : out std_logic_vector(7 dow nto 0);col :);out std_logic_vector(7 dow nto 0)丿;end comp onent;comp onent shuma is块port(clk_i n in std_logic;yin : in std_logic_vector(6 dow nto 0);highlow : in std_logic_vector(1 dow nto 0);auto:in std_logic;auto1 in std_logic;dua nout std_logic_vector(7 dow nto 0);cat : out std_logic_vector(5 dow nto 0));--数码管显示模end comp onent;end comp onent;comp onent selet one is 模块port( highlow:in std 」o gic_vector(1 dow nto 0);yin : in std_logic_vector(6 dow nto 0); tone : out in tegerrange 0 to 2000000); end comp onent;comp onent div isport(clk_i n:in std_logic;tone : in in teger range 0 to 2000000; clk_out :out std_logic);comp onent auto isport( clk_in :in std_logic;auto in std_logic; auto1 in std_logic;yin 」n : in std_logic_vector(6 dow nto 0); clear in std_logic;yin _outout std_logic_vector(6 dow nto0))--自动播放模块--预置分频系数--分频发音模块end comp onent;sig nal yin_tmp std_logic_vector(6 dow nto0);sig nal ton e_tmp : in teger range 0 to 2000000;clk_tmpstd_logic;sig nal:beginu1: auto port map(clk_ in=>clk,auto=>auto_ in,yin_in=>yin,yin _out=> yin _tmp,clear=>clear,auto1=>auto1);u2: selet one port map(highlow=>highlow, yin=>yin _tmp,t on e=>t on e_tmp);u3: shuma port map(dua n=>dua n,cat=>cat,y in=>yin _tmp,clk_ in=>clk_tmp,highlow=>highlow,aut o=>auto_ in ,auto1=>auto1);u4: dia nzhe n port map(row=>row,col=>col,y in=>yin _tmp,clk_ in=>clk_tmp);u5: div port map (clk_i n=>clk,t on e=>t on e_tmp,clk_out=>clk_out);u6: div0 port map (clk_ in=>clk,clk_tmp=>clk_tmp);end a;五、功能说明初始状态,8 X8点阵显示“ 1 2 3 4 5 6 7 ”七个音符构成的电子琴键盘,其中点阵的第一列用一个LED点亮表示音符“ 1 ”,第二列用二个LED点亮表示音符“ 2 ”,依此类推,用BTN1〜BTN7七个按键模拟电子琴手动演奏时的“ 1 2 3 4 5 6 7 ”七个音符。

相关主题