8位可控加减法电路设计_常用电路设计——“分频电路”

058dca60f9027070fadbc0887b82e363.png
欢迎大家关注“数字IC剑指offer”,分享秋招实用干货

在数字IC秋招过程中我们发现,不论是在笔试还是面试中,针对数字逻辑电路基础知识的考察还是不少的,其中就包括一些常用电路的分析、设计以及Verilog代码实现。从本期开始,数字前端版块开始推出”常用电路设计“专题,本期将详细介绍分频电路的设计。

分频电路是数字电路中常见的逻辑电路类型。在时序逻辑电路中,时钟是必不可少的,但对于时钟要求不高的基本设计,自行设计的分频电路,也就是时钟分频器,有时候比采用外部PLL更为简单、有效、快速。

本期目录:

1、偶数分频

(1) 用D触发器级联实现

(2) 用计数器实现

2、奇数分频

(1) 占空比非50%的奇数分频

用Moore状态机实现

用计数器实现

(2) 占空比50%的奇数分频

(3) 利用基本逻辑单元直接搭建占空比为50%的奇数分频电路

3、小数/分数分频

1、偶数分频

(1)用D触发器级联实现

将主时钟以2为幂次进行分割可以得到同步偶数分频时钟,即21,22,23...分频。电路上可采用D触发器实现,n个触发器可以构成2n次偶数分频。如图1所示,为2分频、4分频电路设计及波形。

cc1f02acf9902bead70b1ef5312022cc.png
(a)2分频电路及波形

b7c56b062a874c40816678c3dd348375.png
(b)4分频电路及波形

图1 偶数分频电路设计

(2)用计数器实现

用D触发器级联搭建分频电路只能实现2,4,8,16等分频,对于一般的偶数分频,可以通过计数器实现:若要实现N分频(N为偶数),只需将计数器在待分频时钟上升沿触发下循环计数,从0计数到(N/2 -1)后将输出时钟翻转即可实现。Verilog代码如下:

// N分频器,N为偶数,偶数分频,占空比为50%
module Even_Freq_Div_N (
 input clk_in,
 input rst_n,
 output reg clk_out
);

reg [3:0] cnt;
parameter N = 6;

always @(posedge clk_in or negedge rst_n)
begin
 if(!rst_n)
  begin
   cnt <= 4'b0000;
   clk_out <= 1'b0;
  end
 else if (cnt == (N/2-1))
  begin
   clk_out <= ~clk_out;
   cnt <= 4'b0000;
  end
 else
  cnt <= cnt + 1'b1;
end

endmodule

上述代码实现的是占空比为50%的6分频电路,若实现占空比为50%的其他偶数分频,只需修改参数N及cnt的位宽即可。

2、奇数分频

(1)占空比非50%的奇数分频

① 用Moore状态机实现

以7分频为例,通过如图2所示Moore状态机即可实现输入时钟的7分频。

6b7dc1a9cb18febd8fe6864619da103b.png
图2 7分频电路Moore状态机

值得注意的是,上图实现的7分频的占空比并非50%。具体的Verilog如下:

//N分频器,N为奇数,奇数分频,占空比非50%
module Odd_Freq_Div_N (  
 input clk_in,
 input rst_n,
 output clk_out
 
);

parameter State_0 = 3'b000;
parameter State_1 = 3'b001;
parameter State_2 = 3'b010;
parameter State_3 = 3'b011;
parameter State_4 = 3'b100;
parameter State_5 = 3'b101;
parameter State_6 = 3'b110;

reg [2:0] CS,NS;

always @(posedge clk_in or negedge rst_n)
begin
 if(!rst_n)
  CS <= State_0;
 else
  CS <= NS;
end

always @(*)
begin
 if(!rstn)
  NS = State_0;
 else
    begin
   case(CS)
    State_0: NS = State_1;
    State_1: NS = State_2;
    State_2: NS = State_3;
    State_3: NS = State_4;
    State_4: NS = State_5;
    State_5: NS = State_6;
    State_6: NS = State_0;
    default: NS = State_0;
   endcase
  end
end

always @(posedge clk_in or negedge rst_n)
begin
 if(!rst_n)
  clk_out <= 1'b0;
 else
  begin
   case(NS)
    State_0: clk_out <= 1'b0;
    State_1: clk_out <= 1'b0;
    State_2: clk_out <= 1'b0;
    State_3: clk_out <= 1'b0;
    State_4: clk_out <= 1'b1;
    State_5: clk_out <= 1'b1;
    State_6: clk_out <= 1'b1;
    default: clk_out <= 1'b0;
   endcase
  end
