FPGA学习笔记(三) 流水灯入门FPGA设计流程及阻塞/非阻塞赋值的分析

系列文章目录

一、FPGA学习笔记(一)入门背景、软件及时钟约束

二、FPGA学习笔记(二)Verilog语法初步学习(语法篇1)

三、FPGA学习笔记(三) 流水灯入门FPGA设计流程

四、FPGA学习笔记(四)通过数码管学习顶层模块和例化的编写

五、FPGA学习笔记(五)Testbench(测试平台)文件编写进行Modelsim仿真

六、FPGA学习笔记(六)Modelsim单独仿真和Quartus联合仿真

七、FPGA学习笔记(七)verilog的深入学习之任务与函数(语法篇3)


硬件基础是正点原子开拓者开发板,通过基本的时序电路流水灯来学习FPGA的设计流程。

硬件部分

通过下面硬件可以看到按键所对应的板子的接口,同时也可以发现为什么复位在仿真的时候是低电平,因为按下的时候和GND导通了。按键没有按下的时候,RESET是高电平,按键按下的时候是低电平。
在这里插入图片描述

在这里插入图片描述

软件部分

正点原子的开拓者开发板上的时钟是50Mhz的,这里涉及到的循环左移的语法,可以参考
Verilog语法基础

module flow_led(
	input 				sys_clk,
	input 				sys_rst,
	
	output  reg  [3:0]  led
	);
	
reg [23:0] counter;

//**************************************
//             main code               ///
//*************************************//

//计数器对系统进行时钟计数,计时0.2s   
//50M的频率,那么0.2s要计数:0.2*50*1000*1000=1000_0000  //这里的_可有可无,方便观察
//目前有个疑问,时钟50Mhz
always @(posedge sys_clk or negedge sys_rst) begin  //系统时钟上升沿和复位信号下降沿都会触发
	if(!sys_rst)
	   counter <= 24'd0;
	else if(counter< 24'd1000_0000 - 1'b1)		//减去1,0的时候有一个时序,一直到9还有一个时序,总共是是个
		counter <= counter + 1'b1;
	else
		counter <= 24'd0;
end

//判断条件更改LED状态,因为使用的是reg
always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        led <= 4'b0001;
    else if(counter == 24'd1000_0000 - 1'b1) 
        led[3:0] <= {led[2:0],led[3]};  //利用组合的方式,进行循环移位操作
    else
        led <= led;
end

endmodule

这里面主要有一些细节和语法需要熟悉。

仿真部分

`timescale	1ns/1ns        			 // 定义仿真单位是1ns和仿真时间1ns
 
module flow_led_tb; 				 // 测试模块

parameter	T=20;          			 //定义一个参数,时间周期是20ns

//reg define
reg  sys_clk;               		 // 时钟信号
reg  sys_rst;              			 // 复位信号

//wire define
wire  [3:0]  led;					 //这里使用wire是因为这个输出信号,在仿真程序中用不到

//*****************************************************
//**                    main code
//*****************************************************

//给输入信号初始值
initial begin
	sys_clk		=1'b0;
	sys_rst		=1'b0;
								    //#是延时的作用,后面的数字即延时时间,单位是定义的仿真timescale
	#(T+1)  sys_rst  = 1'b1;      // 在第21ns的时候复位信号信号拉高
end

//50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次
always #(T/2) sys_clk = ~sys_clk;

//例化led模块  将程序模块flow_led例化为u0_flow_led
//前面是程序中的信号,后面应该是例化为新的仿真信号名。
flow_led  u0_flow_led (
    .sys_clk     (sys_clk  ),
    .sys_rst     (sys_rst),
    .led         (led      )
);

endmodule

下图是仿真,对区段进行截取可以看到200ms,LED的时间变化一次。
在这里插入图片描述
下载程序到板子中,也可以看到实现了流水灯,需要经常学习仿真的使用,之后对时序严格后要注意一些小问题的出现。

阻塞赋值和非阻塞赋值


2022.10.17更新:
对于时序逻辑电路的阻塞赋值和非阻塞赋值进行分析:
推荐在时序逻辑电路中一律采用非阻塞赋值,因为阻塞赋值不同语句的先后顺序可能产生不一样的结果。
在这里插入图片描述
一个普通的LED跑马灯,将coount的赋值语句改成阻塞赋值后,仿真结果就变了。24个时钟后led变化,接着下一个时钟led又变一次
在这里插入图片描述
突然循环左移了两次
正常情况下的仿真:25个时钟LED变化一次
在这里插入图片描述
count的仿真:
不知道为什么????
综合仿真测试:
在这里插入图片描述
解释:在复习数电的时候发现里面有写,阻塞赋值的操作是立即执行的,非阻塞赋值要等所有的语句的右边计算完成后,统一赋值给左边

不过网上也没有这种混合写法,推荐时序电路用非阻塞,组合电路用阻塞,书里也明确说不要混合在一起写,所以每次判断count==24前,先进行的是count+1,所以导致比起非阻塞赋值的操作,少了一个时钟周期,而在下一个周期,由于led操作和count<=0的操作都是非阻塞赋值,所以这个周期两个用时执行,所以count还保留上次的值,led又翻转一次。

总结就是,<=非阻塞赋值有延时性,因为只有下一个周期的才能判断上一个周期该变量的操作,阻塞该周期就能判断。这样就能解释上面现象。

网上有推荐这种写法,可以在仿真的时候看,实际下载到板子里的时候,编译器会忽略
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值