Verilog基础知识-——计数器设计以及任意分频设计与modelsim仿真

计数器的逻辑功能:记录时钟脉冲的个数

1、 模10计数器的设计与仿真

现要求设计模10计数器,0到9循环累加,计数满清0。

 module Count_1(
    input clk,
	input rst_n,
	
	output reg [3:0] cnt	    
);
 
always@(posedge clk or negedge rst_n)
    if(!rst_n)
	    cnt <= 4'd0; 
    else if(cnt == 4'd9)
	    cnt <= 4'd0;
	else 
	    cnt <= cnt + 1'b1;

endmodule 

综合出的RTL:
在这里插入图片描述

testbench仿真:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期
module Count_1_tb;

    reg clk;
	reg rst_n;
	
	wire [3:0] cnt;

Count_1 u1(
          .clk(clk),
		  .rst_n(rst_n),
		  .cnt(cnt)
);
//产生时钟激励
initial	 clk = 0;
always #(`Clock/2) clk= ~clk;

//产生复位激励
initial begin
   rst_n=0; #(`Clock*5);
   rst_n=1;

#500
$stop;
end	
endmodule

波形如下:复位拉高,计数器实现从0-9的计数,每当计数到9后即可清零。
在这里插入图片描述

2、加入使能信号

设计带使能的模10计数器。当复位拉高且使能信号有效的时候开始0到9循环累加计数,计数满清0.

verilog代码:

 module Count_1(
    input clk,
	input rst_n,
	input en,
	
	output reg [3:0] cnt	    
);
 
always@(posedge clk or negedge rst_n)
    if(!rst_n)
	    cnt <= 4'd0; 
	 else if(en)begin
        if(cnt == 4'd9)
	        cnt <= 4'd0;
	     else 
	        cnt <= cnt + 1'b1;
	end
	else
	    cnt <= cnt;

endmodule 

生成的RTL图:
在这里插入图片描述

tb仿真文件:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期
module Count_1_tb;

    reg clk;
	reg rst_n;
	reg en;
	
	wire [3:0] cnt;

Count_1 u1(
          .clk(clk),
		  .rst_n(rst_n),
		  .cnt(cnt),
		  .en(en)
);
//产生时钟激励
initial	 clk = 0;
always #(`Clock/2) clk= ~clk;

//产生复位激励和输入
initial begin
   rst_n=0;
	en = 0;
	#(`Clock*5);
   rst_n=1;
	#(`Clock*2);
	en = 1;
   #500
   $stop;
end	
endmodule

波形可看到,复位拉高后并没有直接开始计数,只有当en信号有效的时候,才能开始计数。

在这里插入图片描述

3、先递增后递减的计数器设计与仿真

设计一个计数器,先递增,递增到一定数后开始递减,递减到一定数后又递增,循环反复
.
复位拉高且使能信号有效,进行计数。
当递增标志信号有效且未增到9,则计数器+1
当递减标志信号有效且未减到0,则计数器-1
递增信号、递减信号

module Count_1(
		input         clk                 , 
		input         rst_n               , 
		input         en                  ,
		
		output reg    [3:0]cnt               ,
		output reg    flag_x   //递增递减的标志信号
);


always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        cnt <= 0;
	 else if(en)begin
       if(flag_x==0 && cnt<9) //递增有效且计数小于9
        cnt <= cnt + 1;
     else if(flag_x==1 && cnt>0)//递减有效且计数大于0
        cnt <= cnt - 1;
		end
	 else 
	      cnt <= 0;
end

//生成递增递减的标志信号
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        flag_x <= 0;
    else if(flag_x==0 && cnt==9)
        flag_x <= 1;
    else if(flag_x==1 && cnt==0)
        flag_x <= 0;
end
endmodule

tb仿真文件:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期
module Count_1_tb;

    reg clk;
	reg rst_n;
	reg en;
	
	wire [3:0] cnt;
	wire flag_x;

Count_1 u1(
          .clk(clk),
		  .rst_n(rst_n),
		  .cnt(cnt),
		  .en(en),
		  .flag_x(flag_x)
);
//产生时钟激励
initial	 clk = 0;
always #(`Clock/2) clk= ~clk;

//产生复位激励和输入
initial begin
   rst_n=0;
	en = 0;
	#(`Clock*5);
   rst_n=1;
	#(`Clock*2);
	en = 1;
   #500
   $stop;
end	
endmodule

波形如下:
当en信号有效且flag_x为低电平,计数器小于9的时候,开始了0-9递增计数;当计数到9且flag_x为高电平,表示开始递减计数,于是从9-0;
在这里插入图片描述

4、二分频(用D触发器实现)

Verilog代码:

module Count_1(
		input         clk   , 
		input         rst_n , 
		
		output reg    out
);

always @(posedge clk or negedge rst_n) 
    if (!rst_n)
        out <= 0;
	 else 
	     out <= ~out;
endmodule

RTL图:
在这里插入图片描述

tb测试文件:

`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期
module Count_1_tb;
    reg clk;
	reg rst_n;
	wire out;
	
Count_1 u1(
        .clk(clk),
		  .rst_n(rst_n),
		  .out(out)
);

//产生时钟激励
initial	 clk = 0;
always #(`Clock/2) clk= ~clk;

//产生复位激励和输入
initial begin
   rst_n=0;
	#(`Clock*5);
	rst_n=1;
	#(`Clock*5);
   #500
   $stop;
end	
endmodule

可看到输出的一个周期中,包含两个clk脉冲,因此实现了二分频。
在这里插入图片描述

5、三分频

由div3可看到,其为clk的三分频信号。pos_cnt为clk上升沿计数器,neg_cnt为下降沿计数器。由于是三分频,因此计数三个clk的上升和三个clk的下降沿即可,最后进行逻辑或运算得到div3.

在这里插入图片描述

verilog代码:

module Count_1(

	input rst_n,
	input clk,
	
	output reg [1:0] pos_cnt,  //上升沿计数器
	output reg [1:0] neg_cnt,  //下降沿计数器
	
	output reg neg_cnt_0,  //上升沿脉冲信号
	output reg pos_cnt_0, //下降沿脉冲信号
	
	output div3_o//输出三分频
 
);


//上升沿计数且每计数到2清零
always@(posedge clk or negedge rst_n) begin 
	if(!rst_n)
		pos_cnt<=2'd0;
	else if(pos_cnt==2'd2) 
		pos_cnt<=2'd0;
	else
		pos_cnt<=pos_cnt+1'b1;
end

 //下降沿计数且每计数到2清零
always@(negedge clk or negedge rst_n)begin  

	if(!rst_n)	
		neg_cnt<=2'd0;
	else if(neg_cnt==2'd2)
		neg_cnt<=2'd0;
	else
		neg_cnt<=neg_cnt+1'b1;
end

//产生两个时钟沿的脉冲信号
always@(posedge clk or negedge rst_n) 
begin
	if(!rst_n)	
		pos_cnt_0<=1'b0;
	else if (pos_cnt == 2'd1)
	   pos_cnt_0<=1'b1;
	else
      pos_cnt_0<=1'b0;
end		
		
always@(negedge clk or negedge rst_n) 
begin
	if(!rst_n)	
		neg_cnt_0<=1'b0;
	else if (neg_cnt == 2'd1)
	   neg_cnt_0<=1'b1;
	else
      neg_cnt_0<=1'b0;	
end	
assign div3_o = pos_cnt_0 | neg_cnt_0; 

endmodule 

tb测试文件:


`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module Count_1_tb;

   reg rst_n;
   reg clk;
   wire  [1:0] pos_cnt;  //上升沿计数
   wire  [1:0] neg_cnt;  //下降沿计数
   wire pos_cnt_0;
   wire neg_cnt_0;
   wire div3_o;
		
Count_1 u1(
		.clk(clk),
		.rst_n(rst_n),
		.pos_cnt(pos_cnt),
		.neg_cnt(neg_cnt),
		.neg_cnt_0(neg_cnt_0),
		.pos_cnt_0(pos_cnt_0),
		.div3_o(div3_o)
	);
	
initial clk = 0;
	always #(`Clock/2) clk= ~clk;
	
initial begin
	   rst_n=0 ;
		#(`Clock*20);
	   rst_n=1;
	   #(`Clock*100);
	   $stop;		
end	
	
endmodule 

波形仿真:
在这里插入图片描述

6、任意分频(占空比为50%)

任意分频通过计数器实现,但需要注意的是任意分频电路分为两种:奇数分频和偶数分频。偶数分频可直接采用计数器实现,而奇数分频还需要利用组合逻辑。
.
建议在设计过程中采用参数化设计,这样就可以随时改变参量以得到不同的分频需要。
.
在对时钟要求不是很严格的FPGA系统中,分频通常都是通过计数器的循环计数来实现的,否则将采用PLL来实现。

6.1 任意偶数N分频方式

方法1、先得到1Mhz的时钟,然后每(N/2-1 )和 N-1进行翻转
.
方法2、设计一个 N/2计数器,计数到(N/2-1)清零,然后每(N/2)-1 进行翻转。

例1:通过1Mhz时钟的方式进行偶数分频。

系统时钟为50Mhz,假如要产生1Mhz的时钟,则需要对系统时钟进行分频处理,50分频为偶数分频,可以采用计数的方式进行实现,50/1=50,则计数到49次的时候清零,否则进行+1计数,然后产生1Mhz的时钟频率

module Count_1(

input rst_n,
input clk,
output reg [7:0]cnt,  //上升沿计数
output reg out

);

always@(posedge clk or negedge rst_n )  
begin
	if(!rst_n)
		cnt<=1'b0;
	else if(cnt==8'd49)begin
		cnt<=1'b0;
	 end
	else
		cnt<=cnt+1'b1;
end

always@(posedge clk or negedge rst_n )  
begin
	if(!rst_n)
		out <= 0;
	else if(cnt ==8'd24 | cnt ==8'd49  )begin
		out <= ~out;
	 end
	else
		out <= out;
end

endmodule 
`timescale 1ns/1ps //时间精度
`define Clock 20 //时间周期

module Count_1_tb;

		reg rst_n;
		reg clk;
		wire [7:0] cnt;  //上升沿计数
		wire out;
	
Count_1 counter
			(
			  .clk(clk),
			  .rst_n(rst_n),
			  .cnt(cnt),
			  .out(out)
);
initial	clk = 0;
always #(`Clock/2) clk= ~clk;

initial begin
   rst_n=0 ;
	#(`Clock*20);
   rst_n=1;
   #(`Clock*150);
   $stop;
end	
endmodule

波形如下 :
此时的计数器cnt为50计数器。我们让其在中间24和49的位置进行翻转,最终得到了周期为1000ns的输出,对应的时钟频率为1Mhz
在这里插入图片描述


例2:通过设计N/2计数器的方式进行偶数4分频。

module Count_1(
		input         clk   , 
		input         rst_n , 
		
		output reg    out
);
reg [2:0] cnt;

always @(posedge clk or negedge rst_n) 
    if (!rst_n)
        cnt <= 0;
	 else if(cnt == 1)
	     cnt <= 0;
	 else
	     cnt <= cnt + 1;
		  
		  
always @(posedge clk or negedge rst_n) 
    if (!rst_n)
        	out  <= 0;
			
	 else if(cnt == 1)
	      out  <= ~out;
		  
		  
endmodule

tb测试文件:


`timescale 1ns/1ps //时间精度
`define Clock 20

module Count_1_tb;

		reg clk;
		reg rst_n;
		
		wire out;  //上升沿计数
		
Count_1 inst_Count_1 (
    .clk(clk), 
    .rst_n(rst_n),
     .out(out)
    );

initial clk = 0;
always 	#(`Clock/2) clk = ~clk;
	

initial begin
   rst_n = 0;
	#20;
	rst_n = 1;
   #(`Clock*150);
   $stop;
end	
endmodule

在这里插入图片描述

6.2 任意奇数N分频方式

方法:

第一步:设计N计数器(加到N-1清零)
.
第二步:产生上升沿分频信号和下降沿分频信号【都分别在(N-1)/2 和 N-1 处进行翻转 】
.
第三步:对第二步中的两个信号进行或运算。

例子:进行三分频设计:

如下为三分频的原理,设计模3计数器,分别进行时钟上升沿和下降沿的相应检测,输出的信号进行或运算。
在这里插入图片描述
verilog代码:

module Count_1(
		input         clk   , 
		input         rst_n , 
		
		output        out
);
reg [1:0] cnt;
reg pos_div;
reg neg_div;

always @(posedge clk or negedge rst_n) 
    if (!rst_n)
        cnt <= 0;
	 else if(cnt == 2)
	     cnt <= 0;
	 else
	     cnt <= cnt + 1;
		  

//上升沿分频信号		  
always @(posedge clk or negedge rst_n) 
    if (!rst_n)
        	pos_div  <= 0;
			
	 else if(cnt == 1)
	      pos_div  <= ~pos_div;
	 else if(cnt == 2)
	      pos_div  <= ~pos_div;
	 else 
	     pos_div  <= pos_div;
		  
//下降沿分频信号
always @(negedge clk or negedge rst_n) 
    if (!rst_n)
        	neg_div  <= 0;
			
	 else if(cnt == 1)
	      neg_div  <= ~neg_div;
	 else if(cnt == 2)
	      neg_div  <= ~neg_div;
	 else 
	     neg_div  <= neg_div;
//或运算
assign out = pos_div | neg_div;

	
		  
endmodule

tb测试文件同上。
波形如下:直接看分频出来的out信号的周期是60ns,说明三分频成功。

在这里插入图片描述

产生iic的scl 250khz时钟频率

方法:先50分频产生1Mhz时钟,然后4分频产生250Khz

module Count_1(

    input clk,
    input rst_n,


    output i2c_scl,  //iic总线的串行时钟信号250Khz
    output i2c_clk  //1Mhz

    );
	
reg [5:0] clk_1_cnt;
reg [1:0] clk_1_4_cnt;
reg clk_1; //1Mhz
reg clk_1_4;//250Khz

//通过系统时钟50Mhz得到1Mhz时钟
//产生50计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_1_cnt <= 0;
    end
    else if (clk_1_cnt == 6'd49) begin
        clk_1_cnt <= 0;
    end
    else begin
        clk_1_cnt <= clk_1_cnt + 1;
    end
end
//每计数49和计数24的时候进行翻转,即可生成一个1Mhz的时钟
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_1 <= 0;
    end
    else if (clk_1_cnt == 6'd49 | clk_1_cnt == 6'd24) begin
        clk_1 <= ~ clk_1;
    end
    else begin
        clk_1 <= clk_1;
    end
end

//对1Mhz时钟进行四分频
//产生4计数器
always @(posedge clk_1 or negedge rst_n) begin
    if (!rst_n) begin
        clk_1_4_cnt <= 0;
    end
    else if (clk_1_4_cnt == 2'd3) begin
        clk_1_4_cnt <= 0;
    end
    else begin
        clk_1_4_cnt <= clk_1_4_cnt + 1;
    end
end
//每计数1和计数3的时候进行翻转,即可生成一个250khz的时钟
always @(posedge clk_1 or negedge rst_n) begin
    if (!rst_n) begin
        clk_1_4 <= 0;
    end
    else if (clk_1_4_cnt == 2'd3 | clk_1_4_cnt == 2'd1  ) begin
        clk_1_4 <= ~clk_1_4;
    end
    else begin
        clk_1_4 <= clk_1_4;
    end
end
assign i2c_clk = clk_1;
assign i2c_scl = clk_1_4;
endmodule

tb仿真:


`timescale 1ns/1ps //时间精度
`define Clock 20

module Count_1_tb;

		reg clk;
		reg rst_n;
		

		wire i2c_scl;
		wire i2c_clk;


Count_1 inst_Count_1
		(
			.clk     (clk),
			.rst_n   (rst_n),
			.i2c_scl (i2c_scl),
			.i2c_clk (i2c_clk)
		);


initial clk = 0;
always 	#(`Clock/2) clk = ~clk;
	

initial begin
   rst_n = 0;
	#20;
	rst_n = 1;
   #(`Clock*300);
   $stop;
end	



endmodule

在这里插入图片描述

直接利用200分频,生成250khz时钟

module Count_1(

    input clk,
    input rst_n,

    output i2c_clk  //250Khz
	 
    );
	
reg [7:0] clk_1_cnt;

reg clk_1; 


//通过系统时钟50Mhz得到250khz时钟
//产生200计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_1_cnt <= 0;
    end
    else if (clk_1_cnt == 8'd199) begin
        clk_1_cnt <= 0;
    end
    else begin
        clk_1_cnt <= clk_1_cnt + 1;
    end
end
//每计数199和计数99的时候进行翻转,即可生成一个1Mhz的时钟
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_1 <= 0;
    end
    else if (clk_1_cnt == 8'd199 | clk_1_cnt == 8'd99) begin
        clk_1 <= ~ clk_1;
    end
    else begin
        clk_1 <= clk_1;
    end
end


assign i2c_clk = clk_1;
endmodule

在这里插入图片描述

更多计数器的学习

  • 15
    点赞
  • 157
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Verilog分频计数器是一种用于对系统时钟进行分频处理的电路。根据引用\[1\]和引用\[2\]的描述,分频器可以分为偶数分频和奇数分频两种方式。 对于偶数分频,最简单的二分频可以通过在原时钟的上升沿进行输出信号翻转来实现。而对于更高的偶数分频比如4分频,可以使用计数器,在计数器计到2个上升沿的时候进行输出信号翻转。具体来说,计数器的范围为0-(N-1),其中N为偶数,选择一个值K,当计数器在0~K范围内时,输出信号为低电平;在(K+1)-(N-1)范围内为高电平,从而实现了分频。这样的偶数分频器可以通过参数化设计来灵活地改变分频比例\[1\]。 对于奇数分频,最简单的三分频无法直接使用计数器进行实现。根据引用\[2\]的描述,正确的思路是取两路上升沿和下降沿信号,然后对这两路信号取或。具体来说,可以使用计数器在0-2之间循环计数,控制输出1个高电平,2个低电平的信号1,然后将信号1延迟半个周期得到信号2,最后将信号1与信号2相与得到50%占空比的3分频信号。对于其他奇数分频,可以使用类似的方法进行设计\[2\]。 根据引用\[3\]的例子,如果系统时钟为50MHz,要产生1MHz的时钟,则可以进行50分频。可以使用计数器进行实现,当计数器计到49次时清零,否则进行+1计数。同时,根据计数器的值,可以控制输出信号的翻转,从而得到1MHz的时钟频率。 综上所述,Verilog分频计数器可以根据需要选择偶数分频或奇数分频的方式,并通过计数器和组合逻辑来实现所需的分频比例。 #### 引用[.reference_title] - *1* *3* [Verilog基础知识-——计数器设计以及任意分频设计modelsim仿真](https://blog.csdn.net/H19981118/article/details/115353714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Verilog分频器](https://blog.csdn.net/qq_39586852/article/details/125836784)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting_FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值