任务描述
根据所学的FPGA相关知识完成花样流水灯的设计,使用verilog HDL相关语言,编程实现对四个LED灯的控制,要求完成至少五种流水灯的闪烁方案设计。编写仿真代码,测试正确性。
实验目的
1、学习ISE Design Suite 14.7的基本操作;
2、掌握FPGA的开发流程;
3、学习时序电路的设计;
4、巩固状态机的相关知识。
实验原理
本次实验将通过时间来控制流水灯闪烁的样式。在本次实验中,我设定每个LED灯可以保持发亮状态500ms,我们有四个LED灯,因此通过计算,每一个闪烁样式需要2000ms的时间。所以,我们设定,每当计时器记到2000ms时,自动跳转到下一个闪烁样式的状态。
本次实验中,我们使用状态机来控制流水灯不同闪烁样式之间的转变。状态机是一种能够描述具有逻辑顺序和时序顺序事件的方法,特别适合用于描述存在先后顺序以及其他规律性的事件。
根据对该实验要求的分析,设计状态转移图如下:
其中,在S1状态下LED灯从左往右依次亮;在S2状态下LED灯从右往左依次亮;在S3状态下LED灯从中间向两边扩散亮;在S4状态下LED灯从两边向中间收敛亮;S5状态即为LED灯跳变亮。
实验过程
新建工程
*双击桌面快捷图标,打开ISE Design Suite 14.7软件,新建工程项目,点击File—>New Project
*工程项目命名
将该项目命名为:EDA_liushuideng,随后点击Next
*根据开发板选择硬件配置,具体配置要求请参考下图。再点击Next
*点击Finish,完成新工程的准备工作。
编写.v文件代码
*.v文件命名
完成新工程项目建立后,进入如下界面
右击EDA_liushuideng—>New Source
选择Verilog Module—>在File name对话框中键入.v文件名称—>Next,在本次实验中,我将其命名为:LED,
直接点击Next,进入下一个对话框。
选择Finish。至此,新.v文件的命名步骤完成。
编写代码
根据题目要求,使用Verilog HDL语言编写相关代码。
module LED(
input wire clk ,
input wire rst_n ,
output reg [3:0] led
);
//闪烁状态
parameter S1 = 4'b0000;
parameter S2 = 4'b0001;
parameter S3 = 4'b0010;
parameter S4 = 4'b0100;
parameter S5 = 4'b1000;
reg [3:0] current_state; //现状态
reg [3:0] next_state; //次状态
reg [2:0] mode;//具体led灯闪烁控制位
reg [25:0] cnt;
reg [2:0] counter;
//500ms
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
cnt <= 26'd0;
end
else begin
if(cnt == 26'd25_000_000 - 1)begin
cnt <= 26'd0;
end
else begin
cnt <= cnt + 26'd1;
end
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
counter <= 3'b0;
else if(cnt == 26'd25_000_000 - 1)
counter <= counter +3'b1;
else if (counter == 3'b100)
counter <= 3'b0;
else
counter <= counter;
end
//四个LED灯控制位
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
mode <= 3'b0;
end
else if(cnt == 26'd25_000_000 - 1)
mode <= mode + 3'b1;
else if(mode == 3'b100)
mode <= 3'b0;
else
mode <= mode;
end
//次态赋值给现态
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
current_state <= S1;
end
else begin
current_state <= next_state;
end
end
//状态转移
always@(*)begin
case(current_state)
S1 : begin
if(counter == 3'b100)
next_state = S2;
else
next_state = S1;
end
S2 : begin
if(counter == 3'b100)
next_state = S3;
else
next_state = S2;
end
S3 : begin
if(counter == 3'b100)
next_state = S4;
else
next_state = S3;
end
S4 : begin
if(counter == 3'b100)
next_state = S5;
else
next_state = S4;
end
S5 : begin
if(counter == 3'b100)
next_state = S1;
else
next_state = S5;
end
endcase
end
//输出
always@(posedge clk or negedge rst_n)begin
if(~rst_n)begin
led <= 4'b1111;
end
else begin
case(current_state)
S1 :begin //左移
case(mode)
2'b00: led <= 4'b1110;
2'b01: led <= 4'b1101;
2'b10: led <= 4'b1011;
2'b11: led <= 4'b0111;
default:led <= 4'b1110;
endcase
end
S2 :begin //右移
case(mode)
2'b00: led <= 4'b0111;
2'b01: led <= 4'b1011;
2'b10: led <= 4'b1101;
2'b11: led <= 4'b1110;
default:led <= 4'b0111;
endcase
end
S3 :begin //扩散
case(mode)
2'b00: led <= 4'b1111;
2'b01: led <= 4'b1001;
2'b10: led <= 4'b0110;
2'b11: led <= 4'b1111;
default:led <= 4'b1111;
endcase
end
S4 :begin //收敛
case(mode)
2'b00: led <= 4'b1111;
2'b01: led <= 4'b0110;
2'b10: led <= 4'b1001;
2'b11: led <= 4'b1111;
default: led <= 4'b1111;
endcase
end
S5 :begin //跳变亮
case(mode)
2'b00: led <= 4'b0111;
2'b01: led <= 4'b0101;
2'b10: led <= 4'b0001;
2'b11: led <= 4'b0000;
default: led <= 4'b1111;
endcase
end
endcase
end
end
endmodule
运行代码
代码编写完成之后,点击Implement Top Module,检查代码是否存在错误。
若存在错误,根据提示更正错误后,再次点击Implement Top Module,直到代码正确无误。
仿真测试
在代码运行没有语法错误后,编写仿真文件代码来测试运行结果能否达到预期效果。
新建仿真测试文件
*点击Simulation
*右击LED(LED.v)—>选择New Source
*选择Verilog Test Fixture—>在File name的对话框中输入仿真测试文件名称—>Next,在本次实验中,我将其命名为:LED_text。
点击Next
点击Finish
编写.v仿真测试文件代码
完成仿真测试文件命名之后,进入对话框,编写仿真测试文件代码。
module LED_text;
// Inputs
reg clk;
reg rst_n;
// Outputs
wire [3:0] led;
// Instantiate the Unit Under Test (UUT)
LED uut (
.clk(clk),
.rst_n(rst_n),
.led(led)
);
initial begin
// Initialize Inputs
clk = 0;
rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
// Add stimulus here
end
always#10 clk = ~clk; //20ns
endmodule
完成仿真测试代码编写后,点击Behavioral Check Syntax运行仿真文件,检查是否存在错误。若存在错误,更改后重新编译直到语法正确无误,再点击Simulate Bhaviral Model查看仿真波形图。
查看仿真波形图
从左往右依次亮
根据仿真波形图可以直观地看出,第一个500ms内,最右边的LED亮起。随后在第二个500ms内,最右边的LED熄灭,从右往左数第二个LED灯亮起。在第三个500ms内,最右边的LED依旧保持熄灭状态,从右往左数第二个LED灯也熄灭,从右往左数第三个LED灯亮起。在第四个500ms内,最左边的LED灯亮起,其他三个LED灯保持熄灭状态。满足了我们实验最初的设想,四个LED灯从左往右依次亮起。
从右往左依次亮
根据仿真波形图可以直观地看出,第五个500ms内,最左边的LED亮起。随后在第六个500ms内,最左边的LED熄灭,从左往右数第二个LED灯亮起。在第七个500ms内,最左边的LED依旧保持熄灭状态,从左往右数第二个LED灯也熄灭,从左往右数第三个LED灯亮起。在第八个500ms内,最右边的LED灯亮起,其他三个LED灯保持熄灭状态。满足了我们实验最初的设想,完成状态S1的流水灯样式后,直接进入状态S2,四个LED灯从右往左依次亮起。
从中间向两边扩散亮
根据上面仿真波形图可以直观地观察到,在第九个500ms内,所有地LED灯均保持熄灭状态。然后,在进入第十个500ms后,中间两个LED灯亮起,最左边和最右边地LED灯仍然保持熄灭状态。在进入,第十一个500ms后,中间的两个LED灯熄灭,最左边和最右边的LED灯亮起。然后,在进入第十二个500ms后,所有的LED灯熄灭。分析仿真波形图,实验结果达到预期效果。
从两边向中间收敛亮
据上面仿真波形图可以直观地观察到,在第十三个500ms内,所有地LED灯均保持熄灭状态。然后,在进入第十四个500ms后,中间两个LED灯保持熄灭状态,最左边和最右边地LED灯亮起。在进入,第十五个500ms后,中间的两个LED灯亮起,最左边和最右边的LED灯熄灭。然后,在进入第十六个500ms后,所有的LED灯熄灭。分析仿真波形图,实验结果达到预期效果。
跳变亮
关于状态S5,实验之前我们设计最开始最左边的LED亮起,并且一直保持到该状态结束,随后是从左往右数第三个LED灯亮起,并保持到该状态结束,接下来从左往右数的第二个LED灯亮起,也需要保持到该状态结束,最后是最右边的LED灯亮起,所以在该状态下,所有的LED灯均处于发光状态。分析上诉仿真波形图,可以发现实验结果满足我们对于该状态的预期设计。
在状态S5结束后,跳转到状态S1,进入下一轮循环。分析上诉仿真波形图,可以发现在完成状态S5后,LED灯又进入了状态S1,所有LED灯从右往左依次亮起,满足实验预期效果。
实验总结
通过本次实验,我掌握了FPGA的开发流程,同时也熟悉了ISE Design Suite 14.7的基本操作,也巩固了状态机的相关知识。
这一次设计的花样流水灯,只有4个LED灯,可实现的闪烁样式较少。本次设计的花样流水灯完全由时间控制状态的转移,以及LED灯的亮灭状态。