end

endmodule

② 用计数器实现

其实用状态机实现占空比非50%的分频电路还是比较麻烦的,可以采用计数器的方法:若要实现N分频(N为奇数),只需将计数器在待分频时钟上升沿触发下循环计数,从0计数到(N-1)后计数器清零。当计数到(N-1)/2后将输出时钟翻转,计数到0后再次翻转即可实现。7分频的Verilog代码如下:

//N分频器,N为奇数,奇数分频,占空比非50%
module Odd_Freq_Div_N (    
  input clk_in,
  input rst_n,
  output clk_out

);

parameter N = 7;

reg [2:0] cnt_p;
reg       clk_p;

always @(posedge clk_in or negedge rst_n)
begin
  if(!rst_n)
    cnt_p <= 3'b000;
  else if (cnt_p == N-1)
    cnt_p <= 3'b000;
  else
    cnt_p <= cnt_p + 1'b1;
end

always @(posedge clk_in or negedge rst_n) 
begin
  if(!rst_n)
    clk_p <= 1'b0;
  else if (cnt_p == (N-1)/2)
    clk_p <= ~clk_p;
  else if (cnt_p <= 3'b000)
    clk_p <= ~clk_p;
  else
    clk_p <= clk_p;
end

endmodule

不管是用状态机实现,还是用计数器实现,本质上都是控制输出时钟在每N个待分频时钟周期内完成一次周期性输出。

(2)占空比50%的奇数分频

对于奇数分频,就是分别利用待分频时钟的上升沿触发生成一个时钟,然后用下降沿触发生成另一个时钟,然后将两个时钟信号进行或/与运算得到占空比为50%的奇数分频。上面一小节已经介绍了如何利用待分频时钟的上升沿触发生成占空比非50%的时钟,只需再类似地利用待分频时钟的下降沿触发生成占空比非50%的时钟。具体方法详述如下:

① 设计2个分别用上升、下降沿触发的计数器

定义2个计数器cnt_p和cnt_n,分别利用时钟的上升沿和下降进行触发计数

② 利用上升、下降沿计数器生成两个分频时钟clk_p和clk_n

定义2个时钟信号clk_p和clk_n, 对于上升沿计数器cnt_p,当计数到0或者(N-1)/2时,均翻转clk_p信号;对于下降沿计数器cnt_n,当计数到0或者(N-1)/2时,均翻转clk_n信号。

③ 利用clk_p和clk_n通过逻辑运算生成占空比为50%的分频时钟

若clk_p和clk_n初始复位为0,将2个时钟clk_p和clk_n通过或运算即可生成占空比为50%的分频时钟,且clk_out上升沿和原时钟上升沿对齐。

读者可以思考下,如果clk_p和clk_n初始复位为1,需要使用什么逻辑运算才能生成占空比50%的分频时钟?

占空比为50%的奇数分频(以7分频为例)的Verilog代码如下:

//N分频器,N为奇数,奇数分频,占空比50%
module Odd_Freq_Div_N (  
 input clk_in,
 input rst_n,
 output clk_out
 
);

parameter N = 7;

reg [3:0] cnt_p, cnt_n;
reg       clk_p, clk_n;

always @(posedge clk_in or negedge rst_n)
begin
 if(!rst_n)
  cnt_p <= 4'b0000;
 else if (cnt_p == N-1)
  cnt_p <= 4'b0000;
 else
  cnt_p <= cnt_p + 1'b1;
end

always @(negedge clk_in or negedge rst_n)
begin
 if(!rst_n)
  cnt_n <= 4'b0000;
 else if (cnt_n == N-1)
  cnt_n <= 4'b0000;
 else
  cnt_n <= cnt_n + 1'b1;
end

always @(posedge clk_in or negedge rst_n) 
begin
 if(!rst_n)
  clk_p <= 1'b0;
 else if (cnt_p == (N-1)/2)
  clk_p <= ~clk_p;
 else if (cnt_p <= 4'b0000)
  clk_p <= ~clk_p;
 else
  clk_p <= clk_p;
end

always @(negedge clk_in or negedge rst_n)
begin
 if(!rst_n)
  clk_n <= 1'b0;
 else if (cnt_n == (N-1)/2)
  clk_n <= ~clk_n;
 else if (cnt_n == 4'b0000)
  clk_n <= ~clk_n;
 else
  clk_n <= clk_n;
end

assign clk_out = clk_p | clk_n;

endmodule

详细的波形图如图3所示:

abcddaabe8964d2d1e7d0295eae71203.png
图3 占空比为50%的7分频电路波形生成

还有一种更简便的方法只需要一个计数器cnt_p就可以,通过cnt_p产生clk_p时钟,然后直接用待分频时钟下降沿对时钟clk_p打半拍得到时钟clk_n,最后将clk_p和clk_n相或就可以得到占空比为50%的7分频时钟。

(3)利用基本逻辑单元直接搭建占空比为50%的奇数分频电路

上面我们从波形生成方法及Verilog实现的角度思考了如何设计占空比为50%的奇数分频电路,这里我们直接从电路角度出发进行设计。

首先思考如何用D触发器和组合逻辑实现占空比为50%的三分频电路?

思路:先使用触发器构成序列生成器,输出001循环脉冲,实现占空比非50%的三分频,然后用负沿触发器打一拍,再相或。由于001循环共三个状态,故需2个D触发器。通过列状态表、画卡诺图,得到由两个D触发器及逻辑门构成的001序列生成器,后接负沿触发器打一拍并将其输出与序列生成器的输出相或,即得到占空比为50%的三分频电路。

下面贴出三分频和五分频电路的简略设计思路及过程仅供参考,如图4、图5所示。

df2dd5d26e268dd94ef467fc34816194.png
图4 三分频电路设计思路及过程

282395200668376521062076d516ff4f.png
图5 五分频电路设计思路及过程

3、小数/分数分频

小数分频电路可以转化为特定分频比电路设计问题。如19/9分频,意味着在输入时钟clk_in的19个周期内,输出需产生9个脉冲。因为19/9 = 2.11..., 因此可以用2分频和3分频配合实现,设待分频时钟的19个周期内共有x个二分频时钟周期,y个三分频时钟周期,则有:

x+y=9

2x+3y=19

解得x=8,y=1。即只要在待分频时钟的19个周期内控制输出8个二分频时钟周期和1个三分频时钟周期即可。具体代码思路:

1)首先一个总的计数器,在0-18循环;

2)其次设计两个分别生成2分频和3分频的计数器,根据总计数器的数值范围分别在0-1和0-2循环;

3)最后是波形生成逻辑,根据总计数器和2、3分频计数器的数值控制输出脉冲翻转生成期望分频比的时钟。

