一. 实验目的
1. 了解交流蜂鸣器的发音原理;
2. 利用蜂鸣器呵呵按键设计硬件电子琴;
3. 学会在编写HDL顶层文件。
二. 准备知识
与利用微处理器(CPU或MCU)来实现乐曲演奏相比,以纯硬件完成乐曲演奏电路的逻辑要复杂的多,仅凭传统的数字逻辑技术,很难完成简单的演奏电路,但是借助于功能强大的EDA工具与VHDL语言,就相对简单,很容易实现。
实验箱上有1个交流蜂鸣器BUZZER,通过跳线JP6的BEEP与可编程逻辑器件相连接。其硬件原理图如图!!!!!!!!所示。可以看出,为了增加I/O口的驱动能力,在此采用了PNP型三极管,这样只要在BEEP上输入一定频率的脉冲,蜂鸣器就会发出音乐。从能量的角度来说,这个脉冲信号占空比最好为1:1,此时蜂鸣器的发声强度最大。
乐曲演奏的原理:由于组成乐曲的每个音符的频率值(音调)及其持续时间(音长)是乐曲演奏的2个基本数据,因此需要控制输出到蜂鸣器的激励信号的频率和该频率信号持续的时间。
频率的高低决定了音调的高低,而乐曲的简谱与个音名的频率对应关系如表9.1所示。所以不同的频率的信号都从同一基准频率分频而来的。由于音节频率为非整数,而把分频系数作为小数处理又太麻烦,故需将计算得到的分频数进行四舍五入取整处理,并且其基准频率和分频系数应综合考虑加以选择,从而保证音乐不会走调。如在48MHz的时钟下,中音1(对应的频率值为523..25Hz)的分频系数应该为48000000/(2*523.25)=0xb327,这样只需对系统的时钟进行45863次分频,然后再进行占空比为1:1的二分频即可得到所要的中音1.至于其它音符,同样可以求出其对应的分频系数。如表9.2所示。
表9.1 简谱中的音名与频率的关系
单位:Hz
| 低音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 261.63 | 293.67 | 329.63 | 349.23 | 391.99 | 440.00 | 493.88 |
| 中音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 523.25 | 587.33 | 659.25 | 698.46 | 783.99 | 880 | 987.76 |
| 高音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 1046.50 | 1174.66 | 1381.51 | 1396.92 | 1567.98 | 1760 | 1975.52 |
表9.2 简谱中音名与分频次数的关系
单位:次数
| 低音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 91734 | 81726 | 72810 | 68723 | 61225 | 54545 | 48595 |
| 中音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 45867 | 40863 | 34745 | 34361 | 30613 | 27273 | 24297 |
| 高音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 22934 | 20431 | 17372 | 17181 | 15306 | 13636 | 12149 |
表9.3 简谱中音名与加载数的关系
单位:次数
| 低音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 39338 | 49346 | 58262 | 62349 | 69847 | 76527 | 82477 |
| 中音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 85205 | 90209 | 96327 | 96711 | 100459 | 103799 | 106775 |
| 高音部 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 频 率 | 108138 | 1101 | 113700 | 1131 | 115766 | 117436 | 1123 |
因为只有8个按键,所以这里为了简单起见,进行如下处理:按键key1~key7按下(低电平)时分别对应中音部的1~7,此时数码管8显示音符,数码7全灭不显示,;而按键key8按下时,按键key1~key7分别对应高音部的1~7,此时数码管8显示音符,数码7显示“H”,即标志为高音。为了简单起见,按键不进行消抖处理。
三. 实验步骤
1、新建工程beep1
新建文件夹,并在该文件夹下新建工程beep1。
2、新建顶层文件
新建HDL文件tone,并设为顶层实体文件。
本实验训练的工程文件只包含1个HDL顶层文件,即在一个HDL文件中实现硬件电子琴的设计。
该文件的输入管脚包括:按键key[7..0]、系统时钟clk48M;输出包括:蜂鸣器buzzer、扫描显示的位码dig[7..0]、扫描显示的段码seg[7..0]。
按键key8,按下时(低电平),数码7(段码定义为seg7)显示“H”(seg7= "10001001"),反之不显示(seg7="11111111")。
按键key7~key1,有且只有1个按键按下时(低电平),数码8(段码定义为seg8)分别显示“7”~“1”,并得出不同的加载数count_start;无key7~key1操作时,数码8不显示即全灭(seg8="11111111")。
按下key8时,再分别按键key7~key1,按下时(低电平),数码8分别显示“7”~“1”,译码出不同的加载数。无key7~key1操作时,数码8不显示即全灭。
计数范围为加载数N~满量程的带进位beep_r的进程。
beep_r经T触发器,结果为送蜂鸣器buzzer。
48MHz的系统时钟分频,得到占空比为1:1的clk100Hz时钟信号。该时钟信号为高电平时,点亮数码7(位码dig=“11111101”,段码reg=seg7);该时钟信号为低电平时,点亮数码8(位码dig=“11111110”,段码reg=seg8);
注意:各个进程之间的“连线”就是信号,进程之间依靠信号进行传递“数据”的,故需要定义一些信号(VHDL)或寄存器(Verilog HDL)。
3、编译、锁定管脚、再编译
指定ADDER8原理图文件为顶层文件。
为了方便锁定管脚,我们先进行编译,发现错误进行纠正,直至成功为止。
锁定管脚(管脚表)
再编译,把管脚锁定的信息编译到下载文件中去。
4、下载
连接电源,进行下载
根据设计思路,试验结果。
四. 实验参考程序
程序清单 tone.VHD
LIBRARY IEEE;
USE IEEE.STD_LOGIC_11.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY tone IS
PORT( clk48M: IN STD_LOGIC; --系统时钟48MHz
key: IN STD_LOGIC_VECTOR(7 DOWNTO 0);--按键输入
buzzer: OUT STD_LOGIC;--蜂鸣器输出端
seg: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);--数码管段码输出
dig: OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); --数码管位码输出
END ;
ARCHITECTURE one OF tone IS
SIGNAL beep,beep_r,clk100Hz,clk50Hz: STD_LOGIC;
SIGNAL count,count_start: integer range 0 to 131071; --预置数分频器中间计数值信号
SIGNAL count100Hz: integer range 0 to 480000;--100Hz计数器中间计数值信号
SIGNAL seg8,seg7: STD_LOGIC_VECTOR(7 DOWNTO 0);--数码7、8的译码
BEGIN
PROCESS(clk48M)
BEGIN
IF RISING_EDGE(clk48M)THEN
IF count=131071 THEN --计满X”1FFFF”
count<= count_start;--加载预置数
beep_r<='1'; --输出进位,触发T触发器
ELSE
count<=count+1;
beep_r<='0';
END IF;
END IF;
END PROCESS;
PROCESS(beep_r)
BEGIN
IF RISING_EDGE(beep_r)THEN
beep <= not beep; --T触发器,得到1:1方波
END IF;
END PROCESS;
buzzer <= beep;--输出到蜂鸣器
PROCESS(key)
BEGIN
CASE key IS
WHEN "11111110"=> count_start<=85205;seg8<=X"f9";--中音1预置数及显示译码
WHEN "11111101"=> count_start<=90209;seg8<=X"a4";--中音2
WHEN "11111011"=> count_start<=96327;seg8<=X"b0";--中音3
WHEN "11110111"=> count_start<=96711;seg8<=X"99";--中音4
WHEN "11101111"=> count_start<=100459;seg8<=X"92";--中音5
WHEN "11011111"=> count_start<=103799;seg8<=X"82";--中音6
WHEN "10111111"=> count_start<=106775;seg8<=X"f8";--中音7
WHEN "01111110"=> count_start<=108138;seg8<=X"f9";--高音1
WHEN "01111101"=> count_start<=1101;seg8<=X"a4";--高音2
WHEN "01111011"=> count_start<=113700;seg8<=X"b0";--高音3
WHEN "01110111"=> count_start<=1131;seg8<=X"99";--高音4
WHEN "01101111"=> count_start<=115766;seg8<=X"92";--高音5
WHEN "01011111"=> count_start<=117436;seg8<=X"82";--高音6
WHEN "00111111"=> count_start<=1123;seg8<=X"f8";--高音7
WHEN OTHERS=> count_start<=131071;seg8<=X"ff";--无声、无显示
END CASE;
CASE key(7) IS --key8按下时
WHEN '0' => seg7<="10001001";--显示"H"
WHEN OTHERS => seg7<="11111111";--不显示
END CASE;
END PROCESS;
PROCESS(clk48M)
BEGIN
IF RISING_EDGE(clk48M)THEN
IF count100Hz = 240000 THEN
count100Hz <= 0;
clk100Hz <= not clk100Hz;--反转,占空比1:1
--clk100Hz <= '1';
ELSE
count100Hz <= count100Hz+1;
--clk100Hz <= '0';
END IF;
END IF;
END PROCESS;
PROCESS(clk100Hz)
BEGIN
IF clk100Hz='1'THEN
seg<=seg7; --显示数码7的内容
dig<="11111101"; --选通数码7
ELSE
seg<=seg8; --显示数码8的内容
dig<="11111110"; --选通数码8
END IF;
END PROCESS;
END;下载本文