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

📄 fpga_7279.vhd

📁 基于FPGA的7279键盘数码管驱动
💻 VHD
字号:
--FPGA控制7279的程序

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_ARITH.all;
use IEEE.std_logic_UNSIGNED.all;

entity FPGA_7279 is
	port (
		--以下是引脚信号
		
		CLK       :IN      STD_LOGIC;  --系统时钟
		RST_N     :IN      STD_LOGIC;  --系统复位
		CLK_S     :IN      STD_LOGIC;  --7279时序的状态机时钟,周期为20us
		--外部控制接口与本模块之间的信号
		WR_N      :IN      STD_LOGIC;  --外部写信号
		RD_N      :IN      STD_LOGIC;  --外部读信号
		KEY_EN    :OUT     STD_LOGIC;  --存在有效键值, 高电平为存在有效键值, 外部接口读走数据后变低
		ADDR  	  :IN      STD_LOGIC_VECTOR(2 downto 0);  --地址信号
		D_BUS  	  :IN      STD_LOGIC_VECTOR(7 downto 0);  --指令,数据输入及键盘值输出
		--与7279之间的信号
		KEY7279   :IN      STD_LOGIC;  --7279的键盘信号,有键按下时为低电平,平时为高电平
		CLK7279   :OUT     STD_LOGIC;  --7279的时钟信号
		CS7279    :OUT     STD_LOGIC;  --7279的片选信号
		DAT7279   :INOUT   STD_LOGIC;  --7279数据信号
		OUT7279   :OUT     STD_LOGIC_VECTOR(7 downto 0)   --7279键盘键值输出信号,测试时用
		);
end FPGA_7279;

ARCHITECTURE behav OF FPGA_7279 IS

CONSTANT RST_7279	: std_logic_vector (7 downto 0) := x"A4";  --复位(清除)指令
CONSTANT TST_7279	: std_logic_vector (7 downto 0) := x"BF";  --测试指令
CONSTANT SL_7279	: std_logic_vector (7 downto 0) := x"A1";  --左移指令
CONSTANT SR_7279	: std_logic_vector (7 downto 0) := x"A0";  --右移指令
CONSTANT RL_7279	: std_logic_vector (7 downto 0) := x"A3";  --循环左移指令
CONSTANT RR_7279	: std_logic_vector (7 downto 0) := x"A2";  --循环右移指令
CONSTANT RDKY_7279	: std_logic_vector (7 downto 0) := x"15";  --读键盘数据指令
CONSTANT DC0_7279	: std_logic_vector (7 downto 0) := x"80";  --下载数据且按方式0译码, 1 0 0 0 0 a2 a1 a0 ,后3位用来指定数码管
CONSTANT DC1_7279	: std_logic_vector (7 downto 0) := x"C8";  --下载数据且按方式1译码, 1 1 0 0 1 a2 a1 a0
CONSTANT NDC_7279	: std_logic_vector (7 downto 0) := x"90";  --下载数据不译码,        1 0 0 1 0 a2 a1 a0
CONSTANT FL_7279	: std_logic_vector (7 downto 0) := x"88";  --闪烁控制
CONSTANT HD_7279	: std_logic_vector (7 downto 0) := x"98";  --消隐控制
CONSTANT SGDSP_7279	: std_logic_vector (7 downto 0) := x"E0";  --段点亮指令
CONSTANT SGCLR_7279	: std_logic_vector (7 downto 0) := x"C0";  --段关闭指令

SIGNAL cmd_7279     : STD_LOGIC_VECTOR (7 downto 0); --保存读进来的操作命令
SIGNAL key_7279     : STD_LOGIC_VECTOR (7 downto 0); --保存从7279读出来的按键值
SIGNAL key_7279_tmp : STD_LOGIC_VECTOR (7 downto 0); --从7279读键值,加一级缓存,键有效方才放入键值寄存器
SIGNAL cmd_tmp      : STD_LOGIC_VECTOR (7 downto 0); --保存操作命令到移位缓存
SIGNAL cmd_tmp1     : STD_LOGIC_VECTOR (7 downto 0); --进入START状态后,操作命令缓存,因为2字节指令中读键盘操作有所特殊,需要判断
SIGNAL data_tmp     : STD_LOGIC_VECTOR (7 downto 0); --进入START状态后,操作数据缓存
SIGNAL data_tmp1    : STD_LOGIC_VECTOR (7 downto 0); --保存操作数据到移位缓存
SIGNAL scmd_cnt     : INTEGER RANGE 0 to 7;          --命令字移位计数器
SIGNAL sdata_cnt    : INTEGER RANGE 0 to 7;          --数据字移位计数器,与键盘值读取计数器复用
SIGNAL delay_cnt	: INTEGER RANGE 0 to 3;
SIGNAL seg_cnt		: INTEGER RANGE 0 to 7;			 --数码管计数器,从右到左一共8个数码管

SIGNAL f_edge_cnt	: INTEGER RANGE 0 to 10;	--检测到KEY7279后,延时计数器
SIGNAL key_flag		: STD_LOGIC;				--按键标志,计数器溢出标志

