简易电子琴
1.系统原理框图
扬声器在不同频率的信号驱动下将发出不同的声音。本实验是利用实验板上的 8 个按键
产生不同的音阶信号,按键不同时,不同的音阶信号产生不同的频率信号去驱动扬声器,从
而实现电子琴的功能。
根 据 音 乐 理 论 , 每 个 8 度 音 之 间 可 分 为 12 个 半 音 , 每 个 半 音 之 间 的 频 率 相 差
(
212
.1
0599
Hz)。若 C 调第一个音名的频率为 261.63Hz,则各音名与频率以及 2MHz
时钟的分频系数的关系如表所示。
表 1—1 音名与频率以及 2MHz 时钟的分频系数的关系
音名
低音 1(do)
低音 2(re)
低音 3(mi)
低音 4(fa)
低音 5(sol)
低音 6(la)
低音 7(si)
中音 1(do!)
频率/Hz
分频系数
261.23
293.67
329.63
349.23
391.99
440.00
493.88
523.25
7643
6809
6066
5725
5101
4544
4048
3822
简易电子琴的系统框图如图 1—2 所示,它有键盘编码器和时钟分频器组成。键盘编码
器产生按键编码信号;时钟分频器产生不同的分频系数,将输入时钟频率分频至各音名对应
的频率值,从而驱动扬声器发出该频率的声音。
键盘输入
键盘编码器
时钟分频器
扬声器
2MHz 时钟输入
图 1—2 简易电子琴的系统框图
图 1—3 为实现简易电子琴的顶层原理图。其中,KEYBOARD 模块实现对键盘的编码,
K[7..0]为键盘输入,SEL[2..0]为 3 位二进制编码输出,EN 为使能输出信号(高电平有效);
M_FREQ 模块实现分频功能,CLK 为时钟输入,当 SEL[2..0]编码输入不同,且 EN 输入为
高电平时,分频器产生不同的频率值,当 SPK 输出为 1 时扬声器响,否则静音。
图 1—3 实现简易电子琴的顶层原理图
2.模块设计
①键盘编码器
VHDL 描述文件 keyboard.vhd 如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity keyboard is
port(
--8 位键盘输入
--3 位键盘编码输出
---使能输出
--按键,产生编码
in
out
out
k:
sel:
en:
);
std_logic_vector(7 downto 0);
std_logic_vector(2 downto 0);
std_logic
end keyboard;
architecture arc_keyboard of keyboard is
begin
process(k)
begin
case k is
when"11111110"=>sel<="001";
en<='1';
when"11111101"=>sel<="010";
en<='1';
when"11111011"=>sel<="011";
en<='1';
when"11110111"=>sel<="100";
en<='1';
when"11101111"=>sel<="101";
en<='1';
when"11011111"=>sel<="110";
en<='1';
when"10111111"=>sel<="111";
en<='1';
when"01111110"=>sel<="000";
en<='1';
sel<="000";
en<='0';
when others=>
end case;
end process;
end arc_keyboard;
②时钟分频器
VHDL 描述文件 m_freq,vhd 如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity m_freq is
port(
clk,en:in std_logic;
std_logic_vector(2downto 0);
std_logic
--3 位键盘编码输入
--扬声器控制信号输出
sel: in
spk: out
);
end m_freq;
architecture arc_m_freq of m_freq is
signal count_ld,count:std_logic_vector(12 downto 0);
begin
process(sel)
begin
case sel is
when "000" => count_ld <= "0111011101110";
when "001" => count_ld <= "1110111011011";
when "010" => count_ld <= "1101001010101";
when "011" => count_ld <= "1011110110010";
when "100" => count_ld <= "1011001011101";
when "101" => count_ld <= "1001111101101";
when "110" => count_ld <= "1000111000000";
when "111" => count_ld <= "0111111010000";
when others => count_ld <= "0111011101110";
--3822
--7643
--6809
--6066
--5725
--5101
--4544
--4048
--3822
end case;
end process;
process
begin
wait until clk'event and clk='1';
if en='0' then
count<=(others=>'0');
spk<='1';
--计数器同步清零
--当计数值小于 count_ld/2 时,spk=’1’,且加 1 计数
elsif count<('0'&count_ld(12 downto 1)) then
count<=count+1;
spk<='1';
--当计数值大于 count_ld/2 且小于 count_ld 时,spk=’0’,且加 1 计数
elsif count'0');
spk<='1';
end if;
end process;
end arc_m_freq;
3.原理图和波形仿真图
①键盘编码器的.bsf 图:
②时钟分频器的.bsf 图:
③简易电子琴的顶层原理图.bdf:
⑤波形仿真图:
⑴按键编码为’11111110’时波形图:
⑵按键编码为’11111101’时波形图:
⑶按键编码为’01111111’时波形图:
其它的波形图也和这差不多,只要分别改变 k[7]到 k[0]的高低电平达到和编码的高低电
平相同,然后仿真再看波形图。
4.问题分析
在整个课程设计中,不可避免遇到很多难于解决的问题,一来是对 EDA 技术的不太了
解,初涉 VHDL 语言以致很多语法和语言基本结构、算法生疏,运用不灵活,在编写源程序
上遇到很大难题,而且在编译运行程序时对出错的语句理解不到位,难于下手修改错误语句,
这使得在设计程序时遇到很大的阻碍,此外,VHDL 语言的数据类型很容易造成混淆,比如
IN STD_LOGIC_VECTOR(7 DOWNTO 0)语句,它有时既可以认为是从 7 下降到 0,也可认为是
从 0 上升到 7,当输入有多位时,这就容易造成在读懂仿真波形图时读位数倒置,使仿真现
象与理论结果相出入。
在完成电路验证这一步时,对频率的选择也是一大难点,有的设计项目对频率的要求
很高,需要大频率元件才能满足设计需求,若频率元件选择不恰当,将严重影响设计结果甚
至没有结果输出。对于设计简易电子琴时,由于要求输出不同频率的声音,频率变化范围大,
故需要一个 2MHz 的元件,对于小于这一值的频率不足以满足电路需求,仿真时只有一堆杂
音输出。
在对于设计时遇到的不同问题时,首先应该理解问题关键所在,因为用语言编写程序
需要仔细认真的态度,一点点错误漏洞将导致整个源程序无法编译运行,阻碍下一步工作完
成进度。
5.结束语
通过这次 VHDL 课程设计,不仅增强了我们的实践动手能力,也让我们对课堂上所学到
的理论知识的理解加深了许多,这给我们提供了一个在学习生活中很难得的理论联系实际的
机会。能够借此机会了解到部分 EDA 技术的知识和学习运用其中一种硬件描述语言 VHDL 编
程实现各种常用器件的功能,这是在哪堂讲课上都得不到的一笔财富。
另一方面我们也发现了在平时学习过程中难于发现的许多缺点跟不足。比如实践机会
过少,所学的理论知识不能灵活运用,在遇到实际的问题时无法正确处理;再者在课堂上获
得的专业知识过于浅显,很多的有关基本操作原理、操作方法都理解不了;课外知识了解的
也过少,导致在课程设计初期,面对完全陌生的设计课题无从下手,不知所措。这就提醒我
们在平时的学习生活中不能一味埋头于面前的课本知识,毕竟当今社会竞争越发激烈,而学
校能教授的东西有限,要想在人才市场中脱颖而出就只能靠我们自己。当然,在学习之余我
们更应该积极参加各种有关专业知识的实践活动和比赛,巩固所学理论,多注意培养初步的
实际工作能力和专业技术能力,这样在以后的工作岗位上不会显得那么仓促与生疏。