⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hand_play.vhd

📁 多功能电子琴 可以实现人性化界面 同时可以根据按键选择播放模式
💻 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 + -