led流水灯仿真实现

1、LED灯

LED灯就是发光二极管,二极管在正向电压作用下电阻很小,处于导通状态,相当于一只接通的开关;在反向电压作用下,电阻很大,处于截止状态,如同一只断开的开关。发光二极管在导通的时候发光,在没有导通的时候不发光。
模块设计
led流水灯仿真实现_第1张图片
由上图可以看出有四个led灯,FPGA输出高电平时,LED点亮;FPGA输出低电平时,LED熄灭。输入信号分别为时钟信号和复位信号,设计一个计时器。每0.2s改变四个led的状态,同一时刻下只能有一只led亮,其余的led灭。最后通过移位寄存器输出信号给四个led灯。

2、建立工程

led流水灯仿真实现_第2张图片
在rtl路径下新建fsm_led.v代码文件

module fsm_led#(parameter TIME_1S = 50_000_000)(
    input  wire         clk     ,
    input  wire         rst_n   ,
    output reg  [3:0]   led      
);

    parameter   IDLE = 5'b00001,   // 宏定义 定义状态
                S1   = 5'b00010,
                S2   = 5'b00100,
                S3   = 5'b01000,
                S4   = 5'b10000;
    
    wire        idle2s1 ; // 2 -> to  状态跳转条件
    wire        s12s2   ;
    wire        s22s3   ;
    wire        s32s4   ;
    wire        s42idle ;

    reg     [4:0]   state_n ; // 次态  状态寄存器
    reg     [4:0]   state_c ; // 现态

    // parameter TIME_1S = 50_000_000; //计数1s

    reg     [25:0]  cnt     ; //计数1s计数器
    wire            add_cnt ; //计数器 开始或加一的条件
    wire            end_cnt ; // 计数器 结束的条件

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt <= 26'd0;
        end
        else if(add_cnt)begin  //加1条件有效的时候
            if(end_cnt)begin  //计数到了最大值
                cnt <= 26'd0;
            end
            else begin  
                cnt <= cnt + 1'd1;
            end
        end
        else begin  //默认保持不变
            cnt <= cnt ;
        end
    end

    assign add_cnt = 1'b1;
    assign end_cnt = add_cnt && cnt == TIME_1S - 1;  // 1 && 1  = 1  1 && 0 = 0

    //状态机的第一段  时序逻辑
    always @(posedge clk or negedge rst_n)begin  
        if(!rst_n)begin
            state_c <= IDLE;  //复位状态处于 空闲状态
        end
        else begin
            state_c <= state_n; // 下一个时钟周期到来的时候 就把次态的值 赋予给我们的现态
        end
    end

    // 状态机的第二段  组合逻辑  state_n  只在第二段状态机里面用
    always @(*)begin  // *代表的意思是 里面所有的敏感信号 我都不在意 
        case(state_c)
        IDLE : begin 
            if(idle2s1)
                state_n = S1;
            else 
                state_n = state_c;
        end
        S1   : begin
            if(s12s2)
                state_n = S2;
            else 
                state_n = state_c;
        end
        S2   : begin
            if(s22s3)
                state_n = S3;
            else 
                state_n = state_c;
        end
        S3   : begin
            if(s32s4)
                state_n = S4;
            else 
                state_n = state_c;
        end
        S4   : begin
            if(s42idle)
                state_n = IDLE;
            else 
                state_n = state_c;
        end
        default : state_n = state_c;
        endcase
    end

    assign idle2s1  = state_c == IDLE && end_cnt; //1s计数完了 在IDLE情况下 就满足跳转条件 end_cnt == 五千万减一 到了最大值就跳转
    assign s12s2    = state_c == S1   && end_cnt;
    assign s22s3    = state_c == S2   && end_cnt;
    assign s32s4    = state_c == S3   && end_cnt;
    assign s42idle  = state_c == S4   && end_cnt;

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            led <= 4'b1001;
        end  
        else if(state_c == IDLE)begin
            led <= 4'b0000;
        end
        else if(state_c == S1)begin
            led <= 4'b0001;
        end
        else if(state_c == S2)begin
            led <= 4'b0010;
        end
        else if(state_c == S3)begin
            led <= 4'b0100;
        end
        else if(state_c == S4)begin
            led <= 4'b1000;
        end
        else begin
            led <= led;
        end
    end

endmodule

由代码可以看出,clk为50MHz,1s设置五千万信号,每个信号20ns,使用计数器当做计时器,每记录一个数字等于过去一个时钟周期,从0开始计数,所以计数器只需要记录到50_000_000-1即可,定义了一个26位的计数器cnt。

设置IDLE,S1 ,S2 ,S3 ,S4这几个状态,IDLE表示空闲状态, 当led输出为4’b0001时,第一个led点亮;经过1秒钟,输出4’b0010时,第二个led点亮;经过1秒钟,输出4’b0100时,第三个led点亮;经过1秒钟,输出4’b1000时,第四个led点亮;经过1秒钟,输出4’b0001时,第一个led点亮······按照上述的过程周而复始,就形成了流水灯。
仿真代码

`timescale 1ns/1ns  //仿真尺度
module tb_fsm(); 

    reg         tb_clk  ;//时钟信号
    reg         tb_rst_n;//复位信号
    wire [3:0]  tb_led  ;//4个led灯

    fsm_led#(.TIME_1S(50)) u_fsm_led(
        .clk    (tb_clk     ) ,
        .rst_n  (tb_rst_n   ) ,
        .led    (tb_led     )  
    );

    parameter CYCLE = 20;
    always #(CYCLE / 2) tb_clk = ~tb_clk;//每10ns翻转一次时钟信号

    initial begin
        tb_clk = 1'b0;
        tb_rst_n = 1'b0;
        #(CYCLE * 3);
        tb_rst_n = 1'b1;
        #(CYCLE * 500);//500次循环后停止
        $stop;
    end

endmodule

3、实现

使用Quartus建立工程后,如下图
led流水灯仿真实现_第3张图片
仿真led流水灯仿真实现_第4张图片

在wave界面,首先restart --> run-all --> Zoom Full,得到如下仿真结果
led流水灯仿真实现_第5张图片
跑马灯只需要修改状态的二进制表示即可

always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            led <= 4'b1001;
        end  
        else if(state_c == IDLE)begin
            led <= 4'b00001;
        end
        else if(state_c == S1)begin
            led <= 4'b00011;
        end
        else if(state_c == S2)begin
            led <= 4'b00111;
        end
        else if(state_c == S3)begin
            led <= 4'b01111;
        end
        else if(state_c == S4)begin
            led <= 4'b11111;
        end
        else begin
            led <= led;
        end
    end

led流水灯仿真实现_第6张图片

引脚分配
led流水灯仿真实现_第7张图片

你可能感兴趣的:(fpga开发)