FPGA按键流水灯

该文章介绍了如何使用FPGA实现按键控制四个LED灯的不同效果,如流水灯和闪烁。通过按键状态检测和消抖电路,结合状态机实现不同模式的LED显示。代码中展示了key_debounce模块用于消除按键抖动,key_led模块处理LED显示逻辑。
摘要由CSDN通过智能技术生成

FPGA按键流水灯

1. 要求

使用开发板上的四个按键控制四个LED灯。按下不同的按键时,四个LED灯显示不同效果。

按键状态LED显示效果
无按键按下四个LED全灭
KEY[0]自右向左流水灯
KEY[1]自左向右流水灯
KEY[2]四个LED每隔0.2S同时闪烁
KEY[3]四个LED全亮

2. 按钮说明

开发板上采用的是轻触式按键,没按下时输出高电平,按下时输出低电平。

原理图:

image-20230712164244870

3. 系统框图

image-20230712170030356

4. 代码

4.1 key_led

module key_led 
#(parameter MAX_0_2S = 24'd9_999_999) 
(
    input wire          clk,
    input wire          rst_n,
    input wire [3:0]    key_in,

    output reg [3:0]    led
);


    reg     [23:0]  cnt_0_2s;
    wire            flag_0_2s;
    reg     [1:0]   state;

    //0.2s计数器
    assign flag_0_2s = cnt_0_2s == MAX_0_2S;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt_0_2s <= 24'd0;
        end
        else if (flag_0_2s) begin
            cnt_0_2s <= 24'd0;
        end
        else begin
            cnt_0_2s <= cnt_0_2s + 24'd1;
        end
    end
    
    //状态计数器
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= 2'd0;
        end
        else if (flag_0_2s) begin
            state <= state + 2'd1;
        end
        else begin
            state <= state;
        end
    end

    //根据按键进行状态转换
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            led <= 4'b0000;
        end
        else if (key_in[0]==0) begin
            case (state)
                2'd0: led <= 4'b0001;
                2'd1: led <= 4'b0010;
                2'd2: led <= 4'b0100;
                2'd3: led <= 4'b1000;
                default: led <= 4'b0000;
            endcase
        end
        else if (key_in[1]==0) begin
            case (state)
                2'd0: led <= 4'b1000;
                2'd1: led <= 4'b0100;
                2'd2: led <= 4'b0010;
                2'd3: led <= 4'b0001;
                default: led <= 4'b0000;
            endcase
        end
        else if (key_in[2]==0) begin
            case (state)
                2'd0: led <= 4'b0000;
                2'd1: led <= 4'b1111;
                2'd2: led <= 4'b0000;
                2'd3: led <= 4'b1111;
                default: led <= 4'b0000;
            endcase
        end
        else if (key_in[3]==0) begin
            case (state)
                2'd0: led <= 4'b1111;
                2'd1: led <= 4'b1111;
                2'd2: led <= 4'b1111;
                2'd3: led <= 4'b1111;
                default: led <= 4'b0000;
            endcase
        end
        else begin
		    led <= 4'b0000;//其他情况默认4个led灯全灭
	    end 
    end

endmodule

4.2 key_debounce

//按键消抖
module key_debounce (
    input   wire        clk     ,
    input   wire        rst_n   ,
    input   wire [3:0]  key_in  ,

    output  wire [3:0]  key_out
);
    parameter MAX_20ms = 20'd1_000_000;
    reg     [19:0] cnt_20ms ;
    reg     [3:0]  key_flag ;
    reg            start    ;   // 稳定信号开始
    reg     [3:0]  key_r0   ;  // 按键信号寄存器0
    reg     [3:0]  key_r1   ;  // 按键信号寄存器1
    wire    [3:0]  nedge    ;
    reg     [3:0]  flag     ;

    // 20ms 倒计时计数器设计
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_20ms <= 20'd0;
        end
        else if (nedge) begin
            cnt_20ms <= MAX_20ms;
        end
        else if(start) begin
            if(cnt_20ms == 1'd1)begin
                cnt_20ms <= 20'd0;
            end
            else begin
                cnt_20ms <= cnt_20ms - 1'd1; 
            end
        end
        else if(flag) begin
            cnt_20ms <= MAX_20ms;
        end
        else begin
            cnt_20ms <= cnt_20ms;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            key_r0 <= 4'b1111;
            key_r1 <= 4'b1111;
        end
        else begin
            key_r0 <= key_in;       // 打一拍,同步时钟域
            key_r1 <= key_r0;       // 打一拍,检测按键下降沿 
        end
    end

    // start 信号约束
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            start <= 1'b0;
        end
        else if(nedge) begin
            start <= 1'b1;
        end
        else if(cnt_20ms == 1'b1) begin
            start <= 1'b0;
        end
        else begin
            start <= start;
        end
    end
    // 约束 flag 信号
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            flag <= 4'b0000;
        end
        else if(cnt_20ms == 1'b1) begin
            flag <= ~key_r0;
        end
        else begin
            flag <= 4'b0000;
        end
    end

    assign nedge = ~key_r0 & key_r1;

    assign key_out = flag;
endmodule

4.3 key_led_top

module key_led_top #(parameter MAX_0_2S = 24'd9_999_999) 
(
    input   wire            clk     ,
    input   wire            rst_n   ,
    input   wire    [3:0]   key_in  ,

    output  wire    [3:0]   led
);
    wire    [3:0]   key_out;
    reg     [3:0]   flag;

    //按键状态保存,实现持续按下按钮
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            flag <= 4'b1111;
        end
        else if (key_out[0]) begin
            flag <= 4'b1110;
        end
        else if (key_out[1]) begin
            flag <= 4'b1101;
        end
        else if (key_out[2]) begin
            flag <= 4'b1011;
        end
        else if (key_out[3]) begin
            flag <= 4'b0111;
        end
        else begin
            flag <= flag;
        end
    end

    key_debounce u_key_debounce(
        .clk (clk),
        .rst_n (rst_n),
        .key_in (key_in),

        .key_out (key_out)
    );
    key_led #(.MAX_0_2S (MAX_0_2S)) u_key_led(
        .clk (clk),
        .rst_n (rst_n),
        .key_in (flag),

        .led (led)
    );
endmodule

5. 效果

https://gitee.com/jiyny/photo/raw/master/202307131106346.gif

参考文章

按键控制led灯_单按键控制4个led灯循环点亮

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值