FPGA——FPGA状态机实现流水灯

一、引言

在FPGA开发中,状态机是一种重要的设计工具,用于处理具有时间顺序的事件。本文将详细介绍如何使用状态机实现一个LED流水灯的效果。

二、状态机概述

状态机(FSM)是一种行为模型,用于表示系统在不同状态下的行为以及状态之间的转移。在FPGA中,状态机通常用于控制复杂的流程。

2.1 分类

状态机主要分为两类:

  1. 摩尔(Moore)型状态机:输出只取决于当前状态。
  2. 米勒(Mealy)型状态机:输出取决于当前状态和输入条件。

2.2 写法

根据写法,状态机可以分为:

  1. 一段式:所有逻辑在一个always模块中。
  2. 二段式:状态转移和输出分别在两个always模块中。
  3. 三段式:状态转移、转移条件和输出分别在三个always模块中。

三、流水灯实现

本文采用二段式状态机实现LED流水灯。

3.1 顶层模块

顶层模块是整个设计的核心,它负责连接和协调各个子模块。在本设计中,顶层模块将分频模块、按键消抖模块和状态机模块有机地结合在一起,形成了一个完整的系统。

verilog 复制代码
module top (
    input clk,
    input rst_n,        
    input KEY0,
    input KEY1,
    output [5:0] led
);
    wire en_1Hz;
    wire key0_debounced, key1_debounced;
    reg pause;
    wire fsm_rst_n;
    reg key1_debounced_prev;

    key_debounce u_key0_deb (
        .clk(clk),
        .rst_n(rst_n),
        .key_in(~KEY0),    
        .key_out(key0_debounced)
    );

    key_debounce u_key1_deb (
        .clk(clk),
        .rst_n(rst_n),
        .key_in(~KEY1),    
        .key_out(key1_debounced)
    );

    assign fsm_rst_n = ~key0_debounced;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            pause <= 1'b0;       
            key1_debounced_prev <= 1'b0;
        end else begin
            key1_debounced_prev <= key1_debounced;
            if (key1_debounced_prev && !key1_debounced) begin
                pause <= ~pause;
            end
        end
    end

    clk_divider #(
        .CLK_FREQ(50_000_000),
        .OUT_FREQ(1)
    ) u_clk_div (
        .clk(clk),
        .rst_n(rst_n),
        .en(en_1Hz)
    );

    led_fsm u_led_fsm (
        .clk(clk),
        .rst_n(fsm_rst_n),
        .en(en_1Hz),
        .pause(pause),
        .led(led)
    );
endmodule

3.2 分频模块

分频模块的作用是将FPGA的高频时钟信号转换为低频信号,以满足流水灯的时序要求。在本设计中,我们将50MHz的输入时钟分频为1Hz,使得流水灯的每个LED灯能够以1秒为间隔依次点亮。分频模块通过计数器实现,当计数器达到预设的最大值时,产生一个使能信号,触发状态机的状态转移。

verilog 复制代码
module clk_divider #(
    parameter CLK_FREQ = 50_000_000,
    parameter OUT_FREQ = 1
) (
    input clk,
    input rst_n,
    output reg en
);
    localparam CNT_MAX = CLK_FREQ / OUT_FREQ - 1;
    reg [25:0] cnt;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt <= 0;
            en <= 0;
        end else begin
            if (cnt == CNT_MAX) begin
                cnt <= 0;
                en <= 1;
            end else begin
                cnt <= cnt + 1;
                en <= 0;
            end
        end
    end
endmodule

3.3 按键消抖模块

按键消抖模块用于消除按键抖动的影响,确保按键信号的稳定性和可靠性。在实际应用中,机械按键在按下和释放瞬间会产生多次抖动,这可能导致误触发。消抖模块通过延时采样和状态判断,有效地滤除了抖动信号,为后续的逻辑处理提供了稳定的输入。

