?? 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);--狀態(tài)轉(zhuǎn)換控制信號
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); --數(shù)碼管數(shù)據(jù)信號
Leds:out std_logic_vector(5 downto 0); --數(shù)碼管選通信號
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);--用于時鐘加計數(shù)分頻
signal count:std_logic_vector(1 downto 0);--標記鍵盤掃描線的四種狀態(tài)
signal keyvec:std_logic_vector(9 downto 0);--用于判斷鍵值的向量
signal col_pre_flutter:std_logic_vector(3 downto 0);--消抖后的col信號
signal same_key_time:integer;--同一鍵按下時掃描的次數(shù),可以幫助計算按鍵時間
signal nextkey:integer range 0 to 99:=0;--標記RAM中存放的key按鍵時間的位置
signal iskey: std_logic;--判斷是否有鍵按下
signal time_count,key_begin:std_logic;--time_count標記是否進行按鍵時間計數(shù),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); --數(shù)碼管數(shù)據(jù)信號
Leds:out std_logic_vector(5 downto 0); --數(shù)碼管選通信號
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)--在時鐘的半個周期內(nèi)使col端口放電,消除按鍵靜電積累所產(chǎn)生的影響
begin
if Q(3)='1' then
col<="ZZZZ";
else
col<="0000";
end if;
end process col_qudian;
scanline:process(Q,Ctrl(0))--根據(jù)掃描時鐘產(chǎn)生掃描線
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 --產(chǎn)生鍵盤掃描線
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; --將用于判斷按鍵的各種信號合為一個向量,便于根據(jù)不同情況判斷鍵值
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 + -