FPGA—硬件电路一旦上电配置完成,各个功能模块会并行地持续工作

发布于:2025-09-07 ⋅ 阅读:(19) ⋅ 点赞:(0)

1.示例代码参考

这段代码是用 Verilog 编写的一个 LED 闪烁控制模块,主要实现了 LED 按一定时间间隔循环移位闪烁的功能。下面详细解释其架构组成:

模块定义与端口声明

  • 模块名为 led_flash,包含三个端口:
    • sys_clk:输入端口,是系统时钟信号,用于驱动整个模块的时序逻辑。
    • rst_n:输入端口,是系统复位信号(低电平有效),用于在复位时将模块状态恢复到初始状态。
    • led:输出端口,是一个 4 位的寄存器,用于控制 4 个 LED 的亮灭状态。

内部信号声明

  • cnt:28 位的寄存器,作为计数器,用于计时,实现 0.25 秒的时间间隔。
  • add_cnt:线网类型(wire)信号,用于指示是否进行计数操作。
  • end_cnt:线网类型(wire)信号,用于指示计数是否结束(即达到 0.25 秒的时间)。

计数器逻辑(cnt 部分)

  • 采用时序逻辑(always @(posedge sys_clk or negedge rst_n)),在时钟上升沿或复位信号下降沿时触发。
    • 当 rst_n 为低电平时(复位),cnt 被置为 0。
    • 当 add_cnt 为高电平时(允许计数):
      • 如果 end_cnt 为高电平(计数结束),cnt 被置为 0,重新开始计数。
      • 否则,cnt 加 1,继续计数。

控制信号赋值

  • add_cnt 被赋值为 1,意味着始终允许计数器进行计数操作。
  • end_cnt 是一个组合逻辑信号,当 add_cnt 为 1 且 cnt 计数到 10_000_000 - 1 时,end_cnt 为 1,表示计数结束(即经过了 0.25 秒,假设系统时钟频率为 40MHz,10_000_000 个时钟周期约为 0.25 秒)。

LED 控制逻辑

  • 同样采用时序逻辑(always @(posedge sys_clk or negedge rst_n))。
    • 当 rst_n 为低电平时(复位),led 被置为 4'b1110,这是复位后的初始状态(可以根据实际硬件连接,确定具体哪个 LED 亮灭)。
    • 当 end_cnt 为高电平时(计数结束,即经过 0.25 秒),led 进行循环移位操作({led[2:0], led[3]}),实现 LED 状态的切换。
    • 否则,led 保持当前状态不变。
// 模块名称:led_flash
// 功能描述:实现4个LED按0.25秒间隔循环移位闪烁
// 输入信号:sys_clk(系统时钟)、rst_n(复位信号,低电平有效)
// 输出信号:led(4位,控制4个LED的亮灭状态)
module led_flash(
    input        sys_clk,  // 系统时钟,假设频率为40MHz
    input        rst_n,    // 复位信号,低电平有效
    output reg [3:0] led   // 4位LED输出,高/低电平对应LED亮/灭(取决于硬件设计)
);

// 内部信号定义
reg [27:0] cnt;           // 28位计数器,用于计时(最大计数2^28-1,满足计时需求)
wire       add_cnt;       // 计数使能信号,为1时允许计数器递增
wire       end_cnt;       // 计数结束信号,为1时表示达到设定时间

// 计数器时序逻辑:在时钟上升沿或复位下降沿更新计数器值
always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin           // 复位状态:计数器清零
        cnt <= 28'd0;
    end
    else if(add_cnt) begin     // 计数使能有效
        if(end_cnt) begin      // 计数达到目标值:计数器清零,重新计数
            cnt <= 28'd0;
        end
        else begin             // 未达到目标值:计数器递增
            cnt <= cnt + 28'd1;
        end
    end
    else begin                 // 计数使能无效:保持当前值
        cnt <= cnt;
    end
end

// 计数使能信号:始终为1,让计数器持续工作
assign add_cnt = 1'b1;

// 计数结束信号:当计数器达到10,000,000-1时为1
// 计算依据:40MHz时钟周期为25ns,10,000,000个周期 = 10,000,000 × 25ns = 0.25秒
assign end_cnt = add_cnt && (cnt == 28'd9_999_999);

// LED控制时序逻辑:在时钟上升沿或复位下降沿更新LED状态
always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin           // 复位状态:初始LED状态为4'b1110(假设低电平点亮,此时最右侧LED亮)
        led <= 4'b1110;
    end
    else if(end_cnt) begin     // 每0.25秒更新一次LED状态:循环左移一位
        // 移位逻辑:将低3位移到高3位,最高位移到最低位
        // 例:1110 → 1101 → 1011 → 0111 → 1110(循环)
        led <= {led[2:0], led[3]};
    end
    else begin                 // 未到更新时间:保持当前LED状态
        led <= led;
    end
end

endmodule

2.通过本程序对FPGA的进一步理解

硬件并行特性与非软件式循环

FPGA 是基于硬件描述语言(如 Verilog、VHDL)进行设计,本质上是对硬件电路的描述。 它通过配置可编程逻辑单元(如查找表、触发器等)和布线资源来实现特定功能。硬件电路一旦上电配置完成,各个功能模块会并行地持续工作。比如在一个简单的流水灯 FPGA 设计中,计数器模块和 LED 控制模块是同时在工作的,不存在像软件程序中由 CPU 一条一条按顺序执行指令那样的循环。

时钟驱动下的持续状态更新

FPGA 中的时序逻辑(如触发器、寄存器等)通常由时钟信号驱动。以之前提到的 LED 闪烁控制模块为例,在时钟上升沿或者下降沿,相关寄存器(如计数器 cnt 、LED 输出寄存器 led )会根据当前的输入信号和逻辑条件来更新状态。 时钟信号不断地产生上升沿或下降沿,就会让这些模块持续不断地进行状态更新,看起来就好像是在 “循环运行”。

组合逻辑的即时响应

FPGA 中的组合逻辑部分,如加法器、多路选择器等,只要输入信号发生变化,输出就会立即根据逻辑关系进行更新。比如一个由组合逻辑实现的简单运算电路,输入数据一旦改变,输出会马上重新计算得出新值,这种持续根据输入变化而即时响应的特性,也会给人一种在不断 “运行” 的感觉。

状态机与类似循环的操作

状态机是 FPGA 设计中常用的一种设计方法。在状态机里,会根据当前状态和输入信号决定下一个状态。 当状态机进入一个循环状态序列时,就会在这些状态之间不断切换,从而实现特定的功能。比如一个交通灯控制状态机,会在 “红灯 - 绿灯 - 黄灯” 等状态间循环切换,从宏观功能上看就像是在循环运行。


网站公告

今日签到

点亮在社区的每一天
去签到