lcytms 发表于 2016-11-7 22:02:33

FPGA初级课程第八讲 按键计数(加一或者减一)

FPGA初级课程
第八讲 按键计数(加一或者减一)

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:按键计数(加一或者减一)。
本节课我先简要地介绍一下按键计数的物理原理,然后实际演示一下按键计数驱动逻辑电路的建模与仿真。
最后结合第六讲的单独按键消抖和第四讲的数码管一起编写一个完整的演示逻辑,并下板查看效果。

lcytms 发表于 2016-11-7 22:04:25

首先打开《ZX_NO1.pdf》文件,我们看一下四个轻触开关按键的电路图。

lcytms 发表于 2016-11-7 22:04:58

按键计数(加一或者减一),顾名思义,就是指内部有个计数器,按加数键时计数器加一,按减数键时计数器减一。
由于按键有抖动效应,所以需要对按键进行消抖滤波。
为了更直观地观察计数器变化情况,可以用数码管进行数据显示。
所以在完成按键计数驱动逻辑电路的建模与仿真,我们还要结合第六讲的单独按键消抖和第四讲的数码管一起编写一个完整的演示逻辑,并下板查看实际效果。

lcytms 发表于 2016-11-7 22:06:07

首先我们来编写一个按键计数器逻辑,对加一或者减一按键进行计数。
命名逻辑为key_counter。
架构图如下所示。

lcytms 发表于 2016-11-7 22:07:29

加上单独按键消抖模块和数码管模块后,总体架构图如下。

lcytms 发表于 2016-11-7 22:08:21

本帖最后由 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:12:32

本帖最后由 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

lcytms 发表于 2016-11-7 22:17:15

进行分析综合检查。
进行仿真设置。
查看仿真结果。
模18的加减结果正确无误,初始值为0,加2次变化为0-1-2,减6次变化为2-1-0-17-16-15-14。

lcytms 发表于 2016-11-7 22:18:15

本帖最后由 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:21:00

本帖最后由 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
页: [1] 2 3
查看完整版本: FPGA初级课程第八讲 按键计数(加一或者减一)