verilog 复制代码
module key_debounce(
    input clk,
    input rst_n,
    input key_in,
    output reg key_out
);
    parameter DEBOUNCE_TIME = 1_000_000; 
    reg [19:0] counter;
    reg key_reg;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            counter <= 0;
            key_reg <= 1;
            key_out <= 1'b0;  
        end else begin
            key_reg <= key_in;
            if (key_reg != key_in) begin
                counter <= 0;
            end else if (counter < DEBOUNCE_TIME) begin
                counter <= counter + 1;
            end else begin
                key_out <= key_in;
            end
        end
    end
endmodule

3.4 流水灯状态机模块

状态机模块是流水灯设计的核心部分,它定义了流水灯的状态转移逻辑。在本设计中,我们定义了六个状态,每个状态对应一个LED灯的点亮。通过状态转移,实现流水灯的依次点亮效果。状态机的输出直接控制LED灯的亮灭,而状态的转移则由分频模块产生的使能信号触发。

verilog 复制代码
module led_fsm6 (
    input clk,
    input rst_n,
    input en,
    input pause,        
    output [5:0] led
);
    parameter S_LED0 = 6'b000001;
    parameter S_LED1 = 6'b000010;
    parameter S_LED2 = 6'b000100;
    parameter S_LED3 = 6'b001000;
    parameter S_LED4 = 6'b010000;
    parameter S_LED5 = 6'b100000;

    reg [5:0] current_state, next_state;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            current_state <= S_LED0;
        end else if (en && !pause) begin  
            current_state <= next_state;
        end
    end

    always @(*) begin
        case (current_state)
            S_LED0: next_state = S_LED1;
            S_LED1: next_state = S_LED2;
            S_LED2: next_state = S_LED3;
            S_LED3: next_state = S_LED4;
            S_LED4: next_state = S_LED5;
            S_LED5: next_state = S_LED0;
            default: next_state = S_LED0;
        endcase
    end

    assign led = current_state;
endmodule

四、运行结果

在实际运行中,流水灯按照预设的状态顺序依次点亮,每个LED灯亮起的时间间隔为1秒。通过按键KEY0可以复位流水灯,使其从第一个LED开始重新运行。通过按键KEY1可以暂停和继续流水灯的运行。

五、总结

本文详细介绍了如何使用FPGA状态机实现流水灯效果。通过状态机的设计,可以清晰地控制流水灯的状态转移,使整个系统更加稳定和易于维护。状态机的设计方法和实现过程对于其他复杂的FPGA项目也具有重要的参考价值。

相关推荐
FPGA_ADDA2 小时前
基于PXIE 总线架构的Kintex UltraScale 系列FPGA 高性能数据预处理板卡
fpga开发·pxie总线·ku060·ku115
搬砖的小码农_Sky11 小时前
FPGA:Lattice的FPGA产品线以及器件选型建议
嵌入式硬件·fpga开发·硬件架构·硬件工程
超能力MAX13 小时前
ZYNQ-AXI4 DDR读写测试
fpga开发
fpga小白历险记14 小时前
BUFDS_GTE2,IBUFDS,BUFG缓冲的区别
fpga开发
zly88653721 天前
MMIO机制详解
fpga开发
北京青翼科技1 天前
【PXIE301-211】基于PXIE总线的16路并行LVDS数据采集、1路光纤数据收发处理平台
图像处理·fpga开发·信号处理
霖001 天前
PCIe数据采集系统
数据结构·经验分享·单片机·嵌入式硬件·fpga开发·信号处理
FakeOccupational1 天前
fpga系列 HDL : Microchip FPGA开发软件 Libero Soc 安装 & license申请
fpga开发
千歌叹尽执夏1 天前
FPGA: UltraScale+ bitslip实现(ISERDESE3)
fpga开发·training·ultrascale+·bitslip
zly88653721 天前
MLX5 Linux 驱动代码分析
linux·运维·fpga开发