crazybird

【原创】FPGA应用(三)——按键控制led

0
阅读(4580)

一、设计需求

    设计一个按键控制led的功能模块,即一个按键控制一个led。随着每一次按键的按下,led就按照亮、灭交替显示。

二、设计思路

    本次使用的按键为机械弹性开关按键,但由于机械触点的弹性作用,按键闭合时并不能马上接通,同样按键断开时也不能马上断开,故在按键闭合和断开的瞬间均伴随着一连串的抖动,如图1所示。而抖动的时间由按键的机械特性决定,一般为5ms~10ms。为了避免由于按键抖动而引起的误操作,需要对按键进行消抖。

1

图1 按键抖动

    按键消抖包括硬件消抖和软件消抖。当按键数目较少时,可采用硬件消抖如RS触发器,否则将占大面积的PCB;当按键数目较多时,采用软件消抖,利用程序避开按键的抖动期。

    本设计采用软件消抖的方案,即检测按键是否按下,当检测到按键按下时,延时10ms,再检测按键是否真的按下了,若不是真的按下则返回继续检测按键是否按下,若是真的按下了则进行按键按下处理,接着检测按键是否松开,当检测到按键松开时,延时10ms,再检测按键是否真的松开了,若不是真的松开则返回继续检测按键是否松开,若是真的松开了则进行按键松开处理,接着再返回检测按键是否按下,就这样不断的判断按键按下与否和松开与否。根据这种思路,给出按键检测和消抖流程图,如图2所示。

按键检测与消抖

图2 按键检测和消抖流程图

    图3所示为红色飓风E45开发板上按键的电路原理图。从原理图可以看出,按键按下时为低电平,按键断开时为高电平。

2

图3 E45中按键电路原理图

    图4所示为本设计按键控制led的总体框架,由三个模块组成,分别为子模块KEY_Decounce、led_ctrl和顶层模块key_ctrl_led。这里重点介绍按键检测和消抖。图5所示为KEY_Decounce模块中所用到的按键检测与消抖状态机。状态机中有四个状态,分别为IDLE、JITTER1、DEAL和JITTER2。在IDLE状态中检测按键是否按下,若按下即data!=1则跳转到JITTER1状态中延时10ms进行消抖后再判断按键是否真的按下了,若为真即data!=1则跳转到DELA状态中进行按键按下处理,否则即data==1则返回IDLE状态中继续检测按键是否按下,在DEAL状态中除了按键按下处理外还要检测按键是否松开,若检测到按键松开即data==1则跳转到JITTER2状态中延时10ms进行消抖后再判断按键是否真的松开了,若为真即data==1则跳转到IDLE状态继续检测按键是否按下,否则返回DEAL状态中继续判断按键是否松开。

按键控制led

图4 按键控制led

按键检测与消抖状态机

图5 按键检测与消抖状态机

三、设计实现

key_ctrl_led顶层模块:

