三:【按键控制流水灯与FPGA按键键值简释】


大哥们,时隔一段时间又见面了,上个项目本来说是搞流水灯的,我太拉胯了,写着写着就变成了点亮LED(哈哈哈哈,,,蠢哭了),不过这次带来的是流水灯,本来早就写好了,但是由于还有其他事,一直没弄,,,

硬件

Xilinx spartan6系列的开发板(推荐大家买7,买7,买7)

软件

ise14.6

功能

拨码按键控制流水灯的起始,导航按键控制流水灯的流水方式

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    14:58:12 11/13/2021 
// Design Name: 
// Module Name:    keyRunLed 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//

//			1
//			^
//		3<<	00	>>4
//			v
//			2
//
module keyRunLed(
    input extrst,
    input extclk,
    input pushKey,
    input [4:0] singelKey,
    output reg [7:0] led
    );
	
//按键消抖程序
wire keyMode;				//定义按键触发标志位
reg [3:0] keyValueReg;		//定义按键键值寄存器

assign keyMode = singelKey[0] & singelKey[1] & singelKey[2] & singelKey[3] & singelKey[4];

//按键键值寄存器处理
always @ (posedge extclk or negedge extrst)
	if(!extrst) keyValueReg <= 4'b1111;
	else keyValueReg <= {keyValueReg[2:0],keyMode};
	
wire keyPressUp = keyValueReg[3] & ~keyValueReg[2];//按键抬起标志位(按键抬起为高电平)
wire keyPressDn = ~keyValueReg[3] & keyValueReg[2];//按键按下标志位(按键按下为低电平)
	
reg [19:0] cnt;

always @ (posedge extclk or negedge extrst)
	if(!extrst) cnt <= 20'd0;
	else if(keyPressUp || keyPressDn) cnt <= cnt + 1'b1;
	else if(cnt < 20'hfffff) cnt <= cnt + 1'b1;
	else cnt <= 20'd0;
		
reg [4:0] keyValue[1:0];

always @ (posedge extclk or negedge extrst)
	if(!extrst)
		begin
			keyValue[0] <= 5'b11111;
			keyValue[1] <= 5'b11111;
		end
	else if(cnt == 20'hfffff)			//
		begin
			keyValue[0] <= {singelKey[1],singelKey[2],singelKey[3],singelKey[4],singelKey[0]};
			keyValue[1] <= keyValue[0];
		end
		else ;
	
	
wire [4:0] keyFinVaule = keyValue[1] & ~keyValue[0];
//01111 -->10000 UP按键按下后取反
//按键未按下时状态 11111
//11111   &   ~( 01111)   =  10000 UP键按下后结果-->keyFinVaule[4] = 1;

reg ledEnable;
reg [2:0] ledDir;

always @ (posedge extclk or negedge extrst)
	if(!extrst) 
		begin	
			ledEnable <= 1'b0;
			ledDir <= 3'b000;
		end
	else 
		begin
			if(!pushKey) ledEnable <= 1'b1;
			else ledEnable <= 1'b0;
			
			if(keyFinVaule[4]) ledDir <= 3'b001;		//10000 UP
			else if(keyFinVaule[3]) ledDir <= 3'b010;	//01000 DN
			else if(keyFinVaule[2]) ledDir <= 3'b011;	//00100 LF
			else if(keyFinVaule[1]) ledDir <= 3'b100;	//00010 RG
			else if(keyFinVaule[0]) ledDir <= 3'b101;	//00001 CT
//			else ledDir <= 3'b000;//    玛卡巴卡
			else;
		end
	
reg [19:0] delay;

always @ (posedge extclk or negedge extrst)
	if(!extrst) delay <= 20'd0;
	else delay <= delay + 1'b1;
	
always @ (posedge extclk or negedge extrst)
	if(!extrst) led <= 8'b1111_1110;
	else if((delay == 20'hfffff) && ledEnable)
		begin
			case(ledDir)
				3'b001: led <= {led[6:0],led[7]};	
				3'b010: led <= {led[0],led[7:1]};	
				3'b001: led <= {led[2:0],led[3]};	
				3'b010: led[3] <= ~led[3];	
				3'b001: led[4] <= ~led[4];	
				//3'b000: led[0] <= ~led[0];
				//default:led[7] <= ~led[7];
				default:;
			endcase
		end
	else;	
endmodule

出现的问题

上次就是在做流水灯,但是由于刚学,也不确定哪儿有问题,一直以为是键值判断问题,到后来发现是这个问题:

// else ledDir <= 3’b000;// 玛卡巴卡

本来想没事else一下,加强一下条件,但是逻辑上翻车了,也就是说按键按下抬起以后,按键按下的流水灯程序不会保持,而是被这句话刷了一遍,,,,真蠢!

按键键值代码解释

reg [4:0] keyValue[1:0];

按键键值采集是这样定义的,定义两个五位的寄存器型keyValue,解释一下:
两个:就是为了通过比对获得keyValue[0]和keyValue[1]的最终相与的值,从而判断是哪个按键按下,如下:

wire [4:0] keyFinVaule = keyValue[1] & ~keyValue[0];

从代码可以看出:
always开始时
按键未按下时状态 11111,因此 keyValue[0] 的状态首先被赋值为 11111 ,然后 keyValue[1] 被 keyValue[0] 传参后也是 11111 。此时比如按键一按下后电平的状态为 01111 ,那么 keyValue[0] 的值就是 01111.仅供上面代码的操作keyFinVaule = keyValue[1] & ~keyValue[0];
就变成了
11111 & ~( 01111) = 11111 & 10000 = 10000
此时就可以判断keyFinVaule [4] 的值为高位,根据程序是什么按键按下,大戈壁荒打个比方:10000 是UP键按下后结果–>keyFinVaule[4] = 1;

五位:因为用了5个导航按键,一位是一个按键状态

keyValue[0] <= {singelKey[1],singelKey[2],singelKey[3],singelKey[4],singelKey[0]};
keyValue[1] <= keyValue[0];

这段代码则是将单个按键键值拼接成为5位,还说明了keyValue[0] 和 keyValue[1] 传值的先后顺序,keyValue[0]一定是按键按下时的状态,keyValue[1] 是上次的状态或者是 11111 。

仿真不会

仿真不会
调了一下没调出来我不会,我没学,但感觉这个很重要,但没调出来(好丢脸,,,),但是板子上亲测可以运行,相关问题下面总结

问题

问题一:

begin
			case(ledDir)
				3'b001: led <= {led[6:0],led[7]};	
				3'b010: led <= {led[0],led[7:1]};	
				3'b001: led <= {led[2:0],led[3]};	
				3'b010: led[3] <= ~led[3];	
				3'b001: led[4] <= ~led[4];	
				//3'b000: led[0] <= ~led[0];
				//default:led[7] <= ~led[7];
				default:;
			endcase
		end

这段代码里面只有led <= {led[6:0],led[7]};

led <= {led[0],led[7:1]};
能用,
led <= {led[2:0],led[3]};
这种移位好像不支持,现在还没想明白为啥,,,,

问题二:

功能是拨码按键控制灯的流动,导航按键控制流水灯的流动方式,我想的是,拨码按键按下,其流水灯方式的模式不会再因导航按键按下而改变,实际上,拨码按键停止流水灯流水后再按下导航键控制方式依然能控制,再次打开拨码按键,其按照最新的导航按键设置的模式流动,确实在代码中没有体现这个思想,可能会在后续改进。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值