FPGA入门实验-基于状态机实现多按键控制变速流水灯和跳变灯

功能描述

通过按键控制不同样式的跑马灯。要求:

1.除时钟和复位外,另外有2个KEY和4个LED;

⒉.总共实现两种样式的跑马灯:经典跑马灯和交替显示LED(1、3亮2、4灭,1、3灭2、4亮。)

3.其中一个按键控制跑马灯样式切换,每按一次切换一种样式。

4.另外一个按键控制跑马灯的速度,间隔包括0.5s、1s、2s、5s这4种,每按一次按键就切换一种速度。

代码实现

话不多说,状态机这东西,多看看代码就会了。具体的实现逻辑,看代码也很容易理解。

本程序只用了三个状态实现功能。

上代码!

按键模块key.v:

module key(
    input           sysclk,
    input           rst_n,
    input           key,
    output          reg key_flag
    );
    parameter DELAY = 250_000_0;//计时20ms
    reg[31:0] cnt;
    
    //------------计时模块-----------------------
    always@(posedge sysclk)
        if(!rst_n)
            cnt <= 32'd0;
        else if(key)begin
            if(cnt >= DELAY)
                cnt <= cnt;
            else
                cnt <= cnt +32'd1;
        end
        else
            cnt = 32'd0;
     //------------------key_falg------------------------
     always@(posedge sysclk)
        if(!rst_n)
            key_flag <= 0;
        else if(cnt == DELAY-1)
            key_flag <= 1;
        else
            key_flag <= 0;      
            
endmodule

顶层文件top.v:

module top(
    input                   sysclk,
    input                   rst_n,
    input                   key1,
    input                   key2,
    output  reg     [3:0]   led
    );
    wire key_flag1;
    wire key_flag2;
    reg[3:0]    led_water;
    reg[3:0]    led_jump;
    reg[31:0]   timer;
	reg[31:0]	timedelay;	//计时0.5s  1s  2s   5s
	reg[2:0]	dt;	// 时间档位
	
	parameter IDLE  = 2'd0,//空闲状态
              WATER = 2'd1,//流水灯状态
              JUMP  = 2'd2;//跳转灯状态
	
	reg [1:0] cur_state;//当前状态
    reg [1:0] next_state;//下一状态
    
    // 按键消抖实例化
    key key_1(
        .sysclk     (sysclk),
        .rst_n      (rst_n),
        .key        (key1),
        .key_flag   (key_flag1)
    );
        
    key key_2(
        .sysclk     (sysclk),
        .rst_n      (rst_n),
        .key        (key2),
        .key_flag   (key_flag2)
    );
	
	//计时
    always@(posedge sysclk)
        if(!rst_n)
            timer <= 32'd0;
        else if(timer >=timedelay-32'd1)
            timer <= 32'd0;
        else
            timer <= timer + 32'd1;
    
    //流水灯
    always@(posedge sysclk)
        if(!rst_n)
            led_water <= 4'b0001;
        else if(timer >= timedelay-1 && cur_state == WATER)
            led_water <= {led_water[2:0],led_water[3]};
        else
            led_water <= led_water;
     
     //跳转灯
    always@(posedge sysclk)
        if(!rst_n)
            led_jump <= 4'b1010;
        else if(timer >= timedelay-1 && cur_state == JUMP)
            led_jump <= ~led_jump;
        else
            led_jump <= led_jump;
	
	/* state1 状态切换,时序逻辑 */
    always@(posedge sysclk)
        if(!rst_n)
            cur_state <= IDLE;
        else
            cur_state <= next_state;
	
	/* state2(根据当前状态和条件确定下一状态,组合逻辑) */
	always@(posedge key_flag1)begin
		next_state = IDLE;
		case(cur_state)
		IDLE:begin
			if(key_flag1)
				next_state = WATER;
			end
		WATER:begin
			if(key_flag1)
				next_state = JUMP;
            end
        JUMP:begin
			if(key_flag1)
				next_state = WATER;
            end
		default:next_state = IDLE;
		endcase
	end
	
	/* state3(根据状态确定输出,时序逻辑) */      
    always@(posedge sysclk)
        if(!rst_n)begin
            led <= 4'b0000;
            dt <= 3'd0;
        end
        else begin
            case(next_state)
                IDLE:begin
                    led <= led;
                    dt <= 3'd0;
                end
                
                WATER:begin
                    led <= led_water;
                    if(key_flag2)
                        if(dt >= 3'd3)
                            dt <= 3'd0;
                        else
                            dt <= dt + 1;
                    else
                        dt <= dt;
                end
                
                JUMP:begin
                    led <=  led_jump;
                    if(key_flag2)
                        if(dt >= 3'd3)
                            dt <= 3'd0;
                        else
                            dt <= dt + 1;
                    else
                        dt <= dt;
                end
                
                default:led <= led;
            endcase
            case(dt)
            3'd0:begin
                timedelay<= 32'd62_500_000;
                end
            3'd1:begin
                timedelay<= 32'd125_000_000;
                end
            3'd2:begin
                timedelay<= 32'd250_000_000;
                end
            3'd3:begin
                timedelay<= 32'd625_000_000;
                end
            default:timedelay <= 32'd62_500_000;
            endcase
		end
endmodule

结语

大部分入门的同学可能会用9状态来解决这个题目,不过代码量就多了。个人不建议。

  • 4
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星羽空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值