19/9的分频电路代码如下,其余分频比也可参考:

// M/N小数分频,M为分子,N为分母
module Dec_Freq_Div_M_N(
 input clk,
 input rstn,
 output clk_out
);

reg [5:0] cnt;
reg [3:0] cnt_a;
reg [3:0] cnt_b;
reg clk_out_reg;
assign clk_out = clk_out_reg;

// div_a和div_b分别为根据前述公式计算出来的基准分频系数
// change为2、3分频时钟的切换点
parameter M = 6'd19;
parameter change = 6'd16;
parameter div_a = 5'd2;
parameter div_b = 5'd3;

//总计数器
always @(posedge clk or negedge rstn) begin
 if(!rstn)
  cnt <= 6'b0;
 else begin
  if(cnt == M - 1'b1)
   cnt <= 6'b0;
  else
   cnt <= cnt + 1'b1;
 end 
end 

//产生2、3分频的计数器
always @(posedge clk or negedge rstn) begin 
 if(!rstn) begin
  cnt_a <= 4'b0;
  cnt_b <= 4'b0;
 end 
 else if(cnt<=change-1'b1) begin
  cnt_b <= 4'd0;
  if(cnt_a == div_a - 1'b1)
   cnt_a <= 4'd0;
  else
   cnt_a <= cnt_a + 1'b1;
 end 
 else if(cnt>change-1'b1) begin
  cnt_a <= 4'd0;
  if(cnt_b == div_b - 1'b1)
   cnt_b <= 4'd0;
  else
   cnt_b <= cnt_b + 1'b1;
 end

//输出时钟产生逻辑
always @(posedge clk or negedge rstn) begin
 if(!rstn)
  clk_out_reg <= 1'b0;
 else if(cnt<change) begin
  if(cnt_a == 4'd0 || cnt_a == div_a/2)
   clk_out_reg <= ~clk_out_reg;
  else
   clk_out_reg <= clk_out_reg;
 end 
 else if(cnt>=change) begin
  if(cnt_b == 4'd0 || cnt_b == (div_b - 1'b1)/2)
   clk_out_reg <= ~clk_out_reg;
  else
   clk_out_reg <= clk_out_reg;
 end 
end 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值