VHDL矩阵键盘扫描数码管显示

VHDL矩阵键盘扫描数码管显示

  • 一、新建一个工程
  • 二、矩阵键盘
  • 三、代码部分
    • 四、仿真结果

一、新建一个工程

1.打开Quarteus,直接点击New Project izard.VHDL矩阵键盘扫描数码管显示_第1张图片
2.选择存放路径和工程名后一直Next,直到出现芯片选择页面(这里需要特别注意,这个软件不支持中文,所以工程存放路径一定不能含有中文,否则会报错)
VHDL矩阵键盘扫描数码管显示_第2张图片
3.选择对应的芯片,我这里选择EP4CE40F23C8,然后Next,最后Finish
VHDL矩阵键盘扫描数码管显示_第3张图片
4.完成工程的创建后,界面如图所示
VHDL矩阵键盘扫描数码管显示_第4张图片
5.我们点击File->New,出现如下图所示页面,再点击VHDL File并确定
VHDL矩阵键盘扫描数码管显示_第5张图片
6.至此,完成了VHDL工程文件的创建
VHDL矩阵键盘扫描数码管显示_第6张图片

二、矩阵键盘

矩阵键盘只有8个端口[KR0…KR3]和[KC0…KC3],,即对应四输入和四输出,如下图所示
VHDL矩阵键盘扫描数码管显示_第7张图片
所以,我们需要让行/列做输入口,列/行做输出口,再读取输出口的状态,结合输入即可得出按下的是哪个按键具体实现在代码部分

三、代码部分

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY leds7 IS
PORT(clk,RST,EN:IN STD_LOGIC;
		KR:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);	--行
		KC:IN STD_LOGIC_VECTOR(3 DOWNTO 0);		--列
	ledg:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);		--数码管
	  SEL:OUT STD_LOGIC_VECTOR(2 DOWNTO 0));	--数码管位选
END leds7;

