4x4 矩阵键盘输入与四位数码管显示 VHDL 语言 Quartus II软件
·名称:4x4矩阵键盘到数码管 · VHDL · Quartus II
·软件:Quartus II
·语言:VHDL
代码功能(概述)
本设计实现对 4×4 矩阵键盘的行列扫描与按键识别,将数字键 0~9 的按下事件转换为四个 BCD 字(共 16 位),并通过 7 段数码管(4 位)进行实时显示。核心流程包括:键盘扫描与去抖(边沿检测)、按键值编码、数据移位拼接(高位左移,低 4 位写入新 BCD)、以及七段码译码输出。整体结构清晰、模块化强,便于移植与扩展。
代码实现思路(设计要点)
·键盘扫描:key_4x4 模块以扫描列(H_col)—读取行(L_row)的方式逐行判定,内部使用状态机依次驱动列线并采样行线,定位按键矩阵坐标,输出独热码 key_number(15:0)。
·上升沿检测:key_input 对 key_number 的每一位进行双拍寄存,生成 A~F 与 0~9 的上升沿脉冲。顶层仅使用 0~9 脉冲。
·数据拼接:data_ctrl 接收 key_0~key_9 的上升沿,每次按键将 16 位寄存器整体左移 4 位,并在低 4 位写入对应 BCD(0000~1001)。复位有效时清零。
·显示译码:HEX 将 16 位数据按 4 位切片,交由 4 个 LED7S 子模块分别译码为七段显示;LED7S 采用查表 case 语句覆盖 0~F 的七段码。
代码结构(模块说明)
·key_seg(顶层):连接键盘输入、数据拼接与显示模块,形成完整数据通路并对外暴露接口。
·key_input:对 key_4x4 的独热键值进行双拍,同步并产生 0~F 按键的上升沿脉冲。
·key_4x4:实现 4×4 键盘的行列扫描状态机,将按键位置编码为 16 位独热键值。
·data_ctrl:接收数字键上升沿事件,按次序将 BCD 值左移拼接到 16 位数据寄存器中。
·HEX:将 16 位数据按 4 位切片,驱动 4 组七段显示接口 HEX3..HEX0。
·LED7S:0~F 的七段码译码查表,输出段选信号。
![]()
1、工程文件

2、程序文件


3、程序编译

4、RTL图

5、仿真图
整体仿真图

矩阵按键输入模块

数据控制模块

数码管显示模块

部分代码展示:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
--矩阵键盘
ENTITY key_4x4 IS
PORT (
clk_100KHz : IN STD_LOGIC;
reset : IN STD_LOGIC;
L_row : IN STD_LOGIC_VECTOR(3 DOWNTO 0);--行
H_col : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--列
key_number : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)--按键键值
);
END key_4x4;
ARCHITECTURE trans OF key_4x4 IS
CONSTANT s_L_all : INTEGER := 0;
CONSTANT s_L_row1 : INTEGER := 1;
CONSTANT s_L_row2 : INTEGER := 2;
CONSTANT s_L_row3 : INTEGER := 3;
CONSTANT s_L_row4 : INTEGER := 4;
CONSTANT s_LH : INTEGER := 5;
SIGNAL state : INTEGER:= s_L_all;--状态标志
SIGNAL key_flag : STD_LOGIC := '0';--按键标志位
SIGNAL H_col_reg : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";--寄存扫描列值
SIGNAL L_row_reg : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";--寄存扫描行值
SIGNAL H_and_L : STD_LOGIC_VECTOR(7 DOWNTO 0);
-- Declare intermediate signals for referenced outputs
SIGNAL H_col_sig : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL key_number_sig : STD_LOGIC_VECTOR(15 DOWNTO 0);
BEGIN
-- Drive referenced outputs
H_col <= H_col_sig;
key_number <= key_number_sig;
--************************************************************************
--逐行扫描原理
--************************************************************************/
PROCESS (clk_100KHz, reset)
BEGIN
IF ((NOT(reset)) = '1') THEN
H_col_sig <= "0000";
H_col_reg <= "0000";
L_row_reg <= "0000";
state <= s_L_all;
ELSIF (clk_100KHz'EVENT AND clk_100KHz = '1') THEN
CASE state IS
WHEN s_L_all =>
H_col_sig(3 DOWNTO 0) <= "0000";
key_flag <= '0';
IF (L_row(3 DOWNTO 0) /= "1111") THEN
state <= s_L_row1;
H_col_sig(3 DOWNTO 0) <= "0111";--有键按下,扫描第一行
ELSE
state <= s_L_all;
END IF;
WHEN s_L_row1 =>
IF (L_row(3 DOWNTO 0) /= "1111") THEN
state <= s_LH;--判断是否是第一行
ELSE
state <= s_L_row2;
H_col_sig(3 DOWNTO 0) <= "1011"; --扫描第二行
END IF;
WHEN s_L_row2 =>
IF (L_row(3 DOWNTO 0) /= "1111") THEN
state <= s_LH;--判断是否是第二行
ELSE
state <= s_L_row3;
H_col_sig(3 DOWNTO 0) <= "1101"; --扫描第三行
END IF;
WHEN s_L_row3 =>
IF (L_row(3 DOWNTO 0) /= "1111") THEN
state <= s_LH;--判断是否是第三行
ELSE
state <= s_L_row4;
H_col_sig(3 DOWNTO 0) <= "1110";--扫描第四行
END IF;
WHEN s_L_row4 =>
IF (L_row(3 DOWNTO 0) /= "1111") THEN
state <= s_LH;--判断是否是第四行
ELSE
state <= s_L_all;
END IF;
WHEN s_LH =>
IF (L_row(3 DOWNTO 0) /= "1111") THEN
H_col_reg <= H_col_sig;--保存扫描列值
L_row_reg <= L_row; --保存扫描行值
state <= s_LH;
key_flag <= '1';--有键按下
ELSE
state <= s_L_all;
END IF;
源代码获取
点击下方公众号卡片获取
更多推荐



所有评论(0)