FPGA笔记5——BCD计数器

BCD计数器

158 将158拆解成百位十位个位

C中 
158/100 = 1 百位
(158/10)%10 = 5 十位
158%100 = 8 个位
在FPGA中理论也是可以使用这样的算法 但是过于耗费逻辑资源
BCD:每四位表示一个数,158需要十二个

0001 0101 1000
1 5 8

创建工程文件夹——》 创建工程(选路径起名字) ——》 代码选择——》 型号选择——》 仿真工具及语言选择

BCD计数器

在这里插入图片描述
新建Verilog HDL File 名字为 BCD_counter

 module  BCD_counter (Clk,Cin,Rst_n,Cout,q);
 		input Clk; //计数器 基准时钟
 		input Cin; //进位输入 与普通计数器一样 这个为高电平时
 				   //计数器的值才会+1
 		input Rst_n; //系统复位

 		output reg Cout; //进位输出 //凡是在always中赋值的
 						 //都应该是reg类型
 		output [3:0]q; //计数值输出


		reg [3:0]cnt; //凡是在always中赋值的都应该是reg类型
					  //定义一个计数器

	//计数过程
    always@(possdge 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@(possdge Clk or negedge Rst_n)
    if (Rst_n == 1'b0)
    	Cout <= 1'b0;
    else if (cin == 1'b1 && cnt == 4'd9)
    	Cout <= 1'b1;
    else 
    	Cout <= 1'b0;
 
    assign q = cnt; //把cnt的值传给q 实时输出到外部
 endmodule

在这里插入图片描述

对刚才写的计数器进行testbench仿真

`timecale 1ns/1ns
`define xitongshizhong 20  //(20ns)

module BCD_counter_tb;

	reg clk1;
	reg cin1;
	reg ret_n1;
	
	wire cout1;
	wire [3:0]q1;
	
	BCD_counter u1(
					.Clk(clk1),
				 	.Cin(cin1),
				 	.Rst_n(rst_n1),
				 	
				 	.Cout(cout1),
				 	.q(q1)
				 	);

initial clk1 = 1'b1;

always#(`shizhongzhouqi/2) 
		clk1 = ~ clk1;
		
initial begin
	rst_n1 = 1'b0;
	cin1 = 1'b0;
	#(`shizhongzhouqi*200);
	rst_n1 = 1'b1;
	#(`shizhongzhouqi*20);

	repeat(30)begin 
		cin1 = 1'b1;
		#(`shizhongzhouqi*1);
		cin1 = 1'b0;
		#(`shizhongzhouqi*5);
     end
     
#(`shizhongzhouqi*20);
$stop;

  end
			
endmodule

——》进行分析与综合 ——》链接——》仿真
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
计数器设计完成 仿真验证完成 下一步

进行级联

在这里插入图片描述

moudle BCD_counter_top(Clk,Cin,Rst_n,Cout,q);
	
	    input Clk; 
 		input Cin; 		   
 		input Rst_n; 

 		output  Cout; 
 		output [11:0]q; //3个计数器级联

		wire cout0;
		wire cout1;
		wire [3:0]q0;
		wire [3:0]q1;
		wire [3:0]q2;
		
    assign q = {q2,q1,q0}; //花括号进行位拼接

	BCD_counter C0(
					.Clk(Clk),//共用
				 	.Cin(Cin),
				 	.Rst_n(Rst_n),
				 	
				 	.Cout(cout0),//共用
				 	.q(q0)
				 	);


	BCD_counter C1(
					.Clk(Clk),//共用
				 	.Cin(cout0),
				 	.Rst_n(Rst_n),//共用
				 	
				 	.Cout(cout1),
				 	.q(q1)
				 	);
				 	
	BCD_counter C2(
					.Clk(Clk),//共用
				 	.Cin(cout1),
				 	.Rst_n(Rst_n),//共用
				 	
				 	.Cout(Cout),
				 	.q(q2)
				 	);
endmodule 

——》分析与综合 ——》将其设置为顶层——》分析与综合

对刚才写的顶层计数器进行testbench仿真

`timecale 1ns/1ns
`define xitongshizhong 20  //(20ns)

module BCD_counter_top_tb;

	reg clk1;
	reg cin1;
	reg ret_n1;
	
	wire cout1;
	wire [11:0]q1;
	
	BCD_counter_top u0(
					.Clk(clk1),
				 	.Cin(cin1),
				 	.Rst_n(rst_n1),
				 	
				 	.Cout(cout1),
				 	.q(q1)
				 	);

initial clk1 = 1'b1;

always#(`shizhongzhouqi/2) 
		clk1 = ~ clk1;
		
initial begin
	rst_n1 = 1'b0;
	cin1 = 1'b0;
	#(`shizhongzhouqi*200);
	rst_n1 = 1'b1;
	#(`shizhongzhouqi*20);

	//   repeat(50)begin 
	//	 cin1 = 1'b1;
	//	 #(`shizhongzhouqi*1);
	//	 cin1 = 1'b0;
	//	 #(`shizhongzhouqi*5);
    //   end
    
    cin1 = 1'b1;
    
    //三个(最大10次)计数器 至少要cin有效 999次 所以我们直接让cin一直有效
    //那么就是每一次 时钟上沿来临都会计数一次
     
#(`shizhongzhouqi*2000);//延时2000的时钟周期 大于999 保证能看到
$stop;

  end
			
endmodule

分析与综合——》链接——》仿真
在这里插入图片描述
在这里插入图片描述
这说明我们的进位量出现了问题 把所有模块的图都调出来
在这里插入图片描述
这里可以看到 由于时序逻辑 D触发器的特性 会滞后输出 (cin有效但是需要下次时钟上升沿的时候 这个有效电平才会被捕获

代码修改 基础模块 BCD_counter
将Cout的输出由时序逻辑 改为组合逻辑 组合逻辑无D触发器
在这里插入图片描述

 module  BCD_counter (Clk,Cin,Rst_n,Cout,q);
 		input Clk; //计数器 基准时钟
 		input Cin; //进位输入 与普通计数器一样 这个为高电平时
 				   //计数器的值才会+1
 		input Rst_n; //系统复位

 		output  Cout; //进位输出 
 					
 		output [3:0]q; //计数值输出


		reg [3:0]cnt; //凡是在always中赋值的都应该是reg类型
					  //定义一个计数器

	//计数过程
    always@(possdge 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 ;   //可写可不写


    //产生进位输出信号
    assign  Cout = (cin == 1'b1 && cnt == 4'd9) ;
    //当计数器计数值为9 并且 cin为1时, Cout=1
    
    
    assign q = cnt; //把cnt的值传给q 实时输出到外部
 endmodule

再次仿真
在这里插入图片描述
可以看到 这次没有滞后 都是直接产生的

发布了32 篇原创文章 · 获赞 2 · 访问量 632

猜你喜欢

转载自blog.csdn.net/helloworld573/article/details/104550287