一.任务
Cyclone IV开发板上有四个按键,每个按键通过消抖后作为密码按键KEY1,KEY2,KEY3,KEY4分别代表密码1,2,3,4。按下每个按键4个led灯做相应的动作,只有按照正确的密码1423输入,4个led灯才同时以20ms的间隔闪烁1s时间(同时闪2次),表示开锁成功。
设计思路:
二.工程项目
Verilog HDL编写
①设计按键消抖模块
这里和之前的按键消抖是一样的
key_debounce.v
module key_debounce(
input wire clk,
input wire rst_n,
input wire key,
output reg flag, //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
output reg key_value //消抖后稳定的按键值给到蜂鸣器模块
);
//定义20ms延迟计数器,0.2s,1_000_000次
parameter MAX_NUM = 20'd1_000_000;
reg [19:0] delay_cnt;
//寄存依次key的值用来判断按键是否消抖成功
reg key_reg;
//20ms延时计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
key_reg <= 1'b1; //复位信号,设置按键无效
delay_cnt <= 1'b0; //计数器设置为0
end
else
begin
key_reg <= key;
if(key_reg == 1'b1 && key == 1'b0) //当这一次key值和上一次key值不一样,证明正在抖动
delay_cnt <= MAX_NUM; //延迟时间20ms
else if(delay_cnt > 1'b0)
delay_cnt <= delay_cnt - 1'b1; //没有抖动,开始20ms倒计时
else
delay_cnt <= 1'b0;
end
end
//根据延时计数器获取按键状态以及按键值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
flag <= 1'b0; //复位信号,设置信号标志为抖动
key_value <= 1'b1; //设置抽样值为1
end
else
begin
if(delay_cnt == 20'd1) //倒计时1_000_000到1
begin
flag <= 1'b1;
key_value <= key; //稳定20ms后将key值给到key_value
end
else
begin
flag <= 1'b0;
key_value <= key_value; //20ms内先不取样
end
end
end
endmodule
②设计密码锁模块
digital_lock.v
module digital_lock(
input wire clk,//时钟
input wire rst_n,//复位
input [3:0] key_value,//按键值
input [3:0] flag,
output reg [3:0] led
);
parameter MAX_NUM = 9_999_999;//定义最大计时0.2s
parameter MAX_NUM2 = 10;//2s计数基于0.2s
//定义状态计数器,4个灯4个状态
reg [1:0] led_flag;
reg [2:0] clock_flag;//密码输入共有5个状态,1:无按键按下 2:按下1个正确值 3:按下2个正确值 4:按下3个正确值 5:按下4个正确值
reg [23:0] cnt = 0;//0.2s计时器赋初值为0
reg [26:0] cnt_1 = 0;//2s计时器赋初值为0
reg time_flag;//开始计时标记 1:开始计时 0:不开始
//0.2s计数器模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 1'b0;//按下复位键,清零
else if(cnt == MAX_NUM)//计时器达到最大值,清零重新计数
cnt <= 1'b0;
else
cnt <= cnt + 1'b1;
end
//2s计数器模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_1 <= 1'b0;//按下复位键,清零
else if(time_flag == 1)begin//开始计时
if(cnt == MAX_NUM)begin
if(cnt_1 < MAX_NUM2)begin
cnt_1 <= cnt_1 + 1'b1;
end
else begin
cnt_1 <= 1'b0;//cnt_1计数达到最大就清空
end
end
else begin
cnt_1 <= cnt_1;//其余时间保持
end
end
else begin
cnt_1 <= 1'b0;//不计时,cnt_1清空
end
end
//状态切换计数器模块 led_flag的状态基于0.2s
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
led_flag <= 1'b0;
else if(cnt == MAX_NUM)
led_flag <= led_flag + 1'b1; //超出宽度截取低两位
else
led_flag <= led_flag;
end
//led标志控制模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
clock_flag <= 3'b001; //初始状态无按键按下
else begin
case(clock_flag)