当前位置:文档之家› 数电实验报告

数电实验报告

北京邮电大学数字电路与逻辑设计实验简易电子琴演奏器班级:学号:姓名:一.设计课题的任务要求题目五简易电子琴演奏器原理概述:根据声乐知识,产生音乐的两个因素是音乐频率的持续时间,音乐的十二平均率规定,每两个八音度之间的频率相差一倍,在两个八音度之间,又可分为12个半音。

每两个半音的频率比为4。

另外,音名A(乐谱中的低音6)的频率为440HZ,音名B到C之间,E到F之间为半音,其余为全音。

由此可以计算出乐谱中从低音1到高音1之间每个音名的频率如下表所示。

基本要求:1、用8×8点阵显示“1 2 3 4 5 6 7”七个音符构成的电子琴键盘。

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

图1 点阵显示的电子琴键盘2、用BTN1~BTN7七个按键模拟电子琴手动演奏时的“1 2 3 4 5 6 7”七个音符。

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

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

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

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

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

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

二、系统设计(包括设计思路、总体框图、分块设计)设计思路电子琴的设计主要包括了显示与发声部分,发声部分主要分为三个不同的音阶,每个音阶包括了七个音,发生部分可以通过对50M晶振的分频,通过改变分频系数,得到响应频率的时钟脉冲,以这个脉冲控制蜂鸣器发出声音;显示部分则包括了数码管的音阶显示与点阵的琴键显示。

数码管可以动态显示出音阶与当前音符,点阵则模拟显示琴键,动态显示实现了一个三角阵,并对应到音符琴键,这两个显示模块可以通过动态显示来实现显示显示不同的内容,配合按键可以实现基本功能。

不同的音阶可以通过相应拨码开关的选择来调节,至于显示的复位,则不需要专门设置键位来完成,因为每个转台结束后就会自动转入等待状态。

对于音调,乐曲的12平均率规定:每2个八度音之间的频率相差1倍。

在2个八度音之间,又可分为12个半音,每2个半音的频率比为12√2。

另外,音符A 的频率为440Hz,音符B到C之间、E到F之间为半音,其余为全音。

由此可以计算出简谱中从低音1到高音1之间每个音符的频率。

而对于节拍,如果将一拍的长度定为1秒,则1/4拍的时间为1/4秒,为其提供一个4Hz的时钟频率即可产生出1/4拍的效果了。

若需要半拍,只需将该音符记录两次就可以了。

总体框图3、分块设计程序使用了分块思想,一共两个文件,包括发声与显示部分以及自动播放程序。

发声部分:【分频器】由50M晶振,通过事先得知的频率,得到分频系数,可以控制系数得到不同的发音。

由于存在三个音阶,所以设置了三组分频系数。

【蜂鸣器】由分频后的时钟频率控制,在触发按键后由蜂鸣器发出声音。

【音阶选择】设置三个不同的拨码开关,分别控制高中低音的选择,拨动相应开关,进入相应的状态。

显示部分:【扫描分频】用一个较高频率的时钟控制对数码管选通的扫描以及对于点阵的行扫描。

【译码器】同多一个八位的二进制数,完成对数字音符及字幕音阶的编码,点阵的编码较为简单,在行扫描的状态下,控制每列显示的内容。

【点阵】动态扫描显示出基本要求中的状态,从左至右分别在每一列点亮一个,两个至多个。

【数码管】使用了两个数码管,动态扫描显示出了音符与音阶。

输入部分:【键盘】键盘在两部分中都有涉及,控制相应点阵灭掉以及蜂鸣器发声。

自动播放部分主要涉及一个音符存储的文件,但在这部分由于我使用了一个整数数组对音符编码。

所以又在发声与显示部分重复了部分代码。

三、仿真波形及波形分析仿真波形存在一定问题,首先是毛刺,不同进程间最容易出现类似问题,对于琴键的输入控制的不是很好,因为程序设定为在同一时刻只能有一个音符有效,如果在同一个上升沿到来时,存在多个琴键输入,那么就不存在有效输出,所以蜂鸣器的电平存在大段为零的情况,点阵输入采用了行扫描的情况,所以行的显示是分段出现低电平,且一段时间内只选通一位,所以为7个‘1’,1个‘0’。

