FPGA--按键按下时长控制LED闪烁模式

通过按键按下的时长使LED闪烁不同的模式

							按下时间		t < 1s,led0闪烁3次;
											1 < t < 2s,led0闪烁10次;
											t > 2s,led0-3闪烁10次。

主程序

module led_control (
    input clk,
    input rst_n,
    input key,

    output [3:0] led
);

reg [2:0] state;
wire flash_done;
reg mode,en;
reg [4:0] times;

reg [31:0] cnt;
reg en_cnt;
wire key_flag,key_state;


//按键消抖
key_filter key_filter1(
			.Clk(clk),      //50M时钟输入
			.Rst_n(rst_n),    //模块复位
			.key_in(key),   //按键输入
			.key_flag(key_flag), //按键标志信号
			.key_state(key_state) //按键状态信号
		);


//控制灯的闪烁
led_flash led_flash1(
    .clk(clk),
    .rst_n(rst_n),

    .mode(mode),     //不同的模式闪烁不同灯的个数
    .en(en),
    .times(times),  //闪烁次数

    .led_out(led),
    .flash_done(flash_done)
);

//按键计时
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt <= 0;
    else if(en_cnt)
        cnt <= cnt + 1'b1;
    else 
        cnt <= 0;
end

//状态机
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        begin
            state <= 0;
            en <= 0;
            times <= 0;
            mode <= 0;
            en_cnt <= 0;
        end
    else 
        begin
            case (state)
                0: begin
                    if(key_flag && !key_state)
                        begin
                            state <= 1;
                            en_cnt <= 1;
                        end
                    else
                        begin
                            state <= 0;
                            en_cnt <= 0;
                        end
                end

                1: begin
                    if(key_flag && key_state)
                        begin
                            en_cnt <= 0;

                            if(cnt < 49999999)
                                state <= 2;
                            else if(cnt >= 49999999 && cnt < 99999999)
                                state <= 3;
                            else
                                state <= 4;
                        end
                    else
                        begin
                            state <= 1;
                            en_cnt <= 1;
                        end
                end

                2: begin
                    if(flash_done)
                        begin
                            en <= 0;
                            state <= 0;
                        end
                    else
                        begin
                            times <= 3;
                            mode <= 0;
                            state <= 2;
                            en <= 1;
                        end
                end

                3: begin
                    if(flash_done)
                        begin
                            en <= 0;
                            state <= 0;
                        end
                    else
                        begin
                            times <= 10;
                            mode <= 0;
                            state <= 3;
                            en <= 1;
                        end
                end

                4: begin
                    if(flash_done)
                        begin
                            en <= 0;
                            state <= 0;
                        end
                    else
                        begin
                            times <= 15;
                            mode <= 1;
                            state <= 4;
                            en <= 1;
                        end
                end

                default: begin
                            state <= 0;
                            en <= 0;
                            times <= 0;
                            mode <= 0;
                            en_cnt <= 0;
                        end
            endcase
        end
end

endmodule

闪灯程序

//led按需求闪烁不同的数量和次数
module led_flash (
    input clk,
    input rst_n,
    input mode,     //不同的模式闪烁不同灯的个数
    input en,
    input [4:0] times,  //闪烁次数

    output reg [3:0] led_out,
    output reg flash_done
);

reg en_cnt;
reg [24:0] cnt; //一次闪烁时长250ms---12499999

reg [6:0]flash_cnt;

parameter s = 25'd12499999;

//闪烁时长计数  一次闪烁时长250ms---12499999
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt <= 0;
    else if(en_cnt)
        begin
            if(cnt == s)
                cnt <= 0;
            else
                cnt <= cnt + 1'b1;
        end
    else
        cnt <= 0;
end


//对闪烁次数进行计数
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        flash_cnt <= 0;
    else if(en)
        begin
            if(cnt == s)
                flash_cnt <= flash_cnt + 1'b1;
            else
                flash_cnt <= flash_cnt;
        end
    else
        flash_cnt <= 0;
end


//根据模式使不同的灯进行闪烁
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        led_out <= 4'b1111;
    else if(!mode)
        begin
            if(cnt == s)
                led_out[0] <= ~led_out[0];
            else
                led_out[0] <= led_out[0];
        end
    else
        begin
            if(cnt == s)
                led_out[3:0] <= ~led_out[3:0];
            else
                led_out[3:0] <= led_out[3:0];
        end
