FPGA初级课程第八讲 按键计数(加一或者减一)
FPGA初级课程第八讲 按键计数(加一或者减一)
Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:按键计数(加一或者减一)。
本节课我先简要地介绍一下按键计数的物理原理,然后实际演示一下按键计数驱动逻辑电路的建模与仿真。
最后结合第六讲的单独按键消抖和第四讲的数码管一起编写一个完整的演示逻辑,并下板查看效果。
首先打开《ZX_NO1.pdf》文件,我们看一下四个轻触开关按键的电路图。
按键计数(加一或者减一),顾名思义,就是指内部有个计数器,按加数键时计数器加一,按减数键时计数器减一。
由于按键有抖动效应,所以需要对按键进行消抖滤波。
为了更直观地观察计数器变化情况,可以用数码管进行数据显示。
所以在完成按键计数驱动逻辑电路的建模与仿真,我们还要结合第六讲的单独按键消抖和第四讲的数码管一起编写一个完整的演示逻辑,并下板查看实际效果。
首先我们来编写一个按键计数器逻辑,对加一或者减一按键进行计数。
命名逻辑为key_counter。
架构图如下所示。
加上单独按键消抖模块和数码管模块后,总体架构图如下。 本帖最后由 lcytms 于 2016-11-7 22:11 编辑
先从按键计数模块key_counter.v做起吧!
新建工程文件夹key_counter。
新建key_counter.v文件。
module key_counter (clk, rst_n, key1, key2, data);
input clk, rst_n;
input key1, key2;
output reg data;
parameter CNT_NUM = 24'd32; //count 0~31, or 00~1F
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
data <= 0;
end
else
begin
if (key1 && key2)
data <= data;
else
begin
if(!key1)
begin
if (data < CNT_NUM - 1)
data <= data + 24'b1;
else
data <= 0;
end
else
begin
if (data > 0)
data <= data - 24'b1;
else
data <= CNT_NUM - 24'b1;
end
end
end
end
endmodule
本帖最后由 lcytms 于 2016-11-7 22:15 编辑
进行分析综合检查。
编写Testbench。
新建key_counter_tb.v文件。
`timescale 1ns/1ps
module key_counter_tb;
reg clk, rst_n;
reg key1, key2;
wire data;
key_counter #(.CNT_NUM(18))
dut (.clk(clk), .rst_n(rst_n), .key1(key1), .key2(key2), .data(data));
initial
begin
clk = 1;
rst_n = 0;
key1 = 1;
key2 = 1;
#200.1
rst_n = 1;
#40
key1 = 0; #20 key1 = 1; #20 // +1
key1 = 0; #20 key1 = 1; #20 // +1
key2 = 0; #20 key2 = 1; #20 // -1
key2 = 0; #20 key2 = 1; #20 // -1
key2 = 0; #20 key2 = 1; #20 // -1
key2 = 0; #20 key2 = 1; #20 // -1
key2 = 0; #20 key2 = 1; #20 // -1
key2 = 0; #20 key2 = 1; #20 // -1
#200 $stop;
end
always #10 clk = ~clk;
endmodule
进行分析综合检查。
进行仿真设置。
查看仿真结果。
模18的加减结果正确无误,初始值为0,加2次变化为0-1-2,减6次变化为2-1-0-17-16-15-14。
本帖最后由 lcytms 于 2016-11-7 22:19 编辑
向工程文件夹添加第四讲的数码管模块seg7.v。
module seg7 (clk, rst_n, data, sel, seg);
input clk, rst_n;
input data;
output reg sel;
output reg seg;
reg clk_1k;
parameter T1ms = 25_000; //half_width
reg count;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
count <= 0;
clk_1k <= 1;
end
else
begin
if (count < T1ms - 1)
begin
count <= count + 20'b1;
end
else
begin
count <= 0;
clk_1k <= ~clk_1k;
end
end
end
reg state;
reg data_temp;
always @ (posedge clk_1k or negedge rst_n)
begin
if (!rst_n)
begin
sel <= 3'b000;
state <= 0;
end
else
begin
case (state)
0 : begin
sel <= 3'b000;
data_temp <= data;
state <= 1;
end
1 : begin
sel <= 3'b001;
data_temp <= data;
state <= 2;
end
2 : begin
sel <= 3'b010;
data_temp <= data;
state <= 3;
end
3 : begin
sel <= 3'b011;
data_temp <= data;
state <= 4;
end
4 : begin
sel <= 3'b100;
data_temp <= data;
state <= 5;
end
5 : begin
sel <= 3'b101;
data_temp <= data;
state <= 0;
end
default : state <= 0;
endcase
end
end
always @ (*)
begin
if (!rst_n)
begin
seg = 8'b1111_1111; //null
end
else
begin
case (data_temp)
0 : seg = 8'b1100_0000; //d0
1 : seg = 8'b1111_1001; //d1
2 : seg = 8'b1010_0100; //d2
3 : seg = 8'b1011_0000; //d3
4 : seg = 8'b1001_1001; //d4
5 : seg = 8'b1001_0010; //d5
6 : seg = 8'b1000_0010; //d6
7 : seg = 8'b1111_1000; //d7
8 : seg = 8'b1000_0000; //d8
9 : seg = 8'b1001_0000; //d9
10 : seg = 8'b1000_1000; //dA
11 : seg = 8'b1000_0011; //db
12 : seg = 8'b1100_0110; //dC
13 : seg = 8'b1010_0001; //dd
14 : seg = 8'b1000_0110; //dE
15 : seg = 8'b1000_1110; //dF
default : seg = 8'b1111_1111; //null
endcase
end
end
endmodule
本帖最后由 lcytms 于 2016-11-7 22:22 编辑
向工程文件夹添加第六讲的单独按键消抖模块key_flag.v。
module key_flag (clk, rst_n, key_n, key_out);
input clk, rst_n;
input key_n;
output key_out;
reg click_n;
parameter MASK_TIME = 500_000; // 10ms/20ns=500_000,for checking key hold time
reg cnt;
reg state;
localparam s0 = 1'b0,
s1 = 1'b1;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
cnt <= 0;
click_n <= 1;
state <= s0;
end
else
begin
case (state)
s0 : begin
if (key_n)
begin
cnt <= 0;
click_n <= 1;
state <= s0;
end
else
begin
if (cnt < MASK_TIME - 1)
begin
cnt <= cnt + 19'b1;
state <= s0;
end
else
begin
cnt <= 0;
click_n <= 0;
state <= s1;
end
end
end
s1 : begin
if (!key_n)
begin
cnt <= 0;
click_n <= 0;
state <= s1;
end
else
begin
if (cnt < MASK_TIME - 1)
begin
cnt <= cnt + 19'b1;
state <= s1;
end
else
begin
cnt <= 0;
click_n <= 1;
state <= s0;
end
end
end
default : state <= s0;
endcase
end
end
reg click_r_n;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
click_r_n <= 1;
else
click_r_n <= click_n;
end
assign key_out = click_r_n & ~click_n;
endmodule