列显示基本正常。

数码管情况类似。

四、源程序LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_UNSIGNED.ALL;ENTITY music ISPORT (CAT: OUT STD_LOGIC_VECTOR(5 DOWNTO 0); --六个数码管DIGITAL:OUT STD_LOGIC_VECTOR(6 DOWNTO 0); --七小段数码管CLK: IN STD_LOGIC;BTN: IN STD_LOGIC_VECTOR(7 DOWNTO 0); --8个按键LED_R: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --点阵横着的8个管教LED_C: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --点阵竖着的8个管脚BEEP: OUT STD_LOGIC; --蜂鸣器KEY_SW:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --选择低、中、高音AUTO_SW: IN STD_LOGIC --自动播放开关);END music;ARCHITECTURE music_body OF music ISSIGNAL TEMP_CAT: STD_LOGIC_VECTOR(5 DOWNTO 0); --六个数码管SIGNAL TEMP_DIGITAL:STD_LOGIC_VECTOR(6 DOWNTO 0); --七小段数码管SIGNAL TEMP_R: STD_LOGIC_VECTOR(7 DOWNTO 0); --点阵横列SIGNAL TEMP_C:STD_LOGIC_VECTOR(7 DOWNTO 0); --点阵数列SIGNAL LED_CLK:STD_LOGIC;SIGNAL LED_COUNT:INTEGER RANGE 0 TO 100; --点阵分频时用来计数SIGNAL MUSIC_COUNT:INTEGER RANGE 0 TO 200000; --音符分频时用来计数SIGNAL MUSIC_FRE:INTEGER RANGE 0 TO 200000; --音符分频比SIGNAL AUTO_COUNT1:INTEGER RANGE 0 TO 12500000; --50M除以12500000就等于4HZSIGNAL AUTO_COUNT2:INTEGER RANGE 0 TO 100; --AUTO_COUNT1加到12500000 AUTO_COUNT2就加1,相当于一个AUTO_COUNT2就等于0.25sSIGNAL TEMP_KEY_SW:STD_LOGIC_VECTOR(1 DOWNTO 0); --自动播放开关的临时变量SIGNAL TEMP_KEY_AUTO: STD_LOGIC_VECTOR(7 DOWNTO 0); --按键临时变量,用于自动播放SIGNAL TEMP_KEY: STD_LOGIC_VECTOR(7 DOWNTO 0); --按键临时变量,用于手动播放,即BTN的输入BEGINP1:PROCESS(BTN,KEY_SW) --一直把BTN的值付给临时变量TEAM_KEYBEGINTEMP_KEY <=BTN;TEMP_KEY_SW <=KEY_SW;END PROCESS P1;P2:PROCESS(CLK,MUSIC_FRE) --对应音符分频BEGINIF CLK'EVENT AND CLK='1' THENIF MUSIC_COUNT=MUSIC_FRE THEN --对于每个音符对应不同的分频比MUSIC_FREMUSIC_COUNT<=0;ELSEMUSIC_COUNT<=MUSIC_COUNT+1;END IF;END IF;END PROCESS P2;P3:PROCESS(MUSIC_COUNT,MUSIC_FRE) --经测试需要再把频率二分频一下,实验书上的频率不准,当达到此频率时蜂鸣器响BEGINIF MUSIC_COUNT<= MUSIC_FRE/2 THENBEEP<='0';ELSEBEEP<='1';END IF;END PROCESS P3;P4:PROCESS (CLK) --点阵分频进程,点阵扫描频率为250000HZ BEGINIF(CLK'EVENT AND CLK = '1') THENIF LED_COUNT=100 THENLED_COUNT<=0;LED_CLK<= NOT LED_CLK;ELSELED_COUNT <= LED_COUNT+1;END IF;END IF;END PROCESS P4;P5:PROCESS(LED_CLK) --点阵循环扫描BEGINIF LED_CLK'EVENT AND LED_CLK ='1' THENCASE TEMP_C ISWHEN "00000001" => TEMP_C <= "00000010";WHEN "00000010" => TEMP_C <= "00000100";WHEN "00000100" => TEMP_C <= "00001000";WHEN "00001000" => TEMP_C <= "00010000";WHEN "00010000" => TEMP_C <= "00100000";WHEN "00100000" => TEMP_C <= "01000000";WHEN OTHERS => TEMP_C <= "00000001";END CASE;END IF;END PROCESS P5;P6:PROCESS(TEMP_C,TEMP_KEY,TEMP_KEY_AUTO,TEMP_KEY_SW) --对不同按键及高低音的不同的反应VARIABLE TEMP_FRE:INTEGER RANGE 0 TO 200000;BEGINCASE TEMP_KEY_SW IS --切换低、中、高音WHEN "00" => MUSIC_FRE <= TEMP_FRE*2; --低WHEN "10" => MUSIC_FRE <= TEMP_FRE/2; --高WHEN OTHERS => MUSIC_FRE <=TEMP_FRE; --中END CASE;CASE TEMP_C ISWHEN "00000001" => TEMP_R <= "11111110"; --点阵第一列亮WHEN "00000010" => TEMP_R <= "11111100"; --点阵第二列亮WHEN "00000100" => TEMP_R <= "11111000"; --点阵第三列亮WHEN "00001000" => TEMP_R <= "11110000"; --点阵第四列亮WHEN "00010000" => TEMP_R <= "11100000"; --点阵第五列亮WHEN "00100000" => TEMP_R <= "11000000"; --点阵第六列亮WHEN OTHERS => TEMP_R <= "10000000"; --点阵第七列亮END CASE;IF (AUTO_SW='1') THEN -- 这个if语句块和下面一个语句块,一个用于自动播放,一个用于手动CASE TEMP_KEY_AUTO ISWHEN "00000010" =>TEMP_FRE:=95557;IF TEMP_C="00000001" THEN TEMP_R<="11111111"; END IF;WHEN "00000100" =>TEMP_FRE:=85131;IF TEMP_C="00000010" THEN TEMP_R<="11111111"; END IF;WHEN "00001000" =>TEMP_FRE:=75844;IF TEMP_C="00000100" THEN TEMP_R<="11111111"; END IF;WHEN "00010000" =>TEMP_FRE:=71586;IF TEMP_C="00001000" THEN TEMP_R<="11111111"; END IF;WHEN "00100000" =>TEMP_FRE:=63776;IF TEMP_C="00010000" THEN TEMP_R<="11111111"; END IF;WHEN "01000000" =>TEMP_FRE:=56818;IF TEMP_C="00100000" THEN TEMP_R<="11111111"; END IF;WHEN "10000000" =>TEMP_FRE:=50620;IF TEMP_C="01000000" THEN TEMP_R<="11111111"; END IF;WHEN OTHERS =>TEMP_FRE:=0;END CASE ;END IF;IF (AUTO_SW='0') THENCASE TEMP_KEY ISWHEN "00000010" =>TEMP_FRE:=95557;IF TEMP_C="00000001" THEN TEMP_R<="11111111"; END IF; --当按BTN1时跳过第一列,及第一列不亮WHEN "00000100" =>TEMP_FRE:=85131;IF TEMP_C="00000010" THEN TEMP_R<="11111111"; END IF; --当按BTN1时跳过第二列,及第二列不亮WHEN "00001000" =>TEMP_FRE:=75844;IF TEMP_C="00000100" THENTEMP_R<="11111111"; END IF; --当按BTN1时跳过第三列,及第三列不亮WHEN "00010000" =>TEMP_FRE:=71586;IF TEMP_C="00001000" THEN TEMP_R<="11111111"; END IF; --当按BTN1时跳过第四列,及第四列不亮WHEN "00100000" =>TEMP_FRE:=63776;IF TEMP_C="00010000" THEN TEMP_R<="11111111"; END IF; --当按BTN1时跳过第五列,及第五列不亮WHEN "01000000" =>TEMP_FRE:=56818;IF TEMP_C="00100000" THEN TEMP_R<="11111111"; END IF; --当按BTN1时跳过第六列,及第六列不亮WHEN "10000000" =>TEMP_FRE:=50620;IF TEMP_C="01000000" THEN TEMP_R<="11111111"; END IF; --当按BTN1时跳过第七列,及第七列不亮WHEN OTHERS =>TEMP_FRE:=0;--当没按键时全部都不亮END CASE ;END IF;END PROCESS P6;P7:PROCESS(TEMP_KEY,KEY_SW) --数码管显示进程BEGINCASE TEMP_KEY_SW ISWHEN "00" => TEMP_CAT <= "111110"; --低音CAT0接通WHEN "10" => TEMP_CAT <= "111000"; --高音CAT0,CAT1,CAT2都接通WHEN OTHERS => TEMP_CAT <= "111100"; --中音CAT0,CAT1接通END CASE;CASE TEMP_KEY ISWHEN "00000000" => TEMP_DIGITAL <= "0000000"; --不按键不显示WHEN "00000001" => TEMP_DIGITAL <= "0000000";WHEN "00000010" => TEMP_DIGITAL <= "0110000"; --按BTN1键显示1WHEN "00000100" => TEMP_DIGITAL <= "1101101"; --按BTN2键显示2WHEN "00001000" => TEMP_DIGITAL <= "1111001"; --按BTN3键显示3WHEN "00010000" => TEMP_DIGITAL <= "0110011"; --按BTN4键显示4WHEN "00100000" => TEMP_DIGITAL <= "1011011"; --按BTN5键显示5WHEN "01000000" => TEMP_DIGITAL <= "1011111"; --按BTN6键显示6WHEN OTHERS => TEMP_DIGITAL <= "1110000"; --按BTN7键显示7 END CASE;END PROCESS P7;P8:PROCESS (CLK,AUTO_SW) --自动播放分频BEGINIF(CLK'EVENT AND CLK = '1') THENIF AUTO_COUNT1=12500000 THENAUTO_COUNT1<=0;AUTO_COUNT2 <= AUTO_COUNT2+1;ELSEAUTO_COUNT1 <= AUTO_COUNT1+1;END IF;IF AUTO_COUNT2=60 THENAUTO_COUNT2 <= 0;END IF;END IF;IF (AUTO_SW='0') THEN --只要是手动播放就把AUTO_COUNT2赋为0AUTO_COUNT2 <= 0;END IF;END PROCESS P8;P9:PROCESS(AUTO_SW,AUTO_COUNT2)BEGINIF (AUTO_SW='1') THENCASE AUTO_COUNT2 ISWHEN 1 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 2 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 3 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 4 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 5 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 6 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 7 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 8 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 9 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 10 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 11 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 12 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 13 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 14 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 15 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 16 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 17 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 18 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 19 =>TEMP_KEY_AUTO <= "00010000"; --yinfu 4WHEN 20 =>TEMP_KEY_AUTO <= "00010000"; --yinfu 4WHEN 21 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 22 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 23 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 24 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 25 =>TEMP_KEY_AUTO <= "00010000"; --yinfu 4WHEN 26 =>TEMP_KEY_AUTO <= "00010000"; --yinfu 4WHEN 27 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 28 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 29 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 30 =>TEMP_KEY_AUTO <= "01000000"; --yinfu 6WHEN 31 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 32 =>TEMP_KEY_AUTO <= "00010000"; --yinfu 4WHEN 33 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 34 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 35 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 36 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 37 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 38 =>TEMP_KEY_AUTO <= "01000000"; --yinfu 6WHEN 39 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 40 =>TEMP_KEY_AUTO <= "00010000"; --yinfu 4WHEN 41 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 42 =>TEMP_KEY_AUTO <= "00001000"; --yinfu 3WHEN 43 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 44 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 45 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 46 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 47 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 48 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 49 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 50 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 51 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 52 =>TEMP_KEY_AUTO <= "00000100"; --yinfu 2WHEN 53 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 54 =>TEMP_KEY_AUTO <= "00100000"; --yinfu 5WHEN 55 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN 56 =>TEMP_KEY_AUTO <= "00000010"; --yinfu 1WHEN OTHERS =>TEMP_KEY_AUTO <= "00000000";END CASE;END IF;END PROCESS P9;LED_R <= TEMP_R; --最后将临时变量赋给输出口LED_C <= TEMP_C;CAT <= TEMP_CAT;DIGITAL <= TEMP_DIGITAL;END music_body;五、功能说明实现了全部的基本功能,包括发声,键盘显示。

相关主题