目录
一: 章节导读
1.1 任务要求
1.2 模块功能划分
二: 代码设计
2.1 灯控制逻辑(led_ctrl)
2.2 按键消抖模块(key_filter)
2.3 顶层模块(key_led)
2.4 引脚绑定
module led_ctrl(
input clk,
input reset_n,
input key_add,//自加按键(这是脉冲信号连接按键消抖模块中的按下脉冲标志Key_P_Flag)
input key_sub,//自减按键
input key_shift_l, //左移按键
input key_shift_r, //右移按键
output reg [7:0]led //led 显示
);
always@(posedge clk or negedge reset_n)
if(!reset_n)
led <= 8'b0000_0000;
else if(key_add)
led <= led + 1'b1;
else if(key_sub)
led <= led - 1'b1;
else if(key_shift_l)
led <= (led << 1);
else if(key_shift_r)
led <= (led >> 1);
else
led <= led;
endmodule
//基于状态机思维的按键消抖功能verilog实现思路
//1. 对异步输入信号打拍消除亚稳态
//2.寄存打拍后信号,对比得出上升沿与下降沿标志信号
//3.列出所有状态,编写状态机整体框架
//4.编写各状态间跳转方向以及对应跳转条件
//5.编写状态输出逻辑,在正确时刻输出信号赋值
module key_filter(
input Key,
input Clk,
input Reset_n,
output reg Key_P_Flag,
output reg Key_R_Flag,
output reg Key_State//向外输出过滤后的电平信号,使得输出电平比较干净。
);
reg [29:0]cnt_20ms;//定时20ms计数器
reg [1:0]state;
reg sync_d0_key,sync_d1_key;//定义两个同步D触发器的输出作为输入是为了消除未知信号Key的亚稳态,以及将异步信号Key变为同步信号
reg r_key;//定义下降沿
wire nedge_key;//下降沿定义
wire pedge_key;//下降沿定义
always@(posedge Clk)
sync_d0_key <= Key;
always@(posedge Clk)
sync_d1_key <= sync_d0_key;
always@(posedge Clk)
r_key <= sync_d1_key;
assign nedge_key = (sync_d1_key == 0)&&(r_key == 1);
assign pedge_key = (sync_d1_key == 1)&&(r_key == 0);
localparam IDLE = 0;//localparam是本地参数定义,用于定义一个标识符代表常量,无法进行参数传递,不可修改
localparam P_FILTER = 1; //parameter可以进行参数传递,就是可修改的意思。
localparam WAIT_R = 2;
localparam R_FILTER = 3;
parameter Dly_20ms_cnt = 1000_000-1;
wire time_20ms_reached;
assign time_20ms_reached = (cnt_20ms >= Dly_20ms_cnt);
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)begin
state <= IDLE;
Key_R_Flag <= 0;
Key_P_Flag <= 0;
cnt_20ms <= 0;
Key_State <= 1;
end
else begin
case(state)
IDLE:
if(nedge_key)
state <= P_FILTER;
else begin
state <= IDLE;
Key_R_Flag <= 0; //告知外界按键已经松开
end
P_FILTER:
if(time_20ms_reached)begin//顺利到达20ms说明按键已经顺利按下
state <= WAIT_R;
Key_P_Flag <= 1; //告知外界按键已经按下
cnt_20ms <= 0;//计时到20ms后直接清零。
Key_State <= 0;//此时外界按键已经按下,所以输出低电平
end
else if(pedge_key)begin
state <= IDLE;
cnt_20ms <= 0;//回到IDLE后清零重新计数
end
else begin
state <= state;
cnt_20ms <= cnt_20ms+1;//其他状态开始计数
end
WAIT_R:
if(pedge_key)
state <= R_FILTER;
else begin
state <= WAIT_R;
Key_P_Flag <= 0;
end
R_FILTER:
if(time_20ms_reached)begin
state <= IDLE;
Key_R_Flag <= 1; //告知外界按键已经松开
cnt_20ms <= 0;//计时到20ms后直接清零。
Key_State <= 1; //此时外界按键已经松开,所以Key_State为高电平,这样输出电平就比较干净
end
else if(nedge_key)begin
state <= WAIT_R;
cnt_20ms <= 0;//回到WAIT_R后清零重新计数
end
else begin
state <= state;
cnt_20ms <= cnt_20ms+1;//其他状态开始计数
end
endcase
end
endmodule
module key_led(
input clk,
input reset_n,
input key_in0,//自加按键
input key_in1,//自减按键
input key_in2, //左移按键
input key_in3, //右移按键
output [7:0]led //led 显示
);
wire Key_P_Flag0;(不同的按键产生不同的脉冲信号)
wire Key_P_Flag1;
wire Key_P_Flag2;
wire Key_P_Flag3;
key_filter key_filter_inst0(
.Key(key_in0),
.Clk(clk),
.Reset_n(reset_n),
.Key_P_Flag(Key_P_Flag0),
.Key_R_Flag(),
.Key_State()//向外输出过滤后的电平信号,使得输出电平比较干净。
);
key_filter key_filter_inst1(
.Key(key_in1),
.Clk(clk),
.Reset_n(reset_n),
.Key_P_Flag(Key_P_Flag1),
.Key_R_Flag(),
.Key_State()//向外输出过滤后的电平信号,使得输出电平比较干净。
);
key_filter key_filter_inst2(
.Key(key_in2),
.Clk(clk),
.Reset_n(reset_n),
.Key_P_Flag(Key_P_Flag2),
.Key_R_Flag(),
.Key_State()//向外输出过滤后的电平信号,使得输出电平比较干净。
);
key_filter key_filter_inst3(
.Key(key_in3),
.Clk(clk),
.Reset_n(reset_n),
.Key_P_Flag(Key_P_Flag3),
.Key_R_Flag(),
.Key_State()//向外输出过滤后的电平信号,使得输出电平比较干净。
);
led_ctrl led_ctrl(
.clk(clk),
.reset_n(reset_n),
.key_add(Key_P_Flag0),//自加按键(脉冲信号)
.key_sub(Key_P_Flag1),//自减按键
.key_shift_l(Key_P_Flag2), //左移按键
.key_shift_r(Key_P_Flag3), //右移按键
.led(led) //led 显示
);
endmodule
set_property IOSTANDARD LVCMOS33 [get_ports {led[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports key_in0]
set_property IOSTANDARD LVCMOS33 [get_ports key_in1]
set_property IOSTANDARD LVCMOS33 [get_ports key_in2]
set_property IOSTANDARD LVCMOS33 [get_ports key_in3]
set_property IOSTANDARD LVCMOS33 [get_ports reset_n]
set_property PACKAGE_PIN U18 [get_ports clk]
set_property PACKAGE_PIN H20 [get_ports key_in0]
set_property PACKAGE_PIN H16 [get_ports key_in1]
set_property PACKAGE_PIN J20 [get_ports key_in2]
set_property PACKAGE_PIN J19 [get_ports key_in3]
set_property PACKAGE_PIN F20 [get_ports reset_n]
set_property PACKAGE_PIN K18 [get_ports {led[7]}]
set_property PACKAGE_PIN H17 [get_ports {led[6]}]
set_property PACKAGE_PIN J18 [get_ports {led[5]}]
set_property PACKAGE_PIN K19 [get_ports {led[4]}]
set_property PACKAGE_PIN G18 [get_ports {led[3]}]
set_property PACKAGE_PIN G20 [get_ports {led[2]}]
set_property PACKAGE_PIN G19 [get_ports {led[1]}]
set_property PACKAGE_PIN G17 [get_ports {led[0]}]
上述代码全部经过上板验证,均正确且可正常使用。