zoukankan      html  css  js  c++  java
  • 08按键消抖之驱动流水灯

    一设计功能

       (一)实验现象: 在赛灵思的开发板上,按键每按下一次,四个LED灯向左移位一次实现流水灯效果。

        (二)知识点:按键消抖,移位。按键按下与释放,首先得把按键的完整过程分为下降沿和上升沿,下降沿与上升沿都得维持10ms,才能看作真正的按下与释放。否则为抖动。移位分成左移和右移,实现方式有两种,位拼接符和移位运算符。我个人喜欢移位拼接符实现,相较于运算符少了最高位溢出全为零的情况。

        (三)系统设计框图

    二设计输入

          (一)顶层模块实现按键消抖和LED两个模块的连接和最终的端口定义

        

    //top modue to link all module by inst

    module top(

    input wire  clk,

    input wire  Rst,

    input wire  key,

    output wire [3:0]   led

    );

     

    wire key_flag;

    //例化按键消抖

    key_filter key_filterm0

    (

        .clk(clk),

        .Rst(Rst),

        .Key1(key),

        .Pin_out(key_flag)

    );

    //例化流水灯

        Water_led inst_Water_led

        (

        .clk(clk),

        .Rst(Rst),

        .shift_en(key_flag),

        .led(led));

     

    endmodule

          (二)按键消抖模块

    按键消抖分为,边沿检测模块,按键按下与释放及其消抖的状态机模块。边沿检测,两级寄存器实现了按键的下降沿和上升沿检测。按键的状态机模块:一开始按键处于初始状态,当检测到下降沿到来时,进入按下消抖状态:若按下时间超过10ms当作真正的按下,并产生一个按下的标志信号。若没计满10ms就来了上升沿,则为抖动滤除。若没有前面两种情况则计数直到10ms产生按下标志信号进入下一个状态。按键低电平状态:就等待按键的上升沿到来,进入按键释放状态。按键释放状态:与按下消抖状态相似,只是滤除抖动后,不会产生标志信号,且进入初始状态。

    module key_filter

    (

        clk,

        Rst,

        Key1,

        Pin_out

    );

        input clk;

        input Rst;

        input Key1;             //

        output Pin_out;         //the output of key,when the Key1==1(means press)

        //the output of key,when the Key1==0(means release)

       

        //be careful the binary(二进刍

        localparam

            IDEL = 4'b0001,     //the idel state

            FILTER0 = 4'b0010,  //first filter(key from 1 to 0)

            DOWN = 4'b0100,     //when the Key1==0

            FILTER1 = 4'b1000;  //second filter(key from 0 to 1)

       

        reg H2L_F1;                 //first reg(store the value of key from 1 to 0,press)

        reg H2L_F2;

        reg L2H_F1;                 //first reg(store the value of key from 0 to 1,press)

        reg L2H_F2;

        //the clasic edge detection(边沿检浍

        always@(posedge clk or negedge Rst)

        if(!Rst)

            begin

                H2L_F1<=1'b1;

                H2L_F2<=1'b1;

              L2H_F1<=1'b0;

                L2H_F2<=1'b0;

            end

        else    begin

                H2L_F1<=Key1;

                H2L_F2<=H2L_F1;

              L2H_F1<=Key1;

                L2H_F2<=L2H_F1;

            end

           

            wire nedge,podge;

           

            assign nedge = !H2L_F1 & H2L_F2;//the negedge of key

            assign podge = L2H_F1 & !L2H_F2;//the posedge of key

           

            parameter T10MS = 19'd500_000-1;

            reg [18:0]delay_cnt;

            reg [3:0]state;

            reg Pin_out;

           

            always@(posedge clk or negedge Rst)

            if(!Rst)begin

            state<=IDEL;

            delay_cnt<=19'd0;

            Pin_out<=1'b0;

            end

            else    begin

                case(state)

                    IDEL:begin

                        delay_cnt<=19'd0;

                        if(!H2L_F1 & H2L_F2)

                            state<=FILTER0;

                        else

                            state<=IDEL;

                    end

                    FILTER0:begin

                       

                            if((delay_cnt==T10MS) )begin

                               state<=DOWN;

                                Pin_out<=1'b1;

                                delay_cnt<=19'd0;

                            end

                            else if(podge)

                                state<=IDEL;

                            else

                                delay_cnt<=delay_cnt+1'b1;

                           

                       

                    end

                    DOWN:begin

                       

                        Pin_out<=1'b0;

                        if(L2H_F1 & !L2H_F2)

                            state<=FILTER1;

                        else

                            state<=DOWN;

                    end

                    FILTER1:begin

                   

                        if((delay_cnt==T10MS) )begin

                               state<=IDEL;

                                Pin_out<=1'b0;

                                delay_cnt<=delay_cnt;

                            end

                            else if(nedge)

                                state<=DOWN;

                            else

                                delay_cnt<=delay_cnt+1'b1;

                           

                        end

                   

                    default:state<=IDEL;

                endcase

               

            end

           

    endmodule

            (三)流水灯

              按键按下产生一个标志信号,作为LED灯的输入,驱动led向左移位一次。不断按下就会实现流水灯效果。

    module Water_led(

    input wire clk,

    input wire Rst,

    input wire shift_en,

    output reg [3:0]led

        );

    //shift

    //way1:left shift by {led[2:0],led[3]};

    //way2:led<=led<<1;

    always@(posedge clk or negedge Rst)

    if(!Rst)begin

    led<=4'b0001;

    end

    else if(shift_en)begin

     led<={led[2:0],led[3]};

     end

     else begin

        led<=led;

     end

    endmodule

     

          三仿真

              仿真设计,刚开始产生几次机械抖动,然后再模仿真正的按下一次,看抖动是否被滤除,看看LED灯是否向左移位一次。

    `timescale 1ns/1ns

    `define clk_period 20

     

    module top_tb();

    reg clk;

    reg Rst;

    reg key;

    wire [3:0]led;

    top inst_top

     (

        .clk(clk),

        .Rst(Rst),

         .key(key),

         .led(led)

         );

    initial clk = 1;

    always#(`clk_period/2) clk =~clk;

    initial begin

        Rst = 0;

        key = 0;

        #(`clk_period*300);

        Rst = 1;key = 1;

        #({$random}%65536) key =0;

        #({$random}%65536) key =1;

        #({$random}%65536) key =0;

        #({$random}%65536) key =1;

        #({$random}%65536) key =0;

        #({$random}%65536) key =1;

        #(`clk_period*600000);key =0;

        #(`clk_period*600000);key =1;

        #(`clk_period*500001);key =0;

        #(`clk_period*30);Rst = 0;#(`clk_period*300);

        $stop;

    end

    endmodule

     

    通过波形图,机械抖动都没有产生按下的标志信号,且LED灯没有左移。在按键真正按下时,产生了一个周期的按下标志信号,并且驱动LED左移一次。

          四总结

    在ISE14.7编译时曾出现了一次警告如下:

    delay_cnt_19> (without init value) has a constant value of 0 in block <top>. This FF/Latch will be trimmed during the optimization process.

    报错为:在按键消抖模块的寄存器变量delay_cnt的第19位一直为零,综合时会把它优化了,就没了。

    解决方法:直接把原先的delay_cnt 20位的位宽改为19位就欧了。

  • 相关阅读:
    MS Office CVE-2015-1641 恶意 Exploit 样本分析
    Qbot回归,已感染5.4万台计算机
    工具推荐:Backdoor-apk,安卓APK文件后门测试工具
    安卓微信、QQ自带浏览器 UXSS 漏洞
    延迟注入工具(python)
    小白欢乐多——记ssctf的几道题目
    使用转义防御XSS
    富文本存储型XSS的模糊测试之道
    k8s故障总结
    CentOS7.6部署k8s环境
  • 原文地址:https://www.cnblogs.com/Xwangzi66/p/12868802.html
Copyright © 2011-2022 走看看