一、在VsCode中写代码
1、建立工程项目文件water_led.v文件

2、打开项目文件,创建三个目录

3、打开文件trl,创建water_led.v文件

4、打开文件tb,创建water_led_tb.v文件

5、用VsCode打开water_led.v文件,编写源代码

module water_led (
input clk, // 输入时钟(50 MHz)
input rst_n, // 复位信号(低电平有效)
input pause_sw, // 暂停开关(高电平暂停,低电平运行)
output reg [5:0] led // 输出 6 个 LED
);
parameter T = 50_000_000; // 计数器最大值,用于生成 1 秒定时
reg [2:0] cstate; // 现态
reg [2:0] nstate; // 次态
// 状态划分
localparam state_led0 = 0; // LED0 亮
localparam state_led1 = 1; // LED1 亮
localparam state_led2 = 2; // LED2 亮
localparam state_led3 = 3; // LED3 亮
localparam state_led4 = 4; // LED4 亮
localparam state_led5 = 5; // LED5 亮
reg [25:0] cnt = 0; // 计时器赋初值为 0
// 计数器模块
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 0; // 按下复位键,清零
else if (cnt == T - 1) // 计时器达到最大值,清零重新计数
cnt <= 0;
else if (!pause_sw) // 如果未暂停,计数器继续计数
cnt <= cnt + 1;
end
// 第一段:现态跟随次态,时序逻辑,非阻塞赋值
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cstate <= state_led0; // 复位键被按下,当前状态设置为 LED0 亮
else if (!pause_sw) // 如果未暂停,更新状态
cstate <= nstate;
end
// 第二段:组合逻辑,阻塞赋值
always @(*) begin
if (!rst_n)
nstate = state_led0; // 复位时回到初始状态
else
case (cstate)
state_led0: begin
if (cnt == T - 1) // 该状态持续时间为 1 秒,1 秒后跳转到下一个状态
nstate = state_led1;
else
nstate = state_led0;
end
state_led1: begin
if (cnt == T - 1)
nstate = state_led2;
else
nstate = state_led1;
end
state_led2: begin
if (cnt == T - 1)
nstate = state_led3;
else
nstate = state_led2;
end
state_led3: begin
if (cnt == T - 1)
nstate = state_led4;
else
nstate = state_led3;
end
state_led4: begin
if (cnt == T - 1)
nstate = state_led5;
else
nstate = state_led4;
end
state_led5: begin
if (cnt == T - 1)
nstate = state_led0;
else
nstate = state_led5;
end
default: nstate = state_led0; // 默认状态
endcase
end
// 第三段:跟随状态输出
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
led <= 6'b000001; // 复位时点亮第一个 LED
else
case (cstate)
state_led0: led <= 6'b000001;
state_led1: led <= 6'b000010;
state_led2: led <= 6'b000100;
state_led3: led <= 6'b001000;
state_led4: led <= 6'b010000;
state_led5: led <= 6'b100000;
default: led <= 6'b000001; // 默认状态
endcase
end
endmodule
6、用VsCode打开water_led_tb.v文件,编写仿真代码

`timescale 1ns / 1ps
module fsm3_led_tb;
// 输入信号
reg clk; // 输入时钟(50 MHz)
reg rst_n; // 复位信号(低电平有效)
reg pause_sw; // 暂停开关(高电平暂停,低电平运行)
// 输出信号
wire [5:0] led; // 6 个 LED 输出
// 实例化被测模块
fsm3_led uut (
.clk(clk),
.rst_n(rst_n),
.pause_sw(pause_sw),
.led(led)
);
// 生成时钟信号
initial begin
clk = 0;
forever #10 clk = ~clk; // 50 MHz 时钟周期 = 20 ns
end
// 测试过程
initial begin
// 初始化信号
rst_n = 0; // 初始复位
pause_sw = 0; // 初始不暂停
#20; // 等待 20 ns
// 释放复位信号
rst_n = 1;
#200; // 等待一段时间观察初始状态
// 测试正常流水灯效果
pause_sw = 0; // 不暂停
#2_000_000; // 运行 2 秒,观察 LED 变化
// 测试暂停功能
pause_sw = 1; // 暂停
#1_000_000; // 停留 1 秒,观察 LED 是否保持不变
pause_sw = 0; // 恢复
#2_000_000; // 再次运行 2 秒,观察 LED 变化
// 测试复位功能
rst_n = 0; // 触发复位
#20; // 等待复位完成
rst_n = 1; // 释放复位
#200; // 观察复位后的初始状态
// 结束仿真
$stop;
end
endmodule
二、在Quartus中创建工程与仿真
1、打开Quartus,点击New Project Wizard

2、把工程保存在之前创造的prj文件里

3、添加之前在VsCode中写好的源码和仿真源码

4、选择芯片

5、选择仿真必要选项

其余为展示页面,均点击Next即可。
6、将源码设为顶层文件

7、分析与综合

8、设置water_led_tb.v文件

添加完后,一直点OK,完成设置。
9、仿真

10、点击最下方的sim,然后右键u_water_led,在选项中选择Add Wave

11、点击最下方的Wave,根据图片点击左下角的黑点消除文件前缀,这样看着舒服点。然后选中一个参数,再CTRL+A全选中参数,最后CTRL+G分组

12、重新开始

13、运行所有

分析仿真可知,结果大差不差,嘿嘿

14、完整编译运行一次,发现未报错,然后配置引脚,配置完成后再次编译
15、下载
16、演示
FPGA-状态机+分层次+流水灯
17、参考链接