EDA课程设计报告
——电子琴的设计
指导老师:
时间:2011年12月20日
组员:
电子琴设计过程
一、简易电子琴的工作原理
音乐产生原理及硬件设计由于一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。
二、简易电子琴中各模块的设计
本系统设计采用自顶向下的设计方案,系统的整体组装设计原理图如图1所示,它主要由音调发生模块,数控分频模块和显示模块三部分组成。各模块分别完成计时过程的控制功能、计时功能与显示功能。
为了更清楚的了解电子琴的工作过程,我们利用EDA工具(本课程设计Active-HDL)对各个模块实施时序仿真(Timing Simulation),由自顶向下的设计方式,最后将三个模块进行整合,做出简易电子琴整个系统的时序仿真图。
1、音调发生模块
音调发生模块的作用是产生音阶的分频预置值。当8位发声控制输入信号中的某一位为高电平时,则对应某一音阶的数值将输出,该数值即为该音阶的分频预置值,分频预置值控制数控分频模块进行分频,由此可得到每个音阶对应的频率。
音调发生模块原理图
音调发生模块可以由VHDL语言来实现,下面是一段主要代码:
process(clk,scn,kin) ---scan main
begin
iffalling_edge(clk)then
case scans is
when "10000001"=>state<="0000000000000001";
when "10000010"=>state<="0000000000000010";
when "10000100"=>state<="0000000000000100";
when "10001000"=>state<="0000000000001000";
when "01000001"=>state<="0000000000010000";
when "01000010"=>state<="0000000000100000";
when "01000100"=>state<="0000000001000000";
when "01001000"=>state<="0000000010000000";
when "00100001"=>state<="0000000100000000";
when "00100010"=>state<="0000001000000000";
when "00100100"=>state<="0000010000000000";
when "00101000"=>state<="0000100000000000";
when "00010001"=>state<="0001000000000000";
when "00010010"=>state<="0010000000000000";
when "00010100"=>state<="0100000000000000";
when "00011000"=>state<="1000000000000000";
when others=>null;
end case;
end if;
scans<=scn&kin;
scansignal<=scn;
case state is --LED
when "0000000000000001"=>lednum<="11111110";
when "0000000000000010"=>lednum<="11100001";
when "0000000000000100"=>lednum<="10111110";
when "0000000000001000"=>lednum<="10110111";
when "0000000000010000"=>lednum<="01100110";
when "0000000000100000"=>lednum<="11110011";
when "0000000001000000"=>lednum<="11011010";
when "0000000010000000"=>lednum<="01100001";
when others=>null;
end case;
ledout<=lednum;
end process;
2、数控分频模块
在对计算机组成原理的学习中,我们知道数控分频器的功能是在输入端输入不同数据时,对输入时钟产生不同的分频比,输出不同频率的时钟,以改变输出信号的频率。本设计中数控分频模块是利用并行预置数的减法计数器对时基脉冲进行分频,得到与1、2、3、4、5、6、7、8八个音符相对应的频率。
数控分频模块原理图如图所示:
数控分频模块原理图
其主要VHDL代码如下所示:
ARCHITECTURE arch OF key_led_bee IS
SIGNAL clk_div1 : std_logic_vector(3 DOWNTO 0); --基频分频计数器,基频为4M
SIGNAL clk_div2 : std_logic_vector(12 DOWNTO 0); --音阶分频计数器,由基频分频产生各个音阶
SIGNAL cnt : std_logic_vector(21 DOWNTO 0); --各音阶发声时间长短计数器
SIGNAL state : std_logic_vector(15 DOWNTO 0); --state 8bit
signalscn : std_logic_vector(3 DOWNTO 0); --key row in
signal counter : integer range 0 to 3; --creat scan signal
signal scans : std_logic_vector(7 downto 0); ---scans
signallednum : std_logic_vector(0 to 7); --led_num
--各个音调的分频系数
3、完成整个系统顶层设计的主要VHDL代码如下:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY key_led_bee IS
PORT (
clk : IN std_logic;
rst : IN std_logic;
kin:INstd_logic_vector(3 downto 0);
out_bit : OUT std_logic;
scansignal : out std_logic_vector(3 downto 0);
ledout :out std_logic_vector(7 downto 0) );
END key_led_bee;
ARCHITECTURE arch OF key_led_bee IS
SIGNAL clk_div1 : std_logic_vector(3 DOWNTO 0); --基频分频计数器,基频为4M
SIGNAL clk_div2 : std_logic_vector(12 DOWNTO 0); --音阶分频计数器,由基频分频产生各个音阶
SIGNAL cnt : std_logic_vector(21 DOWNTO 0); --各音阶发声时间长短计数器
SIGNAL state : std_logic_vector(15 DOWNTO 0); --state 8bit
signalscn : std_logic_vector(3 DOWNTO 0); --key row in
signal counter : integer range 0 to 3; --creat scan signal
signal scans : std_logic_vector(7 downto 0); ---scans
signallednum : std_logic_vector(0 to 7); --led_num
--各个音调的分频系数
CONSTANT duo : std_logic_vector(12 DOWNTO 0) :="0111011101110";
CONSTANT lai : std_logic_vector(12 DOWNTO 0) := "0110101001101";
CONSTANT mi : std_logic_vector(12 DOWNTO 0) := "0101111011010";
CONSTANT fa : std_logic_vector(12 DOWNTO 0) := "0101100110001";
CONSTANT suo : std_logic_vector(12 DOWNTO 0) := "0100111110111";
CONSTANT la : std_logic_vector(12 DOWNTO 0) := "0100011100001";
CONSTANT xi : std_logic_vector(12 DOWNTO 0) := "0011111101000";
CONSTANT duo1 : std_logic_vector(12 DOWNTO 0) := "0011101110111";
SIGNAL out_bit_tmp :std_logic;
BEGIN
out_bit<=out_bit_tmp;
PROCESS(clk,rst)
BEGIN
IF (NOT rst = '1') THEN
clk_div1 <= "0000";
ELSIF(clk'EVENT AND clk='1')THEN
IF (clk_div1 /= "1001") THEN
clk_div1 <= clk_div1 + "0001";
ELSE
clk_div1 <= "0000";
END IF;
END IF;
END PROCESS;
PROCESS(clk,rst)
BEGIN
IF (NOT rst = '1') THEN
cnt<= "0000000000000000000000";
out_bit_tmp<= '0';
ELSIF(clk'EVENT AND clk='1')THEN
IF (clk_div1 = "1001") THEN
CASE state IS
WHEN "0000000000000001" => --发“多”
IF (clk_div2 /= duo) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000000000010" => --发“来”
IF (clk_div2 /=lai) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000000000100" => --发"米“
IF (clk_div2 /=mi) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000000001000" => --发"法“
IF (clk_div2 /=fa) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000000010000" => --发"梭“
IF (clk_div2 /=suo) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000000100000" => --发"拉“
IF (clk_div2 /= la) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000001000000" => --发"西“
IF (clk_div2 /= xi) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN "0000000010000000" => --发"多“(高音)
IF (clk_div2 /= duo1) THEN
clk_div2 <= clk_div2 + "0000000000001";
ELSE
clk_div2 <= "0000000000000";
out_bit_tmp<= NOT out_bit_tmp;
END IF;
WHEN OTHERS =>
NULL;
END CASE;
END IF;
END IF;
END PROCESS;
process(clk) ----creat scan signal
begin
ifrising_edge(clk)then
if counter=3 then
counter<=0;
else
counter<=counter+1;
end if;
end if;
end process;
process(clk,scn,kin) ---scan main
begin
iffalling_edge(clk)then
case scans is
when "10000001"=>state<="0000000000000001"; --1
when "10000010"=>state<="0000000000000010"; --2
when "10000100"=>state<="0000000000000100"; --3
when "10001000"=>state<="0000000000001000"; --4
when "01000001"=>state<="0000000000010000"; --5
when "01000010"=>state<="0000000000100000"; --6
when "01000100"=>state<="0000000001000000"; --7
when "01001000"=>state<="0000000010000000"; --8
when "00100001"=>state<="0000000100000000"; --9
when "00100010"=>state<="0000001000000000"; --10
when "00100100"=>state<="0000010000000000"; --11
when "00101000"=>state<="0000100000000000"; --12
when "00010001"=>state<="0001000000000000"; --13
when "00010010"=>state<="0010000000000000"; --14
when "00010100"=>state<="0100000000000000"; --15
when "00011000"=>state<="1000000000000000"; --16
when others=>null;
end case;
end if;
scans<=scn&kin;
scansignal<=scn;
case state is --LED
when "0000000000000001"=>lednum<="11111110"; --1
when "0000000000000010"=>lednum<="11100001"; --2
when "0000000000000100"=>lednum<="10111110"; --3
when "0000000000001000"=>lednum<="10110111"; --4
when "0000000000010000"=>lednum<="01100110"; --5
when "0000000000100000"=>lednum<="11110011"; --6
when "0000000001000000"=>lednum<="11011010"; --7
when "0000000010000000"=>lednum<="01100001"; --1
when others=>null;
end case;
ledout<=lednum;
end process;
END arch;
三、系统仿真
整个系统的设计完成之后的仿真如图所示:
电子琴整个系统的仿真图
四、ISE软件物理实现
打开ISE软件,创建项目工程,将源程序带入综合,然后定义输入输出管脚约束,设计实现。
下载到FPGA板子上,可以观察到设计的数字秒表可以按照设计要求正常工作。
至此,整个课程设计完成。
五、结束语
通过两个多周的紧张工作,终于完成了电子琴的设计,这个课程设计使我受益匪浅,他使我了解了硬件设计的整个流程,并且加深了我对计算机组成原理这门的课内容的理解,通过这个课程设计,不仅使我了解了组成原理的脊髓,而且使我对VHDL语言从陌生到初步理解,扩充的我的知识面。
这个课程设计也培养了我们的耐心和毅力,一个小小的错误就会导致结果的不正确,而对错误的检查要求我要有足够的耐心,由于这个课程设计也使我积累了一些经验,相信这些经验在我以后的学习工作中会有很大的作用。此课程设计也使我了解了VHDL设计的方便灵活性,这是我们跨入计算机硬件行业很好的一次锻炼。
本文来源:https://www.2haoxitong.net/k/doc/533f1757f01dc281e53af0e8.html
文档为doc格式