·名称: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 的七段码。
简化框图:
L_row → key_4x4 → key_input →(key_0..key_9 上升沿)→ data_ctrl → data[15:0] → HEX → HEX3..HEX0
↑ ↓ ↑
H_col(列驱动) 复位/时钟 LED7S×4(七段译码)
代码结构(模块说明)
·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 ISPORT (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 ISCONSTANT 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 outputsSIGNAL H_col_sig : STD_LOGIC_VECTOR(3 DOWNTO 0);SIGNAL key_number_sig : STD_LOGIC_VECTOR(15 DOWNTO 0);BEGIN-- Drive referenced outputsH_col <= H_col_sig;key_number <= key_number_sig;--************************************************************************--逐行扫描原理--************************************************************************/PROCESS (clk_100KHz, reset)BEGINIF ((NOT(reset)) = '1') THENH_col_sig <= "0000";H_col_reg <= "0000";L_row_reg <= "0000";state <= s_L_all;ELSIF (clk_100KHz'EVENT AND clk_100KHz = '1') THENCASE state ISWHEN s_L_all =>H_col_sig(3 DOWNTO 0) <= "0000";key_flag <= '0';IF (L_row(3 DOWNTO 0) /= "1111") THENstate <= s_L_row1;H_col_sig(3 DOWNTO 0) <= "0111";--有键按下,扫描第一行ELSEstate <= s_L_all;END IF;WHEN s_L_row1 =>IF (L_row(3 DOWNTO 0) /= "1111") THENstate <= s_LH;--判断是否是第一行ELSEstate <= s_L_row2;H_col_sig(3 DOWNTO 0) <= "1011"; --扫描第二行END IF;WHEN s_L_row2 =>IF (L_row(3 DOWNTO 0) /= "1111") THENstate <= s_LH;--判断是否是第二行ELSEstate <= s_L_row3;H_col_sig(3 DOWNTO 0) <= "1101"; --扫描第三行END IF;WHEN s_L_row3 =>IF (L_row(3 DOWNTO 0) /= "1111") THENstate <= s_LH;--判断是否是第三行ELSEstate <= s_L_row4;H_col_sig(3 DOWNTO 0) <= "1110";--扫描第四行END IF;WHEN s_L_row4 =>IF (L_row(3 DOWNTO 0) /= "1111") THENstate <= s_LH;--判断是否是第四行ELSEstate <= s_L_all;END IF;WHEN s_LH =>IF (L_row(3 DOWNTO 0) /= "1111") THENH_col_reg <= H_col_sig;--保存扫描列值L_row_reg <= L_row; --保存扫描行值state <= s_LH;key_flag <= '1';--有键按下ELSEstate <= s_L_all;END IF;
代码获取:
703