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, // 系统时钟,假设频率为40MHzinput 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) beginif(!rst_n) begin // 复位状态:计数器清零cnt <= 28'd0;endelse if(add_cnt) begin // 计数使能有效if(end_cnt) begin // 计数达到目标值:计数器清零,重新计数cnt <= 28'd0;endelse begin // 未达到目标值:计数器递增cnt <= cnt + 28'd1;endendelse 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) beginif(!rst_n) begin // 复位状态:初始LED状态为4'b1110(假设低电平点亮,此时最右侧LED亮)led <= 4'b1110;endelse if(end_cnt) begin // 每0.25秒更新一次LED状态:循环左移一位// 移位逻辑:将低3位移到高3位,最高位移到最低位// 例:1110 → 1101 → 1011 → 0111 → 1110(循环)led <= {led[2:0], led[3]};endelse begin // 未到更新时间:保持当前LED状态led <= led;end
endendmodule
2.通过本程序对FPGA的进一步理解
硬件并行特性与非软件式循环
FPGA 是基于硬件描述语言(如 Verilog、VHDL)进行设计,本质上是对硬件电路的描述。 它通过配置可编程逻辑单元(如查找表、触发器等)和布线资源来实现特定功能。硬件电路一旦上电配置完成,各个功能模块会并行地持续工作。比如在一个简单的流水灯 FPGA 设计中,计数器模块和 LED 控制模块是同时在工作的,不存在像软件程序中由 CPU 一条一条按顺序执行指令那样的循环。
时钟驱动下的持续状态更新
FPGA 中的时序逻辑(如触发器、寄存器等)通常由时钟信号驱动。以之前提到的 LED 闪烁控制模块为例,在时钟上升沿或者下降沿,相关寄存器(如计数器 cnt
、LED 输出寄存器 led
)会根据当前的输入信号和逻辑条件来更新状态。 时钟信号不断地产生上升沿或下降沿,就会让这些模块持续不断地进行状态更新,看起来就好像是在 “循环运行”。
组合逻辑的即时响应
FPGA 中的组合逻辑部分,如加法器、多路选择器等,只要输入信号发生变化,输出就会立即根据逻辑关系进行更新。比如一个由组合逻辑实现的简单运算电路,输入数据一旦改变,输出会马上重新计算得出新值,这种持续根据输入变化而即时响应的特性,也会给人一种在不断 “运行” 的感觉。
状态机与类似循环的操作
状态机是 FPGA 设计中常用的一种设计方法。在状态机里,会根据当前状态和输入信号决定下一个状态。 当状态机进入一个循环状态序列时,就会在这些状态之间不断切换,从而实现特定的功能。比如一个交通灯控制状态机,会在 “红灯 - 绿灯 - 黄灯” 等状态间循环切换,从宏观功能上看就像是在循环运行。