EDA 课程设计
班级: 通信工程四班
姓名:
学号:
时间:
设计一: 梁祝乐曲演奏电路设计
一. 设计任务
1) 了解乐曲演奏电路的实验原理。
2) 掌握利用可编程器件实现乐曲演奏的设计方法。
二.设计分析
根据声学知识,组成乐曲的每个音符的发声频率值及其持续的时间是乐曲能连续弹奏
所需的两个基本要素,获取这两个要素所对应的数值和通过纯硬件的手段来利用这些数值
实现所希望乐曲的演奏效果是该实验的关键。
实验原理图
原理电路如上图所示,实验由三个模块组成:
1)数控分频与演奏发生器模块,即 SPEAKERA。
2)乐曲简谱码对应的分频预置数查表电路模块,即 TONETABA。
3)音乐节拍和音调发生器模块,即 NOTETABS。
模块一(SPEAKERA):产生音符的频率。这是一个数控分频器,由其 clk 端输入一
个 12MHz 的信号,通过 SPEAKERA 分频后由 SPKOUT 输出,由于直接从数控分频器中
出来的输出信号是脉宽极窄的脉冲式信号,为了有利于驱动扬声器,须另加一个 D 触发器
以均衡其占空比,但这时的频率将是原来的一半。SPEAKERA 对 clk 输入信号的分频比由
11 位预置数 TONE[10..0]决定。SPKOUT 的输出频率将决定每一音符的音调,这样,分
频计数器的预置值 TONE[10..0]与 SPKOUT 的输出频率就有了对应关系。
模块二(TONETABA):音符的持续时间须根据乐曲的速度即每个音符的节拍数来确
定,原理图中 TONETABA 的功能首先是为 SPEAKERA 提供决定所发音符的分频预置数,
而此数在 SPEAKERA 输入口的停留时间即为音符的节拍值。模块 TONETABA 是乐曲简谱
码对应的分频预置数查表电路,其中设置了梁祝乐曲全部音符所对应的分频预置数,共 13
个,每一音符的停留时间由音乐节拍和音调发生器模块 NOTETABS 的 clk 的输入频率决定,
在此为 4Hz.这 13 个数值的输出由对应于 NOTETABA1 的 4 位输入值 Index[3..0]的输出
值与持续时间由模块 NOTETABS 决定。
模块三(NOTETABS):在 NOTETABS 中设置了一个 8 位二进制计数器(计数最大
值为 138,因为共有 138 个音符),这个计数器的频率选为 4Hz,即每一个计数值得停留
时 间 为 0.25 秒 , 恰 为 当 全 音 符 设 为 1 秒 时 , 四 四 拍 的 4 分 音 符 持 续 时 间 。 例 如 ,
NOTETABS 在以下的 VHDL 逻辑描述中,梁祝乐曲的第一个音符为 3,此音在逻辑中停留
了 4 个时钟节拍,即 1 秒时间,相应 地,所对应的 3 音符分 频预置值为 1036,在
SPEAKERA 的输入端停留了 1 秒。随着 NOTETABS 中的计数器按 4Hz 的时钟速率做加法
计数时,梁祝乐曲就开始连续自然地演奏起来了。
三. 实验程序:
模块一(speakera):
library ieee;
use ieee.std_logic_1164.all;
entity speakera is
port(clk:in std_logic;
tone:in integer range 0 to 16#7FF#;
spks:out std_logic);
end ;
architecture one of speakera is
signal preclk :std_logic;
signal fullspks:std_logic;
begin
divideclk:process(clk)
variable count4:integer range 0 to 15;
begin
preclk<='0';
if count4>11 then preclk<='1';count4:=0;
elsif clk'event and clk='1'then count4:=count4+1;
end if;
end process;
genspks:process(preclk,tone)
variable count11:integer range 0 to 16#7FF#;
begin
if preclk'event and preclk='1'then
if count11=16#7FF# then
count11:=tone;
fullspks<='1';
else count11:=count11+1;
fullspks<='0';end if;
end if;
end process;
delayspks:process(fullspks)
variable count2:std_logic;
begin
if fullspks'event and fullspks='1'then
count2:=not count2;
if count2='1'then spks<='1';
else spks<='0';end if;