资源描述
电子琴
课程名称:
学院(系): 电子信息工程
专 业: 电子信息工程
班 级:
学生姓名:
学 号:
完成日期:
成 绩:
1 设计要求
(1)有两种模式可供选择,分别为弹奏模式和自动演奏模式。
(2)在弹奏模式下,分别按下实验箱上七个键,扬声器分别发出中音Do, Re, Mi, Fa, Sol, La, Ti
(3)在自动演奏模式下,自动循环播放歌曲Jingle Bells。
(4) 由三位数码管分别显示高、中、低音的音符。
2 设计分析及系统方案设计
a. 设计分析:
电子琴的设计包括四个模块:弹奏模块keyplay、自动演奏模块autoplay、查表及显示模块table和分频模块fenpin。
弹奏模块keyplay根据按键动作key产生指示音调的index_key
自动演奏模块autoplay接收1024Hz的时钟信号,输出index_auto
查表及显示模块table根据按键button选择采用index_key或ndex_auto来查分频系数表,输出分频系数tone。同时将音调对应的BCD码code0(低音)、code1(中音)、code2(高音)分别输出给三个数码管。
分频模块fenpin接收tabled输出的分频系数 tone,并据此分频,将对应频率的信号buzz输出给扬声器供其发声。
b. 系统设计方案:
顶层设计:
输入:6MHz时钟clk、1024Hz时钟、按键key[6..0]、按键button
输出:spkout给扬声器
弹奏模块keyplay:
将输入key[6..0]编码为index_key[4..0]。index_key[4..0]的高两位表示高、中、低音,00表示低音,01表示中音、10表示高音。由于按键数目有限,只能弹出中音。index_key[4..0]低三位表示音调,001表示do,010表示re,以此类推,000表示不发音。
自动演奏模块autoplay:
把1024Hz的输入时钟分频为16Hz,作为节拍。将要自动演奏的歌曲预先写为index_auto的格式(index_auto格式与index_key格式相同)。以16Hz 的频率将index_auto输出。
查表及显示模块table:
(1)输入按键button用于选择模式。由于是琴键式,不能根据button本身的值来选择模式。故加一个内部信号choice,button每来一个上升沿,choice翻转一次。Choice为1则把index_auto赋给内部信号index,否则把index_key 赋给它。
(2) 用index来查表,获得分频系数tone,输出。
(3)同时根据index获得BCD码表示的高、中、低音的音调,输出给数码管。
分频模块fenpin:
输入分频系数 tone。(1)设置内部信号i用于计数,clk_data作为分频结果。,每次clk上升沿检测i是否等于tone,相等则把i清零,并使clk_data翻转,否则i自增1。(2)把clk_data赋给输出信号buzz,由buzz驱动扬声器发声。
设计框图:
buzz
code0 code1 code2
tone
fenpin
button
Index_auto
Index_key
table
Clk2
autoplay
key
Keyplay
3系统以及模块硬件电路设计
译码器
译码器
译码器
PIO27-24 PIO23-20 PIO23-20
F P G A最小系统
Clk0
Clk5
PIO7 PIO6 PIO5 PIO4 PIO3 PIO2 PIO1 PIO0 spk
6MHz
1024Hz
Key0
Key1
Key2
Key3
Key4
Key5
Key6
Button
试验箱使用的是模式3的电路结构。
1. 按键PIO7是模式选择按键button,每按下一次改变一次模式
2. 按键PIO6-0用于弹奏,在弹奏模式下,被按下时分别发出中音Do, Re, Mi, Fa, Sol, La, Ti。
3. Clk0用于分频以供扬声器发声
4. Clk5用于控制自动演奏节拍
5. 三个数码管用于显示高、中、低音音调
下载时选择的开发系统模式以及管脚定义
表1 GW48-CK开发系统工作模式:
接口
名称
类型
(输入/输出)
结构图上
的信号名
引脚号
说明
clk
INPUT
CLK0
2
供分频发声
Clk2
INPUT
CLK5
83
供分频获得节拍
Key
INPUT
PIO6-0
11-5
按键弹奏
Button
INPUT
PIO7
16
模式选择
Code0top
OUTPUT
PIO19-16
30-27
低音显示
Code1top
OUTPUT
PIO23-20
38-35
中音显示
Code2top
OUTPUT
PIO27-24
49-47,39
高音显示
Spkout
OUTPUT
SPEAKER
3
发声
4 系统的VHDL设计
顶层程序:top.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity top is
port ( clk :in std_logic;
clk2:in std_logic;
key:in std_logic_vector(6 downto 0);
button:in std_logic;
spkout :out std_logic;
code0top:out std_logic_vector(3 downto 0);
code1top:out std_logic_vector(3 downto 0);
code2top:out std_logic_vector(3 downto 0));
end top;
architecture behave of top is
component autoplay
port ( clk2: in std_logic;
index_auto : out std_logic_vector(4 downto 0));
end component;
component fenpin
port(clk:in std_logic;
tone:in integer range 0 to 8190;
buzz:out std_logic);
end component;
component table
port(index_auto:in std_logic_vector(4 downto 0);
index_key:in std_logic_vector(4 downto 0);
button :in std_logic;
tone:out integer range 0 to 8190;
code0:out std_logic_vector(3 downto 0);
code1:out std_logic_vector(3 downto 0);
code2:out std_logic_vector(3 downto 0)
);
end component;
component keyplay
port(key:in std_logic_vector(6 downto 0);
index_key:out std_logic_vector(4 downto 0)
);
end component;
signal index_auto_top :std_logic_vector(4 downto 0);
signal index_key_top :std_logic_vector(4 downto 0);
signal tone_top :integer range 0 to 8190;
begin
u1:autoplay port map(clk2=>clk2,index_auto=>index_auto_top);
u2:fenpin port map(clk=>clk,tone=>tone_top,buzz=>spkout);
u3:table port map(index_auto=>index_auto_top,index_key=>index_key_top,tone=>tone_top,button=>button,code0=>code0top,code1=>code1top,code2=>code2top);
u4:keyplay port map(key=>key,index_key=>index_key_top);
end behave;
按键弹奏模块:keyplay.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith;
use ieee.std_logic_unsigned.all;
entity keyplay is
port(key:in std_logic_vector(6 downto 0);
index_key:out std_logic_vector(4 downto 0)
);
end;
architecture behave of keyplay is
begin
process(key)
begin
case key is
when "0000001"=> index_key<="01001";--按键从右到左依次表示do,re,mi,fa,sol,la,ti
when "0000010"=> index_key<="01010";
when "0000100"=> index_key<="01011";
when "0001000"=> index_key<="01100";
when "0010000"=> index_key<="01101";
when "0100000"=> index_key<="01110";
when "1000000"=> index_key<="01111";
when others => index_key<="00000";
end case;
end process ;
end behave;
自动演奏模块:autoplay.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity autoplay is
port (clk2: in std_logic;
index_auto : out std_logic_vector(4 downto 0));
end;
architecture behave of autoplay is
signal count :integer range 0 to 136;--可根据乐曲长度改变
signal jiepai: std_logic;
signal j: integer range 0 to 60;
begin
jiepai1: process(clk2)--分频产生16Hz的节拍
begin
if clk2' event and clk2 = '1' then
if j = 30 then
j <= 0;
jiepai <= not jiepai;
else
j <= j+1;
end if;
end if;
end process jiepai1;
--jiepai <= clk2;
process(jiepai)
begin
if jiepai'event and jiepai='1' then
if count=136 then count<=0;--可根据乐曲长度改变
else count<=count+1;
end if;
end if;
end process;
music:process(count)--歌曲jingle bells
begin
case count is --此case语句:存储自动演奏部分的曲谱
when 0 => index_auto<="01011"; --3第一小节
when 1 => index_auto<="01011"; --3
when 2 => index_auto<="01011"; --3
when 3 => index_auto<="00000"; --0
when 4 => index_auto<="01011"; --3
when 5 => index_auto<="01011"; --3
when 6 => index_auto<="01011"; --3
when 7 => index_auto<="00000"; --0
when 8 => index_auto<="01011"; --3
when 9 => index_auto<="01011"; --3
when 10 =>index_auto<="01011"; --3
when 11=> index_auto<="01011"; --3
when 12=> index_auto<="01011"; --3
when 13=> index_auto<="01011"; --3
when 14=> index_auto<="01011"; --3
when 15=> index_auto<="00000"; --0
when 16=> index_auto<="01011"; --3
when 17 => index_auto<="01011"; --3
when 18 => index_auto<="01011"; --3
when 19 => index_auto<="00000"; --0
when 20=> index_auto<="01011"; --3
when 21=> index_auto<="01011"; --3
when 22=> index_auto<="01011"; --3
when 23=> index_auto<="00000"; --0
when 24=> index_auto<="01011"; --3
when 25 => index_auto<="01011"; --3
when 26=>index_auto<="01011"; --3
when 27=> index_auto<="01011"; --3
when 28=> index_auto<="01011"; --3
when 29=> index_auto<="01011"; --3
when 30=> index_auto<="01011"; --3
when 31=> index_auto<="00000"; --0
when 32=> index_auto<="00000"; --0
when 33=> index_auto<="00000"; --0
when 34=> index_auto<="00000"; --0
when 35=> index_auto<="01011"; --3--第二小节
when 36=> index_auto<="01011"; --3
when 37=> index_auto<="01011"; --3
when 38=> index_auto<="00000"; --0
when 39=> index_auto<="01101"; --5
when 40=> index_auto<="01101"; --5
when 41=> index_auto<="01101"; --5
when 42=> index_auto<="00000"; --0
when 43=> index_auto<="01001"; --1
when 44=> index_auto<="01001"; --1
when 45=> index_auto<="01001"; --1
when 46=> index_auto<="01001"; --1
when 47=> index_auto<="00000"; --0
when 48=> index_auto<="01010"; --2
when 49=> index_auto<="01010"; --2
when 50=> index_auto<="00000"; --0
when 51=> index_auto<="01011"; --3
when 52=> index_auto<="01011"; --3
when 53=> index_auto<="01011"; --3
when 54=> index_auto<="01011"; --3
when 55=> index_auto<="01011"; --3
when 56=> index_auto<="01011"; --3
when 57=> index_auto<="01011"; --3
when 58=> index_auto<="01011"; --3
when others => null;
end case;
end process;
end behave;
查表及显示模块:table.vhd
说明:
简谱中音名所对应的频率(Hz)
音名
频率(Hz)
音名
频率(Hz)
音名
频率(Hz)
低音1
261.6
中音1
523.3
高音1
1045.5
低音2
293.7
中音2
587.3
高音2
1174.7
低音3
329.6
中音3
659.3
高音3
1318.5
低音4
349.2
中音4
698.5
高音4
1396.9
低音5
392
中音5
784
高音5
1568
低音6
440
中音6
880
高音6
1760
低音7
493.9
中音7
987.8
高音7
1975.5
分频系数的计算举例:对中音1求分频系数tone,
523.3Hz = 1/(2*(tone+1))*6*10^6Hz。计算得tone = 5732
代码如下:
use ieee.std_logic_1164.all;
use ieee.std_logic_arith;
use ieee.std_logic_unsigned.all;
entity table is
port(index_key:in std_logic_vector(4 downto 0);
index_auto:in std_logic_vector(4 downto 0);
button :in std_logic;
tone:out integer range 0 to 8190;
code0:out std_logic_vector(3 downto 0);
code1:out std_logic_vector(3 downto 0);
code2:out std_logic_vector(3 downto 0)
);
end;
architecture search of table is
signal index: std_logic_vector(4 downto 0);
signal choice: std_logic;
begin
process(button)
begin
if button' event and button = '1' then
choice<=not choice;
end if;
if choice = '1' then
index<= index_auto;
else
index<= index_key;
end if;
end process;
process(index)
begin
case index is
when "01001"=> tone<=5732;--10表示高音,01表示中音,00表示低音
when "01010"=> tone<=5120;--后三位表示音调0-7
when "01011"=> tone<=4549;
when "01100"=> tone<=4294;
when "01101"=> tone<=3826;
when "01110"=> tone<=3408;
when "01111"=> tone<=3036;
when "11001"=> tone<=2868;
when "11010"=> tone<=2553;
when "11011"=> tone<=2275;
when "11100"=> tone<=2147;
when "11101"=> tone<=1913;
when "11110"=> tone<=1704;
when "11111"=> tone<=1518;
when others => tone<=0;
end case;
end process ;
process(index)--由index得BCD码
begin
if(index(4) = '0' and index(3) = '0') then
code0(3) <= '0' ;
code0(2) <= index(2) ;
code0(1) <= index(1) ;
code0(0) <= index(0);
code1 <= "0000";
code2 <= "0000";
elsif (index(4) = '0' and index(3) = '1') then
code0 <= "0000";
code1(3) <= '0' ;
code1(2) <= index(2) ;
code1(1) <= index(1) ;
code1(0) <= index(0);
code2 <= "0000";
elsif (index(4) = '1' and index(3) = '0') then
code0 <= "0000";
code1 <= "0000";
code2(3) <= '0' ;
code2(2) <= index(2) ;
code2(1) <= index(1) ;
code2(0) <= index(0);
end if;
end process;
end;
分频模块:fenpin.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity fenpin is
port(clk:in std_logic;--6MHz时钟
tone:in integer range 0 to 8190;--输入分频系数
buzz:out std_logic);--驱动扬声器发声
end;
architecture behave of fenpin is
signal clk_data: std_logic;
signal i: integer range 0 to 8190;
begin
yinpin: process(clk)--根据输入的分频系数分频
begin
if clk'event and clk = '1' then
if i = tone then
i <= 0;
clk_data <= not clk_data;
else
i <= i+1;
end if;
end if;
end process yinpin;--f=1/(2*(tone+1))*f0
buzz <= clk_data;
end;
5 结论以及结果说明
a. 运行环境:PC,MAX+plas II.
b. 仿真
图中显示了auto_play模块的仿真结果。Clk2用于分频。J用于计数。Count则表示乐曲长度。
图中显示了key_play模块的仿真结果。可以看出模块将输入key编码为index_key。
c.在实验箱上运行,效果很好。能够实现弹奏、自动播放和显示音调等功能,达到了设计要求。
参考文献
[1]高仁璟,孙鹏,陈景.数字电子基础与设计及[M].大连:大连理工大学出版社,2004年.117-119页.
[2] 简谱中音名所对应的频率
[3] 钢琴之家网,音乐和简谱知识,
[4] 维基百科,简谱http://zh.wikipedia.org/zh-cn/%E7%B0%A1%E8%AD%9C#
[5] 搜谱网,jingle bells 简谱
[6] 百度文库,使用vhdl进行分频器设计,
展开阅读全文