集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 10472|回复: 22

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

[复制链接]
lcytms 发表于 2016-11-7 22:02:33 | 显示全部楼层 |阅读模式
FPGA初级课程
第八讲 按键计数(加一或者减一)

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-7 22:04:25 | 显示全部楼层
首先打开《ZX_NO1.pdf》文件,我们看一下四个轻触开关按键的电路图。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-7 22:04:58 | 显示全部楼层
按键计数(加一或者减一),顾名思义,就是指内部有个计数器,按加数键时计数器加一,按减数键时计数器减一。
由于按键有抖动效应,所以需要对按键进行消抖滤波。
为了更直观地观察计数器变化情况,可以用数码管进行数据显示。
所以在完成按键计数驱动逻辑电路的建模与仿真,我们还要结合第六讲的单独按键消抖和第四讲的数码管一起编写一个完整的演示逻辑,并下板查看实际效果。
 楼主| lcytms 发表于 2016-11-7 22:06:07 | 显示全部楼层
首先我们来编写一个按键计数器逻辑,对加一或者减一按键进行计数。
命名逻辑为key_counter。
架构图如下所示。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-7 22:07:29 | 显示全部楼层
加上单独按键消抖模块和数码管模块后,总体架构图如下。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| 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 [23:0] 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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| 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 [23:0] 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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-7 22:17:15 | 显示全部楼层
进行分析综合检查。
进行仿真设置。
查看仿真结果。
模18的加减结果正确无误,初始值为0,加2次变化为0-1-2,减6次变化为2-1-0-17-16-15-14。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| 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 [23:0] data;
       
        output reg [2:0] sel;
        output reg [7:0] seg;
       
        reg clk_1k;
       
        parameter T1ms = 25_000;                //half_width
        reg [19:0] 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 [2:0] state;
        reg [3:0] 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[23:20];
                                                                state <= 1;
                                                        end
                                                       
                                        1        :        begin
                                                                sel <= 3'b001;
                                                                data_temp <= data[19:16];
                                                                state <= 2;
                                                        end
                                                       
                                        2        :        begin
                                                                sel <= 3'b010;
                                                                data_temp <= data[15:12];
                                                                state <= 3;
                                                        end
                                                       
                                        3        :        begin
                                                                sel <= 3'b011;
                                                                data_temp <= data[11:8];
                                                                state <= 4;
                                                        end
                                                       
                                        4        :        begin
                                                                sel <= 3'b100;
                                                                data_temp <= data[7:4];
                                                                state <= 5;
                                                        end
                                                       
                                        5        :        begin
                                                                sel <= 3'b101;
                                                                data_temp <= data[3:0];
                                                                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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| 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 [18:0] 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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-5-21 11:55 , Processed in 0.079203 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表