BCD計數器設計與驗證


第一部分:單個BCD計數器

一、BCD計數器原理

  • BCD碼的特點:用4位二進制數,來表示一位十進制數(0~9)。
  • 類似於4位二進制計數器,但4位二進制計數器需要計數到1111然后才返回0000,而十進制計數器要求計數到1001(十進制的9)就返回0000。BCD計數器是一種常見的十進制計數器。
  • 而4位二進制就相當於1位十六進制,因此看十六進制更方便。

二、RTL圖

三、代碼編寫

1、BCD_Counter 模塊

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;  //定義 計數器寄存器(counter)
	
//執行計數過程
	always@(posedge Clk or negedge Rst_n) begin
		if(Rst_n == 1'b0)
			cnt <= 4'b0;
		else if(Cin == 1'b1)begin
			if(cnt == 4'd9)
				cnt <= 4'd0;
			else 
				cnt <= cnt + 1'b1;		
		end
		else 
			cnt <= cnt;
	end
	
	
//產生進位輸出信號	
	always@(posedge Clk or negedge Rst_n) begin
		if(Rst_n == 1'b0)
			Cout <= 4'b0;
		else if(Cin == 1'b1 && cnt == 4'd9)
			Cout <= 1'b1;
		else
			Cout <= 1'b0;
	end	

	assign q = cnt;
	
endmodule 

2、testbench 代碼

`timescale 1ns/1ns

`define clock_period 20 //系統時鍾20ns(50MHZ)

module BCD_Counter_tb;

//激勵信號定義,對應連接到待測模塊輸入端口。 reg型
	reg Clk;
	reg Cin;
	reg Rst_n;

//待檢測信號定義,對應連接到待測試模塊的輸出端口。 wire型	
	wire Cout;
	wire[3:0] q;

//例化待測試模塊	
	BCD_Counter BCD_Counter0(
		.Clk(Clk), 
		.Cin(Cin), 
		.Rst_n(Rst_n), 
		.Cout(Cout), 
		.q(q)
		);
	
	
//產生時鍾信號
	initial Clk = 1'b1;
	always#(`clock_period/2) Clk = ~Clk;
	
	
//產生 Cin激勵信號 和 Rst_n復位信號
	initial begin
		Rst_n = 0; //首先系統處於復位狀態
		Cin = 1'b0;
		#(`clock_period*200); //延時200個系統時鍾周期
		Rst_n = 1'b1; //系統開始運行
		#(`clock_period*20);
		
		repeat(30) begin //重復執行30次。1個周期高電平,5個周期低電平。
			Cin = 1'b1;
			#`clock_period;
			Cin = 1'b0;
			#(`clock_period*5);		
		end
		
		#(`clock_period*20);
		$stop;
	
	end
	
endmodule 

四、波形圖

結果:每計數到9,進位輸出:Cout = 1 ,計數器清零。

五、內部結構


第二部分:三個BCD計數器的級聯

一、RTL圖

testbench:

二、代碼編寫

1、BCD_Counter_top 模塊 (設置為 “頂層文件”)

注意:q 是12位。q0 是低位,q2 是高位。

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

	input Clk; //計數基准時鍾
	input Cin; //計數器進位輸入
	input Rst_n; //系統復位
	
	output Cout; //計數器進位輸出
	output[11:0] q; //計數器輸出
	
	wire Cout0,Cout1;
	wire[3:0] q0,q1,q2;
	
	assign q = {q2,q1,q0};
	
	BCD_Counter BCD_Counter0(
		.Clk(Clk), 
		.Cin(Cin), 
		.Rst_n(Rst_n), 
		.Cout(Cout0), 
		.q(q0)
		);
		
	BCD_Counter BCD_Counter1(
		.Clk(Clk), 
		.Cin(Cout0), 
		.Rst_n(Rst_n), 
		.Cout(Cout1), 
		.q(q1)
		);
		
	BCD_Counter BCD_Counter2(
		.Clk(Clk), 
		.Cin(Cout1), 
		.Rst_n(Rst_n), 
		.Cout(Cout), 
		.q(q2)
		);

endmodule 

2、BCD_Counter_top_tb testbench


`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), 
		.Rst_n(Rst_n), 
		.Cout(Cout), 
		.q(q)
		);
	
	
//產生時鍾信號
	initial Clk = 1'b1;
	always#(`clock_period/2) Clk = ~Clk;
	
	
//產生 Cin激勵信號 和 Rst_n復位信號
	initial begin
		Rst_n = 0; //首先系統處於復位狀態
		Cin = 1'b0;
		#(`clock_period*200); //延時200個系統時鍾周期
		Rst_n = 1'b1; //系統開始運行
		#(`clock_period*20);
		Cin = 1'b1;
	//直接就讓 Cin = 1 ,不再設置Cin為周期信號了。
		#(`clock_period*3000);
		$stop;
	
	end
	
endmodule
 

注意:

  • 1、頂層的 q 是12位
  • 2、直接就讓 Cin = 1 ,不再設置Cin為周期信號了。
    對比之前的圖:

現在的 Cin :

三、仿真結果

波形存在錯誤:999 之后 不是 000, 而是999 -> 990 -> 901 -> 002

1. 錯誤分析步驟:

(1)添加子模塊波形

(2)對信號進行分組

Ctrl + A 全選信號
Ctrl + G 對信號智能分組

(3)分組完 restart 重新啟動一下

(4)波形分析

Cout 一直滯后,因為有D觸發器,導致了延遲。

2. 修改代碼

修改方法:把always改成assign

波形圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM