要求:
1.未按建则所有LED全黑;
2.按K1按钮,则用前8个LED灯二进制显示25;
3.按K2按钮,则12只LED合并显示流水灯效果,3个LED点亮并向右流水。
注:是HR-240B FPGA 创新实验系统,其核心板的核心芯片为 EPM240T100C5N 。
分析:
LED是共阴极,所以点亮LED需要高电平;
有两个按键K1和K2,所以需要按键消抖;
按下K1,用前8个LED显示二进制25,也就是00011001;
按下K2,用12个LED灯,3个LED灯点亮,向右流水,也就是{111_000000000}循环右移。
系统时钟是50MHz,
整个程序,除了按键消抖有点需要思考,其他还是很简单实现的。
系统时钟50MHz,也就是周期为20ns,按键抖动时间一般为15ms,如下图(按键未按下时为高电平,按下后为低电平):
但是,在按键按下或者释放的时候都会出现一个不稳定的抖动时间,如果不处理好这个抖动时间,我们就无法正确采集到正确有效的按键值,所以我们的设计中必须有效消除按键抖动。
消除按键抖动的原理是检测到按键值变化后,不能立即采样,而是需要计数15ms之后采样按键值。
根据上述分析,给出Verilog设计代码:
单个按键消抖模块:
module One_key (
input clk, // Clock
input rst_n, // Asynchronous reset active low
input key_in1,
output reg key_out1
);
reg [19 : 0] count;
reg key_in1_r;
reg key_in1_rr;
//对按键值进行两拍寄存,为了后面检测按键变化
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
key_in1_r <= 1;
key_in1_rr <= 1;
end
else begin
key_in1_r <= key_in1 ;
key_in1_rr <= key_in1_r;
end
end
wire edge_l, edge_h;
assign edge_h = ~key_in1_rr & key_in1_r; //上升沿检测
assign edge_l = ~key_in1_r & key_in1_rr; //下降沿检测
//按键值变化后,edge_en有效
wire edge_en;
assign edge_en = edge_l | edge_h;
reg [19 : 0] cnt;
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
cnt <= 0;
end
else if(edge_en) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
key_out1 <= 1;
end
else if(cnt == 20'd7000_000) begin
key_out1 <= key_in1;
end
else ;
end
endmodule
在下面模块中例化按键消抖模块:
module Key_Ctrl_Led (
input clk, // Clock
input rst_n, // Asynchronous reset active low
input [1 : 0] key_in, //key_in[0] represents k1, key_in[1] represents k2;
output [11 : 0] led //led[0] represents first led,...
);
wire [1 : 0] key_out;
One_key inst_One_key1 (.clk(clk), .rst_n(rst_n), .key_in1(key_in[0]), .key_out1(key_out[0]));
One_key inst_One_key2 (.clk(clk), .rst_n(rst_n), .key_in1(key_in[1]), .key_out1(key_out[1]));
reg [1 : 0] mode;
reg [11 : 0] led_reg;
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
mode <= 0;
end
else if(~key_out[0]) begin
mode <= 2'b01;
end
else if(~key_out[1]) begin
mode <= 2'b10;
led_reg <= 12'b1110_0000_0000;
end
else ;
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
led_reg <= 0;
end
else if(mode == 2'b01) begin
led_reg <= 12'b0000_10011000; //(前8个灯显示25,也即00011001,led灯的约束按照大对大,小对小)
end
else if(mode == 2'b10) begin
led_reg <= {led_reg[0],led_reg[11:1]};
end
end
assign led = led_reg;
endmodule
思路是这样子的,很简单,但是由于时间原因还未上板子验证,请自行验证。
引脚约束按照高对高,低对低约束。
注意,这里的复位采用的是低电平复位,如果你的板子是高电平复位,需要稍微修改下代码。