/**********************************************版权申明*************************************************
**                                   电子技术应用网站, CrazyBird
**                     http://www.chinaaet.com, http://blog.chinaaet.com/crazybird
**
**--------------------------------------------文件信息--------------------------------------------------
** 文件名:          key_ctrl_led.v
** 创建者:          CrazyBird
** 创建日期:        2015-7-12
** 版本号:           v1.0
** 功能描述:        顶层模块将按键消抖模块和led控制模块连接起来,完成按键控制led的功能
**                   
********************************************************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module key_ctrl_led(
    rst_n,
    clk,
    key_data,
    led_data
    );
    //******************************************************************************
    //                                参数定义
    //******************************************************************************
    //  修改以下参数以满足需求
    parameter   CLK_CYCLE = 20;                                        //   时钟周期,单位ns
    //  修改以上参数以满足需求
    
    //******************************************************************************
    //                            输入/输出端口定义
    //******************************************************************************
    input                           rst_n;                             //   全局复位信号,低电平有效
    input                           clk;                               //   全局时钟信号,50MHz
    input                           key_data;                          //   键值输入
    output                          led_data;                          //   led状态
    
    //******************************************************************************
    //                                变量定义   
    //******************************************************************************
    wire                            key_flag;
    
    //******************************************************************************
    //                               模块的连接
    //******************************************************************************
    //  例化KEY_Debounce模块
    KEY_Debounce #(
        .CLK_CYCLE(CLK_CYCLE)
    )
    u_KEY_Debounce (
        .rst_n      (   rst_n       ),
        .clk        (   clk         ),
        .key_data   (   key_data    ),
        .key_flag   (   key_flag    )
    );
    
    //  例化led_ctrl模块
    led_ctrl u_led_ctrl (
        .rst_n      (   rst_n       ),
        .clk        (   clk         ),
        .led_en     (   key_flag    ),
        .led_data   (   led_data    )
    );
    
    //******************************************************************************

endmodule
//*********************************************文件结束*****************************************************

KEY_Debounce模块:

/**********************************************版权申明*************************************************
**                                   电子技术应用网站, CrazyBird
**                     http://www.chinaaet.com, http://blog.chinaaet.com/crazybird
**
**--------------------------------------------文件信息--------------------------------------------------
** 文件名:          KEY_Debounce.v
** 创建者:          CrazyBird
** 创建日期:        2015-7-12
** 版本号:           v1.0
** 功能描述:        该模块主要负责完成按键的检测和消抖
**                   
********************************************************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module KEY_Debounce(
    rst_n,
    clk,
    key_data,
    key_flag
    );
    //******************************************************************************
    //                                参数定义 
    //******************************************************************************
    //  修改以下参数以满足需求
    parameter   CLK_CYCLE = 20;                                        //   时钟周期,单位ns
    parameter   T0        = 10_000_000;                                //   10ms,按键消抖时间
    // parameter   T0        = 1000;                                      //   测试用
    parameter   DELAY     = 19;                                        //   10ms计数器位宽
    //  修改以上参数以满足需求
    
    //  以下参数不要修改
    parameter   T0_VAL = (T0/CLK_CYCLE)-1;                             //   10ms,按键消抖时间
    parameter   IDLE   = 2'b00,
                JITTER1= 2'b01,
                DEAL   = 2'b10,
                JITTER2= 2'b11;
    //  以上参数不要修改
    
    //******************************************************************************
    //                           输入/输出端口定义   
    //******************************************************************************
    input                           rst_n;                             //   全局复位信号,低电平有效
    input                           clk;                               //   全局时钟信号,50MHz
    input                           key_data;                          //   键值输入
    output reg                      key_flag;                          //   按键按下标志位
    
    //******************************************************************************
    //                               变量定义
    //******************************************************************************
    wire                            delay_cnt_done;
    
    //******************************************************************************
    //                      实现按键检测和消抖的状态机
    //******************************************************************************
    reg         [1:0]               state;
    reg                             delay_cnt_en;
    
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n==1'b0)
        begin
            state        <= IDLE;
            delay_cnt_en <= 1'b0;
            key_flag     <= 1'b0;
        end
        else
        begin
            case(state)
                IDLE :
                begin
                    if(key_data!=1'b1)
                    begin
                        state        <= JITTER1;
                        delay_cnt_en <= 1'b1;
                    end
                    else
                        state <= IDLE;
                end
                
                JITTER1 :
                begin
                    if(delay_cnt_done==1'b1)
                    begin
                        delay_cnt_en <= 1'b0;
                        
                        if(key_data!=1'b1)
                        begin
                            state    <= DEAL;
                            key_flag <= 1'b1;
                        end
                        else
                            state <= IDLE;
                    end
                    else
                        state <= JITTER1;
                end
                
                DEAL :
                begin
                    key_flag <= 1'b0;
                    
                    if(key_data==1'b1)
                    begin
                        state        <= JITTER2;
                        delay_cnt_en <= 1'b1;
                    end
                    else
                        state <= DEAL;
                end
                
                JITTER2 :
                begin
                    if(delay_cnt_done==1'b1)
                    begin
                        delay_cnt_en <= 1'b0;
                        
                        if(key_data==1'b1)
                            state <= IDLE;
                        else
                            state <= DEAL;
                    end
                    else
                        state <= JITTER2;
                end
            endcase
        end
    end
    
    //******************************************************************************
    //                               计数器的实现
    //******************************************************************************
    reg         [DELAY-1:0]         delay_cnt;
    
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n==1'b0)
            delay_cnt <= {(DELAY){1'b0}};
        else if(delay_cnt_en==1'b1)
        begin
            if(delay_cnt_done==1'b1)
                delay_cnt <= {(DELAY){1'b0}};
            else
                delay_cnt <= delay_cnt + 1'b1;
        end
        else
            delay_cnt <= {(DELAY){1'b0}};
    end
    assign  delay_cnt_done = (delay_cnt==T0_VAL);
    
    //******************************************************************************

endmodule
//*********************************************文件结束*****************************************************

led_ctrl模块:

/**********************************************版权申明*************************************************
**                                   电子技术应用网站, CrazyBird
**                     http://www.chinaaet.com, http://blog.chinaaet.com/crazybird
**
**--------------------------------------------文件信息--------------------------------------------------
** 文件名:          led_ctrl.v
** 创建者:          CrazyBird
** 创建日期:        2015-7-12
** 版本号:           v1.0
** 功能描述:        该模块根据按键每次按下时将led的状态取反
**                   
********************************************************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module led_ctrl(
    rst_n,
    clk,
    led_en,
    led_data
    );
    //******************************************************************************
    //                               输入/输出端口定义
    //******************************************************************************
    input                           rst_n;                             //   全局复位信号,低电平有效
    input                           clk;                               //   全局时钟信号,50MHz
    input                           led_en;                            //   led状态取反使能信号
    output reg                      led_data;                          //   led状态
    
    //******************************************************************************
    //                              led状态控制
    //******************************************************************************
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n==1'b0)
            led_data <= 1'b0;
        else if(led_en==1'b1)
            led_data <= ~led_data;
        else
            led_data <= led_data;
    end
    
    //******************************************************************************

endmodule
//*********************************************文件结束*****************************************************

modelsim仿真结果:

3

    从仿真结果看,本设计已实现了按键控制led的功能,同时也达到了按键消抖的效果。

    最后对设计进行综合、布局布线、生成bit流文件、下载在红色飓风板子上,然后通过控制led灯的亮与灭。