SIGNAL cmd_start	: STD_LOGIC;		--单字节指令判断开始标志
SIGNAL data_start	: STD_LOGIC;		--双字节指令,由数据来判断开始标志
SIGNAL cmd_start_tmp	: STD_LOGIC;	--缓存单字节指令判断开始标志
SIGNAL data_start_tmp	: STD_LOGIC;	--缓存由数据来判断开始标志

TYPE SEG_Register IS ARRAY ( 0 To 7) of STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL seg_r 		:SEG_Register;
SIGNAL data_7279 	:SEG_Register;
SIGNAL decode_bus 	:STD_LOGIC_VECTOR (7 downto 0);	--从D_BUS读进数据来后,解码
TYPE STATE_TYPE is (IDLE, START, START_DELAY, SHIFT_CMD_LOW, 
					SHIFT_CMD_HIGH,	NEXT_DELAY,  SHIFT_DATA_LOW, SHIFT_DATA_HIGH, 
					SHIFT_KEY_LOW, SHIFT_KEY_HIGH, SHIFT_KEY_HIGH1, FINISH );
	signal state : STATE_TYPE;
TYPE STATE_TYPE1 IS (IDLE, START_WR, STOP);
	SIGNAL state1: STATE_TYPE1;	
BEGIN

	OUT7279 <= key_7279;
	
--直接对7279控制的状态机
process(CLK_S,RST_N)
	begin
	if (RST_N = '0') then
		state <= IDLE;
		key_7279 <= x"00";
		CS7279 <= '1';
		CLK7279 <= '0';
		DAT7279 <= 'Z';
		state <= IDLE;
	elsif falling_edge(CLK_S) then
		case state is
			when IDLE =>
				if (KEY7279 = '0') then
					cmd_tmp <= RDKY_7279;--为了测试读键盘操作
					DAT7279 <= 'Z';
					state <= START; 
				else
					if (seg_cnt = 7) then
						seg_cnt <= 0;
					else
						seg_cnt <= seg_cnt + 1;						
					end if;
					cmd_tmp <= NDC_7279(7 downto 3) & CONV_STD_LOGIC_VECTOR(seg_cnt,3);
					data_tmp <= data_7279(seg_cnt);
					state <= START; 
				end if;					
			when START =>
				delay_cnt <= 3;
				CS7279 <= '0';			--7279片选置低,开始4次延时,即80us
				CLK7279 <= '0';			--设置时钟为低
				state <= START_DELAY;
			
			--开始发送命令字-------------------------------------------------
			when START_DELAY =>
				if (delay_cnt > 1) then
					delay_cnt <= delay_cnt - 1;
				else
					scmd_cnt <= 7;		--80us延时结束,开始送命令字
					state <= SHIFT_CMD_LOW;
				end if;
			when SHIFT_CMD_LOW =>		--1位数据送到数据线上
				DAT7279 <= cmd_tmp1(scmd_cnt);	--用命令字的二级缓存做
				CLK7279 <= '1';			--时钟信号由低变高
				state <= SHIFT_CMD_HIGH;
			when SHIFT_CMD_HIGH =>
				CLK7279 <= '0';		--一外时钟后,时钟信号由高变低
				if (scmd_cnt > 0) then
					scmd_cnt <= scmd_cnt - 1;
					state <= SHIFT_CMD_LOW;					
				--当为双字节操作时,交替间断的延时
				elsif (data_start_tmp = '1') or (cmd_tmp1 = RDKY_7279) then
					delay_cnt <= 3;
					state <= NEXT_DELAY;
				else
					state <= FINISH;
				end if;
			
			--开始发送8位数据------------------------------------------------
			when NEXT_DELAY =>
				if (delay_cnt >1) then
					delay_cnt <= delay_cnt - 1;
				elsif (cmd_tmp = RDKY_7279) then	--当为键盘接收指令时
					sdata_cnt <= 7;
					state <= SHIFT_KEY_LOW;			--进行读取按键
				else
					sdata_cnt <= 7;
					state <= SHIFT_DATA_LOW;		--80us延时结束,进入数据传输
				end if;
			when SHIFT_DATA_LOW =>					--1位数据送到数据线上
				DAT7279 <= data_tmp1(sdata_cnt);
				CLK7279 <= '1';						--时钟信号由低变高
				state <= SHIFT_DATA_HIGH;
			when SHIFT_DATA_HIGH =>
				CLK7279 <= '0';						--时钟信号由高变低
				if (sdata_cnt > 0) then					
					sdata_cnt <= sdata_cnt - 1;
					state <= SHIFT_DATA_LOW;
				else
					state <= FINISH;
				end if;
			
			--读取按键值-----------------------------------------------------
			when SHIFT_KEY_LOW =>
				CLK7279 <= '1';						--时钟信号由低变高,DAT7279变为输入状态
				DAT7279 <= 'Z';
				state <= SHIFT_KEY_HIGH;
			when SHIFT_KEY_HIGH =>					--保证一个时钟周期的建立时间
				--key_7279(sdata_cnt) <= DAT7279;
				key_7279_tmp(sdata_cnt) <= DAT7279;
				state <= SHIFT_KEY_HIGH1;
			when SHIFT_KEY_HIGH1 =>
				CLK7279 <= '0';						--低电平后为一个时钟周期的保持时间
				if (sdata_cnt > 0) then					
					sdata_cnt <= sdata_cnt - 1;
					state <= SHIFT_KEY_LOW;
				else
					if (KEY7279 = '0') then			--当读取完后,KEY7279仍为0才能确定读取的为有效值
						key_7279 <= key_7279_tmp;
					end if;
					state <= FINISH;
				end if;
								
			--结束操作-------------------------------------------------------
			when FINISH =>
				CS7279 <= '1';		--7279片选置高,结束操作
				state <= IDLE;				
			when others =>
				NULL;
		end case;
	end if;
