📄 hand_play.vhd
字号:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.ram_pack.all;
entity Hand_Play is
port(
choose:in std_logic;--歌曲选择信号
clk_10:in std_logic;--10HZ时钟
clk_20:in std_logic;--20M时钟
high:in std_logic;--高音输入控制信号
low:in std_logic;--低音输入控制信号
fast: in std_logic;--快速播放音乐
slow: in std_logic;--慢速播放音乐
Ctrl:in std_logic_vector(2 downto 0);--状态转换控制信号
row:out std_logic_vector(3 downto 0);--键盘扫描行信号,同管脚中的scan信号,作为输出信号
col:inout std_logic_vector(3 downto 0);--键盘扫描列信号,同管脚中的kin信号,为input信号
audio:out std_logic;--音频输出信号
Dout:out std_logic_vector(6 downto 0); --数码管数据信号
Leds:out std_logic_vector(5 downto 0); --数码管选通信号
Key_Leds:out std_logic_vector(7 downto 0) --输出音阶的LED显示
);
end Hand_Play;
architecture code of Hand_Play is
signal tune_memory:RAM_TYPE;
signal time_memory:RAM_TYPE;
signal keynum, keynum1:integer range 0 to 31; --临时变量,用来存放按键值,初值0为无效值
signal keynum_last:integer range 0 to 31 :=0;--上一次扫描键盘时的键值,用于判断按键时间的长短
signal row_temp:std_logic_vector(3 downto 0);--时钟扫描线向量
signal Q:std_logic_vector(20 downto 0);--用于时钟加计数分频
signal count:std_logic_vector(1 downto 0);--标记键盘扫描线的四种状态
signal keyvec:std_logic_vector(9 downto 0);--用于判断键值的向量
signal col_pre_flutter:std_logic_vector(3 downto 0);--消抖后的col信号
signal same_key_time:integer;--同一键按下时扫描的次数,可以帮助计算按键时间
signal nextkey:integer range 0 to 99:=0;--标记RAM中存放的key按键时间的位置
signal iskey: std_logic;--判断是否有键按下
signal time_count,key_begin:std_logic;--time_count标记是否进行按键时间计数,key_begin标记一个键按下的开始
signal isreset:std_logic;--清RAM信号
signal clk_div:std_logic_vector(21 downto 0);--从20MHZ分频得到10HZ时钟
signal clk_play:std_logic;--可控制音乐播放快慢的时钟频率
component Prevent_Flutter is
port(
clk:in std_logic;
in1:in std_logic_vector(3 downto 0);
out1:out std_logic_vector(3 downto 0)
);
end component;
component Play_ram
port(
keynum2:in integer range 0 to 31;
signal tune_played:RAM_TYPE;
signal time_passed:RAM_TYPE;
max_addr:in integer range 0 to 127;
Ctrl:in std_logic_vector(2 downto 0);
song:out std_logic;
clk_com,clk_in,choose:in std_logic;
Dout:out std_logic_vector(6 downto 0); --数码管数据信号
Leds:out std_logic_vector(5 downto 0); --数码管选通信号
Key_Leds:out std_logic_vector(7 downto 0) --输出音阶的LED显示
);
end component;
begin
u0:Prevent_Flutter port map(Q(3),col,col_pre_flutter);
u1:Play_ram port map(keynum1,tune_memory,time_memory,nextkey,Ctrl,audio,clk_20,clk_play,choose,Dout,Leds,Key_Leds);
clkdiv_10:process(clk_20)
begin
if(clk_20'event and clk_20 = '1')then
clk_div<=clk_div+1;
if fast='1' and slow='0' then --时钟频率增加,快速播放
clk_play<=clk_div(18);
elsif fast='0' and slow='1' then --时钟频率减小,慢速播放
clk_play<=clk_div(20);
else
clk_play<=clk_div(19); --中速播放
end if;
end if;
end process clkdiv_10;
clkscan_pro:process(clk_20)--时钟分频
begin
if clk_20'event and clk_20='1' then
Q<=Q+1;
end if;
end process clkscan_pro;
col_qudian:process(Q)--在时钟的半个周期内使col端口放电,消除按键静电积累所产生的影响
begin
if Q(3)='1' then
col<="ZZZZ";
else
col<="0000";
end if;
end process col_qudian;
scanline:process(Q,Ctrl(0))--根据扫描时钟产生扫描线
begin
if(Ctrl(0)='0') then
row_temp<="0000";
isreset<='0';
elsif Q(3)'event and Q(3)='1' then
if isreset='0' then --判断是否需要对RAM清零,每次进入HAND模式时自动清RAM
for i in 0 to 127 loop
tune_memory(i)<=0;
time_memory(i)<=15;
end loop;
nextkey<=1;--RAM第一个元素避开
isreset<='1';
end if;
count<=count+1;
case count is --产生键盘扫描线
when "00"=> row_temp<="0001";
when "01"=> row_temp<="0010";
when "10"=> row_temp<="0100";
when "11"=> row_temp<="1000";
when others =>null;
end case;
if count="10" then
keynum1<=keynum;
end if;
if keynum_last/=0 and keynum_last=keynum1 then --同一个键按下未放开
time_count<='1';
key_begin<='0';
end if;
if keynum1/=0 and keynum_last/=keynum1 then --新的按键按下
keynum_last<=keynum1;
tune_memory(nextkey)<=keynum1;
time_memory(nextkey)<=same_key_time/4;
nextkey<=nextkey+1;
key_begin<='1';
time_count<='1';
end if;
if keynum_last=0 and keynum1=0 then --没有按键按下
time_count<='0';
key_begin<='0';
end if;
end if;
end process scanline;
row<=row_temp;
keyvec<=high&low&row_temp&col; --将用于判断按键的各种信号合为一个向量,便于根据不同情况判断键值
key_judge:process(clk_20 )
begin
if clk_20'event and clk_20='1' then
if iskey='0' then
case keyvec is
when "1000010001"=>keynum<=1;iskey<='1';--低音
when "1000010010"=>keynum<=2;iskey<='1';
when "1000010100"=>keynum<=3;iskey<='1';
when "1000011000"=>keynum<=4;iskey<='1';
when "1000100001"=>keynum<=5;iskey<='1';
when "1000100010"=>keynum<=6;iskey<='1';
when "1000100100"=>keynum<=7;iskey<='1';
when "0100010001"=>keynum<=15;iskey<='1';--高音
when "0100010010"=>keynum<=16;iskey<='1';
when "0100010100"=>keynum<=17;iskey<='1';
when "0100011000"=>keynum<=18;iskey<='1';
when "0100100001"=>keynum<=19;iskey<='1';
when "0100100010"=>keynum<=20;iskey<='1';
when "0100100100"=>keynum<=21;iskey<='1';
when "0000010001"=>keynum<=8;iskey<='1';--中音
when "0000010010"=>keynum<=9;iskey<='1';
when "0000010100"=>keynum<=10;iskey<='1';
when "0000011000"=>keynum<=11;iskey<='1';
when "0000100001"=>keynum<=12;iskey<='1';
when "0000100010"=>keynum<=13;iskey<='1';
when "0000100100"=>keynum<=14;iskey<='1';
when "1100010001"=>keynum<=8;iskey<='1';--高低音控制键同时按下,判为中音
when "1100010010"=>keynum<=9;iskey<='1';
when "1100010100"=>keynum<=10;iskey<='1';
when "1100011000"=>keynum<=11;iskey<='1';
when "1100100001"=>keynum<=12;iskey<='1';
when "1100100010"=>keynum<=13;iskey<='1';
when "1100100100"=>keynum<=14;iskey<='1';
when others =>keynum<=0;iskey<='0';
end case;
else
if count="11" then
iskey<='0';
end if;
end if;
end if;
end process key_judge;
time_measure:process(clk_play,time_count) --测量按键按下的时间
begin
if clk_play'event and clk_play='1' then
if time_count='1' and key_begin='1' then --新键按下,按键时间清零
same_key_time<=0;
elsif time_count='1' and key_begin='0' then
same_key_time<=same_key_time+1;
else
null;
end if;
end if;
end process time_measure;
end code;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -