FPGA 05 基础 led灯闪烁 FPGA 实验
模块名称: led_flash
主要功能 :每隔一段时间,输出 led[x:0] 所有电平进行翻转,对外部电路实现控制4个led灯的闪烁。
实现(设计)流程: 1、内部使用一个定时器计数器,分两个部分
①计数到设置值,重新开始计数
②计数到设置值,led[x:0]电平翻转,否则保持不变。
- led_flash.v 文件
module led_flash(
//端口列表
clk50M ,
Rst_n ,
led
);
// 这里类似与 C 语言的函数定义,也可以使用类似于C语言的定义,如下所示:
// module led_flash(input clk50M ,input Rst_n , reg [3:0]led);
// 上述可以看到
//端口定义
input clk50M ;
input Rst_n ;
//output wire [3:0]led ; //定义的是一个【线网】类型的信号
output reg [3:0]led ; //定义的是一个寄存器输出的端口
//传参,修改定时器的值,方便在后续的参数传递时
//仅仅只需要修改一个参数变量即可
// 1、减少修改文件的数目
// 2、减少修改出现的错误
parameter CNT_MAX = 25'd24_999_999 ; //类似与 C 语言的 #define
reg [24:0]cnt ; //定义一个25位的寄存器,用做计数
//always 语句分析
// 总是关注 clk50M 信号的上升沿或者 Rst_n 的下降边沿,那么就会
// 执行 always 里面的语句
// always 语句,是不断在执行和处理的,
// 个人理解: always 会不断执行alway 里面到下一个always 块之前的语句
// 这里面属于一个单独的always 块,相当于分片进行设计和操作
// 此外,always 和另外一个always 是互不影响的
//第一个always块
always@(posedge clk50M or negedge Rst_n)
// posedge : 上升沿 negedge: 下降沿
if(!Rst_n) //判断 复位引脚是否位低电平,如果是,则进入if语句执行一些操作
cnt <=25'd0 ; //进入if语句,表示Rst_n是低电平,则进入复位
else if(cnt == CNT_MAX) //判断是否到达定时器的值,到了,对cnt 清零
cnt <= 25'd0 ;
else //未满足上面的条件,则表示既没有复位,计数器的值也没有达到设定的值
cnt <= cnt +1'b1 ; // cnt++
//第二个always 块,不影响其他always块的执行
always@(posedge clk50M or negedge Rst_n)
if(!Rst_n) //判断 复位引脚是否位低电平,如果是,则进入if语句执行一些操作
led <= 4'b1111 ; //上拉电阻,高电平熄灭
else if(cnt == CNT_MAX)
led <= ~led; //计时完成后,led的电平全部反转
endmodule
// 编辑完成上述步骤后,进行分析和综和进行编译 按钮 start Analysie & Synthesis
- led_flash_tb.v 文件
`timescale 1ns/1ns
//建议上面直接复制粘贴,不然容易出错
`define clock_period 20 //定义一个仿真的时钟周期的时间是20ns
module led_flash_tb;
//端口模块测试的端口定义
//测试模块编写流程
reg clk50M ;
reg Rst_n ;
//output wire [3:0]led ; //定义的是一个【线网】类型的信号
wire [3:0]led ; //定义的是一个寄存器输出的端口
//测试模块函数,重定义了一个新的 测试模块名称: led_flash0
//传递参数进入
//测试模块函数
// led_flash
// #(
// .CNT_MAX(25'd249) // 这里表示,在我们仿真的时候修改
// // led_flash 模块里面的 CNT_MAX 修改为 25’d2499 进行仿真测试
// // 参数传递的好处,不需要修改源文件的蚕食
// // 保证实际电路的输出效果时不会出错
// )
// //加入测试接口和函数
// led_flash0(
// .clk50M(clk50M) ,
// .Rst_n(Rst_n) ,
// .led(led)
//);
//实际电路仿真, CNT_MAX 的参数不可更改 ,若 CNT_MAX参数,则实际电路仿真时会出错
//其余和逻辑仿真保持一致即可,注: 可以和上面的近对比。
led_flash
//加入测试接口和函数
led_flash0(
.clk50M(clk50M) ,
.Rst_n(Rst_n) ,
.led(led)
);
//设定初始状态
initial clk50M =1 ; //初始化 clk50M = 1 定义一个
//
// always #10 clk50M = ~clk50M ; //延时10ns,时钟翻转一次,这样的话,时钟周期就是 20ns
// 也可以使用下面的方式进行操作 ,一个周期有 10ns 的低电平,10ns的高电平
// 每个电平持续时间是 10ns , 则一个总的时钟信号周期就是 20ns
always #(`clock_period/2) clk50M = ~clk50M ;
// 初始化信号,(begin end)
// 出现begin 后面必须有 end
// 开机执行一次
initial begin
Rst_n = 0 ;
#(`clock_period*20+1);
Rst_n =1 ; //延时20个周期+1,避免异步对准(齐)
#(`clock_period*250000+1); //仿真的延时时间
$stop ; //仿真停止
end
endmodule
// 编写完成测试后,设置该源代码位仿真代码
// Assigment->Settings --> EDA Tool Settings
// --> Simulation --> Compile test bench
// 添加测试的文件 (点击 Test Benches --> New)
// 点击Filename 后面跟随的(...)--> 添加自己的测试文件
// 添加完成以后,在TestBench 里面添加 测试的文件名称(不要添加.v这个后缀) 即可
// 保存--> Ok--> apply 即可
// 主界面 --> Tools --> Run Simulation --> RTL Simulation or Gate Level Simulation
// 重新仿真操作
// 仿真出错 --> 修改好文件 -> 在仿真软件 ->Library -> Recompile
// Reset --> Run All
// 出现仿真时间过长--> break 进行停止
// 电路图视图 操作: 看内部实际电路的连接方式
// Tools -> NetList Viwers -> RTL Viewer
// 逻辑仿真和模拟实际情况下的仿真 的对比(不同点)
// #(.CNT_MAX(25'd249)) 在逻辑电路可以传递参数
// 实际电路中不可以传递参数
// 最后,配置IO 口进行下载到芯片中
// 2种方式
// 方式1、选择Pin planner 配置选中对应的IO口 Assigment->Pin Planner
// 方式2、 ①编写自动化脚本文件 new -> File -> Tcl_script.tcl 文件 (针对IO口较多的情况)
// ②编写完成后, Tools -> Tcl_script --> 导入 --> run 执行编写的脚本文件