end process;

process(CLK_S,RST_N)
	begin
	if (RST_N = '0') then
		cmd_start <= '0';
		data_start <= '0';
	elsif falling_edge(CLK_S) then
		case state is
			when IDLE =>
				if (KEY7279 = '0') then
					cmd_start <= '1';	--为了测试
					data_start <= '0';	--为了测试	
				else
					cmd_start <= '0';	--为了测试
					data_start <= '1';	--为了测试	
				end if;	
			when START => --IDLE =>
				cmd_tmp1 <= cmd_tmp;	--为防止丢失双字节指令,所以多加一级缓存
				data_tmp1 <= data_tmp;
				cmd_start_tmp <= cmd_start;
				data_start_tmp <= data_start;
			when others =>
				NULL;
		end case;
	end if;
end process;

--读键值标志位
KEY_EN <= not key_flag;		--高电平,键值有效,(一般用高电平表示有效,用沿的话一般用下降沿表示有效)
process(KEY7279,CLK,RST_N)
	begin
	if (RST_N = '0') then
		key_flag <= '1';
	elsif (RD_N = '0') then
		key_flag <= '1';			--读键值寄存器key_7279时,清key_flag键值标志
	elsif rising_edge(KEY7279) then	--7279上升沿时,即按键已释放
		key_flag <= '0';			--key_flag下降沿,通知外部,可以读键值了
	end if;
end process;

--解码模块,从数据到显示码
decode_bus <= 	"00000000" when (D_BUS = "11111111") else	--D_BUS为x"FF"时,清除显示
				D_BUS(7) & "1111110" when (D_BUS(3 downto 0) = "0000") else	--0,D_BUS(7)小数点位
				D_BUS(7) & "0110000" when (D_BUS(3 downto 0) = "0001") else	--1
				D_BUS(7) & "1101101" when (D_BUS(3 downto 0) = "0010") else	--2
				D_BUS(7) & "1111001" when (D_BUS(3 downto 0) = "0011") else	--3
				D_BUS(7) & "0110011" when (D_BUS(3 downto 0) = "0100") else	--4
				D_BUS(7) & "1011011" when (D_BUS(3 downto 0) = "0101") else	--5
				D_BUS(7) & "1011111" when (D_BUS(3 downto 0) = "0110") else	--6
				D_BUS(7) & "1110000" when (D_BUS(3 downto 0) = "0111") else	--7
				D_BUS(7) & "1111111" when (D_BUS(3 downto 0) = "1000") else	--8
				D_BUS(7) & "1111011" when (D_BUS(3 downto 0) = "1001") else	--9
				D_BUS(7) & "1110111" when (D_BUS(3 downto 0) = "1010") else	--a
				D_BUS(7) & "0011111" when (D_BUS(3 downto 0) = "1011") else	--b
				D_BUS(7) & "1001110" when (D_BUS(3 downto 0) = "1100") else	--c
				D_BUS(7) & "0111101" when (D_BUS(3 downto 0) = "1101") else	--d
				D_BUS(7) & "1001111" when (D_BUS(3 downto 0) = "1110") else	--e
				D_BUS(7) & "1000111" when (D_BUS(3 downto 0) = "1111") else	--f
				"00000000";

--外部控制接口的写操作
process(CLK,RST_N)
	begin
	if(RST_N = '0') then
		for i in 0 to 7 loop
			data_7279(i) <= x"00";
			--data_7279(i) <= CONV_STD_LOGIC_VECTOR(i,8); --测试用
		end loop;
	elsif falling_edge(CLK) then
		case state1 is
			when IDLE =>
				if (WR_N = '0') then	--只有在WR_N与state状态为IDLE时,才允许接收命令
					state1 <= START_WR;
				end if;
			when START_WR =>
				if (WR_N = '0') then	
					--data_7279(CONV_INTEGER(ADDR)) <= D_BUS; 		--DC0_7279或DC1_7279
					data_7279(CONV_INTEGER(ADDR)) <= decode_bus;	--NDC_7279
				else
					state1 <= STOP;
				end if;
			when STOP =>
				state1 <= IDLE;
			when others =>
				NULL;
		end case;
	end if;
end process;



END behav;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -