FPGA学习笔记3-BCD计数器的设计和验证(小梅哥)

1.一个四位计数器

BCD_Counter.v

module BCD_Counter(Clk,Cin,Rst_n,Cout,q);

	input Clk;//计数器基准时钟
	input Cin;//计数器进位输入
	input Rst_n;//系统复位
	
	output reg Cout;//计数器进位输出
	output [3:0]q;//计数值输出
	
	reg [3:0]cnt;//计数器的寄存器
	
	always@(posedge Clk or negedge Rst_n)//执行计数的过程
	if(Rst_n == 1'b0)
		cnt <= 4'd0;
	else if(Cin == 1'b1)begin
		if(cnt == 4'd9)
			cnt <= 4'd0;
		else
			cnt <= cnt + 1'b1;
	end
	else
		cnt <= cnt;
		
	always@(posedge Clk or negedge Rst_n)//产生进位输出信号
	if(Rst_n == 1'b0)
		Cout <= 1'b0;
	else if(Cin == 1'b1 && cnt == 4'd8)
		Cout <= 1'b1;
	else
		Cout <= 1'b0;
	//cnt计数值作为输出
	assign q = cnt;
	
endmodule

BCD_Counter_tb.v

`timescale 1ns/1ns

`define clock_period 20

module BCD_Counter_tb;
//激励信号
	reg Clk;
	reg Cin;
	reg Rst_n;
	
	wire Cout;
	wire [3:0]q;
	

//端口连接
	BCD_Counter BCD_Counter0(
	.Clk(Clk),
	.Cin(Cin),
	.Cout(Cout),
	.Rst_n(Rst_n),
	.q(q)
	);

	initial Clk = 1'b1;
	always#(`clock_period/2)Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		Cin = 1'b0;
		#(`clock_period*200);
		Rst_n = 1'b1;
		#(`clock_period*20);
		repeat(30)begin
				Cin = 1'b1;
				#(`clock_period);
				Cin = 1'b0;
				#(`clock_period*5);
		end
		#(`clock_period*20);
		$stop;
	end
	
endmodule

仿真波形:每一次Cin输出1, 就会计数一次(q加一)。q计数10的时候,Cout输出一次高电平。

2.两个四位计数器级联

BCD_Counter_top.v

module BCD_Counter_top(Clk,Cin,Rst_n,Cout,q);
	input Clk;//计数器基准时钟
	input Cin;//计数器进位输入
	input Rst_n;//系统复位
	
	output Cout;//计数器进位输出
	output [11:0]q;//计数值输出 
	
	reg [3:0]cnt;//计数器的寄存器
	wire Cout0,Cout1;
	wire [3:0]q0,q1,q2;
	assign q = {q2,q1,q0};
	
	BCD_Counter BCD_Counter0(
	.Clk(Clk),
	.Cin(Cin),
	.Cout(Cout0),
	.Rst_n(Rst_n),
	.q(q0)
	);
	
	BCD_Counter BCD_Counter1(
	.Clk(Clk),
	.Cin(Cout0),
	.Cout(Cout1),
	.Rst_n(Rst_n),
	.q(q1)
	);
	
	BCD_Counter BCD_Counter2(
	.Clk(Clk),
	.Cin(Cout1),
	.Cout(Cout),
	.Rst_n(Rst_n),
	.q(q2)
	);

endmodule

BCD_Counter_top_tb.v 

`timescale 1ns/1ns

`define clock_period 20

module BCD_Counter_top_tb;
//激励信号
	reg Clk;
	reg Cin;
	reg Rst_n;
	
	wire Cout;
	wire [11:0]q;
	

//端口连接
	BCD_Counter_top BCD_Counter_top0(
	.Clk(Clk),
	.Cin(Cin),
	.Cout(Cout),
	.Rst_n(Rst_n),
	.q(q)
	);

	initial Clk = 1'b1;
	always#(`clock_period/2)Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		Cin = 1'b0;
		#(`clock_period*200);
		Rst_n = 1'b1;
		#(`clock_period*20);
		
		Cin = 1'b1;
		#(`clock_period*5000);
		$stop;
	end
	
endmodule

 仿真波形:由于是三个四位计数器级联,理想结果是计数值q加到999的时候进位输出,然后q值清零。

3 .调试  修改代码

将判断条件改成  4'd8

再次仿真,观察到结果还是不对,添加counter0,1,2的波形,ctr+G  分组查看

如图,当counter0的q 值为9时,会产生一个Cout信号,这个Cout信号只有当一个时钟上升沿的时候才能被捕获到。  当下一个时钟上升沿来了,捕获Cout信号进行一次自加。 所以这个过程中q值的自加滞后了一个时钟。  当counter1的q值为9时,再产生一个Cout信号,等待下一个时钟上升沿到来时这个Cout信号才被捕获到,又滞后了一次。

 

改进代码:

这段代码,使得Cout的值滞后了一拍。所以要改成组合逻辑,就不用使用D触发器,就不会出现滞后一拍的情况。

 修改成如下:

同时必须修改Cout类型 ,删掉reg,否则会报错

满足条件时 Cout输出1, 否则输出0。

分析与综合后,来到modelsim, 从新编译BCD_Counter文件

最后Cout在q值计数到999时输出1, 达到理想的结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值