ARCHITECTURE bhv OF leds7 IS
BEGIN
	PROCESS(clk,RST,EN)
	VARIABLE RC:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE K:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE ROW:STD_LOGIC_VECTOR(3 DOWNTO 0);
	VARIABLE Q:STD_LOGIC_VECTOR(1 DOWNTO 0);
	--定义八个变量用于存储对应数码管的值
	VARIABLE Q1:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q2:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q3:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q4:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q5:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q6:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q7:STD_LOGIC_VECTOR(7 DOWNTO 0);
	VARIABLE Q8:STD_LOGIC_VECTOR(7 DOWNTO 0);
	
	VARIABLE count:STD_LOGIC_VECTOR(2 DOWNTO 0);
	VARIABLE SELG:STD_LOGIC_VECTOR(2 DOWNTO 0);
	VARIABLE T:STD_LOGIC_VECTOR(9 DOWNTO 0);
	VARIABLE FLAG:STD_LOGIC;
	BEGIN
	IF RST = '0'THEN		--当复位信号为低电平时,清空八个数码管对应存储的值,即复位
			Q8:="00000000";Q7:="00000000";Q6:="00000000";Q5:="00000000";
			Q4:="00000000";Q3:="00000000";Q2:="00000000";Q1:="00000000";
			count := "000";
			SELG := "000";
			ELSIF clk'EVENT AND clk = '1'THEN		--获取时钟上升沿信号
			Q:=Q+1;
			CASE Q IS
				WHEN "00"=>ROW:="1110";KR<=ROW;		--扫描第一列
				WHEN "01"=>ROW:="1101";KR<=ROW;		--扫描第二列
				WHEN "10"=>ROW:="1011";KR<=ROW;		--扫描第三列
				WHEN "11"=>ROW:="0111";KR<=ROW;		--扫描第四列
				WHEN OTHERS=>NULL;
			END CASE;
			IF EN = '1' THEN
				CASE ROW IS 
					WHEN "1110" =>
                     CASE KC IS
                        WHEN "0111" =>RC:= "11101110";  --扫描第一行,按键按下则为1  
                        WHEN "1011" =>RC:= "11101101";  --扫描第二行,按键按下则为4  
                        WHEN "1101" =>RC:= "11101011";  --扫描第三行,按键按下则为7  
                        WHEN "1110" =>RC:= "11100111";  --扫描第四行,按键按下则为E  
                        WHEN OTHERS => NULL;
                     END CASE;
					WHEN "1101" =>
							CASE KC IS
								WHEN "0111" =>RC:= "01111110";   --扫描第一行,按键按下则为A 
								WHEN "1011" =>RC:= "01111101";   --扫描第二行,按键按下则为B
								WHEN "1101" =>RC:= "01111011";   --扫描第三行,按键按下则为C
								WHEN "1110" =>RC:= "01110111";   --扫描第四行,按键按下则为D  
								WHEN OTHERS =>NULL;
							END CASE;
					WHEN "1011" =>
							CASE KC IS
								WHEN "0111" =>RC:= "10111110";   --扫描第一行,按键按下则为3 
								WHEN "1011" =>RC:= "10111101";   --扫描第二行,按键按下则为6 
								WHEN "1101" =>RC:= "10111011";   --扫描第三行,按键按下则为9  
								WHEN "1110" =>RC:= "01111011";   --扫描第四行,按键按下则为C  
								WHEN OTHERS =>NULL;
							END CASE;
					WHEN "0111" =>
							CASE KC IS 
								WHEN "0111" =>RC:= "11011110";   --扫描第一行,按键按下则为2  
								WHEN "1011" =>RC:= "11011101";   --扫描第二行,按键按下则为5
								WHEN "1101" =>RC:= "11011011";   --扫描第三行,按键按下则为8
								WHEN "1110" =>RC:= "11010111";   --扫描第四行,按键按下则为0 
								WHEN OTHERS =>NULL;
							END CASE;
					WHEN OTHERS  =>NULL;
				END CASE;
			END IF;
			T:=T+1;		--每次时钟上升沿T自增1
			IF T = "0011101101"THEN		--当T满足0011101101时
				FLAG := '1';				--标志位FLAG为1,即允许按键输入
				T := T-T;					--可以适当修改T的值,使得按键灵敏度达到最佳
			END IF;
			SELG:=SELG-1;					--数码管位选自减1
			IF(RC /= "11111111")AND(FLAG = '1') THEN		--按键输入一个值时数码管对应值向左移
				Q8:=Q7;Q7:=Q6;Q6:=Q5;Q5:=Q4;
				Q4:=Q3;Q3:=Q2;Q2:=Q1;Q1:=RC;
				FLAG := '0';				--标志位返回0,目的是避免按键按下一次输入多个值
				T := T-T;					--计数器T清零
				IF Q8 = "00000000" THEN --每有一个按键值输入时
					count := count-1;		--count自减1,目的是存储位选值循环的条件
				ELSE 							--当Q8的值不为零时,说明有八个数输入了,位选信号可以从111自减到000
				count := "000";			
				END IF;
			END IF;
			IF FLAG = '0'THEN				--在标志位FLAG为0的时候
				RC:="11111111";			--RC始终为11111111,避免一次键入多个值
			END IF;
			IF (SELG < count) OR (Q1 = "00000000")THEN
				SELG := "111";				--每当数码管位选达到最后一位要显示的位置时,位选重新回归111
			END IF;
			SEL <= SELG;					--把位选信号传递给位选引脚
			--数码管与对应存储数据的配对关系
			CASE SELG IS
				WHEN "000" =>K:= Q8;
				WHEN "001" =>K:= Q7;
				WHEN "010" =>K:= Q6;
				WHEN "011" =>K:= Q5;
				WHEN "100" =>K:= Q4;
				WHEN "101" =>K:= Q3;
				WHEN "110" =>K:= Q2;
				WHEN "111" =>K:= Q1;
				WHEN OTHERS => NULL;
			END CASE;
			--数码管显示译码部分
			CASE K IS
				WHEN "11010111" =>ledg <= "00111111"; --0
				WHEN "11101110" =>ledg <= "00000110"; --1
				WHEN "11011110" =>ledg <= "01011011"; --2
				WHEN "10111110" =>ledg <= "01001111"; --3
				WHEN "11101101" =>ledg <= "01100110"; --4
				WHEN "11011101" =>ledg <= "01101101"; --5
				WHEN "10111101" =>ledg <= "01111101"; --6
				WHEN "11101011" =>ledg <= "00000111"; --7
				WHEN "11011011" =>ledg <= "01111111"; --8
				WHEN "10111011" =>ledg <= "01101111"; --9
				WHEN "01111110" =>ledg <= "01110111"; --A
				WHEN "01111101" =>ledg <= "01111100"; --B
				WHEN "01111011" =>ledg <= "00111001"; --C
				WHEN "01110111" =>ledg <= "01011110"; --D
				WHEN "11100111" =>ledg <= "01111001"; --E
				WHEN "10110111" =>ledg <= "01110001"; --F
				WHEN OTHERS => ledg <= "00000000";
			END CASE;
		END IF;
	END PROCESS;
END bhv;
	

我们分四步对矩阵键盘进行扫描,我们首先给第一行赋值1,其他行赋值0,即KR=“0001”,当第一个的按键按下时,列输出KC将得到“0001”,第二个按键按下时,KC= “0010”,依次类推,再给第二行赋值“0010”,列值得到不同的输出,一共有16种情况,对应4X4矩阵键盘的16个按键,当满足不同条件时将相应数码管的值赋给SEG7,最终再赋给SEG7S。

四、仿真结果

VHDL矩阵键盘扫描数码管显示_第8张图片
从仿真结果中可以看出,当只键入一个值时,数码管显示一个值,同时数码管位选也只有一个值“111”,逐个输入后,位选相应增加,数码管显示对应的值。

你可能感兴趣的:(VHDL,矩阵,算法)