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位就欧了。

原文地址:https://www.cnblogs.com/Xwangzi66/p/12868802.html