大哥们,时隔一段时间又见面了,上个项目本来说是搞流水灯的,我太拉胯了,写着写着就变成了点亮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]};
这种移位好像不支持,现在还没想明白为啥,,,,
问题二:
功能是拨码按键控制灯的流动,导航按键控制流水灯的流动方式,我想的是,拨码按键按下,其流水灯方式的模式不会再因导航按键按下而改变,实际上,拨码按键停止流水灯流水后再按下导航键控制方式依然能控制,再次打开拨码按键,其按照最新的导航按键设置的模式流动,确实在代码中没有体现这个思想,可能会在后续改进。