end


//根据闪烁次数完成情况 使能计数和输出结束标志位
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        begin
            flash_done <= 0;
            en_cnt <= 0;
        end
    else if(en)
        begin
            if(flash_cnt < times*2)
                begin
                    flash_done <= 0;
                    en_cnt <= 1;
                end
            else
                begin
                    flash_done <= 1;
                    en_cnt <= 0;
                end
        end
    else 
        begin
            flash_done <= 0;
            en_cnt <= 0;
        end 
end

endmodule

按键消抖

module key_filter(
			Clk,      //50M时钟输入
			Rst_n,    //模块复位
			key_in,   //按键输入
			key_flag, //按键标志信号
			key_state //按键状态信号
		);

	input Clk;
	input Rst_n;
	input key_in;
	
	output reg key_flag;
	output reg key_state;
	
	localparam
		IDEL		= 4'b0001,
		FILTER0		= 4'b0010,
		DOWN		= 4'b0100,
		FILTER1 	= 4'b1000;
		
	reg [3:0]state;
	reg [19:0]cnt;
	reg en_cnt;	//使能计数寄存器
	
//对外部输入的异步信号进行同步处理
	reg key_in_sa,key_in_sb;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_in_sa <= 1'b0;
		key_in_sb <= 1'b0;
	end
	else begin
		key_in_sa <= key_in;
		key_in_sb <= key_in_sa;	
	end
	
	reg key_tmpa,key_tmpb;
	wire pedge,nedge;
	reg cnt_full;//计数满标志信号
	
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_tmpa <= 1'b0;
		key_tmpb <= 1'b0;
	end
	else begin
		key_tmpa <= key_in_sb;
		key_tmpb <= key_tmpa;	
	end

//产生跳变沿信号	
	assign nedge = !key_tmpa & key_tmpb;
	assign pedge = key_tmpa & (!key_tmpb);
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		en_cnt <= 1'b0;
		state <= IDEL;
		key_flag <= 1'b0;
		key_state <= 1'b1;
	end
	else begin
		case(state)
			IDEL :
				begin
					key_flag <= 1'b0;
					if(nedge)begin
						state <= FILTER0;
						en_cnt <= 1'b1;
					end
					else
						state <= IDEL;
				end
					
			FILTER0:
				if(cnt_full)begin
					key_flag <= 1'b1;
					key_state <= 1'b0;
					en_cnt <= 1'b0;
					state <= DOWN;
				end
				else if(pedge)begin
					state <= IDEL;
					en_cnt <= 1'b0;
				end
				else
					state <= FILTER0;
					
			DOWN:
				begin
					key_flag <= 1'b0;
					if(pedge)begin
						state <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						state <= DOWN;
				end
			
			FILTER1:
				if(cnt_full)begin
					key_flag <= 1'b1;
					key_state <= 1'b1;
					state <= IDEL;
					en_cnt <= 1'b0;
				end
				else if(nedge)begin
					en_cnt <= 1'b0;
					state <= DOWN;
				end
				else
					state <= FILTER1;
			
			default:
				begin 
					state <= IDEL; 
					en_cnt <= 1'b0;		
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
				
		endcase	
	end
	

	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt <= 20'd0;
	else if(en_cnt)
		cnt <= cnt + 1'b1;
	else
		cnt <= 20'd0;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt_full <= 1'b0;
	else if(cnt == 20'd999_999)
		cnt_full <= 1'b1;
	else
		cnt_full <= 1'b0;	

endmodule

仿真文件

`timescale 1ns/1ns
`define clock_period 20

module led_control_tb;

reg clk;
reg rst_n;
reg key;
reg [15:0]myrand;
wire [3:0]led;

initial clk = 1;
always #(`clock_period/2) clk = ~clk;

led_control led_control(
    .clk(clk),
    .rst_n(rst_n),
    .key(key),

    .led(led)
);


initial begin
    rst_n = 0;
    key = 1;
    #(`clock_period *10)
    rst_n = 1;
    #(`clock_period *11)
    press_key(39999999);

    $stop;
end

task press_key;
    input [31:0] press_time;
    begin
        key = 0;
        #press_time;
        
        key = 1;
        #press_time;		
    end	
endtask

endmodule

实现效果:

按键按下时长控制LED闪烁模式

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值