设计一个1-8分频电路?要求占空比50%

发布时间 2023-08-04 11:35:31作者: 余你余生

请设计一个1-8分频电路,占空比50%。

这样的分频电路其中有奇分频和偶分频,需要在一个电路中实现。其中奇分频和偶分频是在输入确定的分频值下,对其进行相应的奇偶分频。

给出设计的代码&激励&仿真波形

module  fenpin_8
(
input              sys_clk            ,
input              sys_rst_n          ,
input    [3:0]     in                 ,
output             clk_out
);
//分频参数1-8
parameter    DIV1=       1;
parameter    DIV2=       2;
parameter    DIV3=       3;
parameter    DIV4=       4;
parameter    DIV5=       5;
parameter    DIV6=       6;
parameter    DIV7=       7;
parameter    DIV8=       8;

reg  [7:0]       fen_en     ;  //由输入决定对应的分频使能信号是否有效
reg              clk_even   ;  //偶分频 计数翻转
reg              clk_odd    ;  //奇分频 计数翻转 上升沿
reg              clk_odd_r  ;  //奇分频  下降沿 对之前的信号打拍
reg  [3:0]       cnt        ;  //计数器  确定翻转的位置
 
always@(*) begin 
    case(in)
        DIV1 :  fen_en<=8'b0000_0001;
        DIV2 :  fen_en<=8'b0000_0010;
        DIV3 :  fen_en<=8'b0000_0100;
        DIV4 :  fen_en<=8'b0000_1000;
        DIV5 :  fen_en<=8'b0001_0000;
        DIV6 :  fen_en<=8'b0010_0000;
        DIV7 :  fen_en<=8'b0100_0000;
        DIV8 :  fen_en<=8'b1000_0000;
        default :  fen_en<=8'b0000_0000;
    endcase
end 


always@(posedge sys_clk or negedge sys_rst_n)  begin 
    if(!sys_rst_n) begin 
        clk_even<=1'b0;
        clk_odd<=1'b0;  
    end 
    else  begin 
        case(1'b1) 
            fen_en[0] :                     ;   //一分频
            fen_en[1] : clk_even<=~clk_even ;   //二分频
            fen_en[2] : begin                   //三分频
                            if(cnt==1)   clk_odd<=~clk_odd;
                            else if(cnt==2)  clk_odd<=~clk_odd;
                            else  clk_odd<=clk_odd;
                        end 
            fen_en[3] : begin                   //四分频
                            if(cnt==1)   clk_even<=~clk_even;
                            else if(cnt==3)  clk_even<=~clk_even;
                            else  clk_even<=clk_even;
                        end 
            fen_en[4] : begin                   //五分频
                            if(cnt==2)   clk_odd<=~clk_odd;
                            else if(cnt==4)  clk_odd<=~clk_odd;
                            else  clk_odd<=clk_odd;
                        end 
            fen_en[5] : begin                   //六分频
                            if(cnt==2)   clk_even<=~clk_even;
                            else if(cnt==5)  clk_even<=~clk_even;
                            else  clk_even<=clk_even;
                        end   
            fen_en[6] : begin                   //七分频
                            if(cnt==3)   clk_odd<=~clk_odd;
                            else if(cnt==6)  clk_odd<=~clk_odd;
                            else  clk_odd<=clk_odd;
                        end                         
            fen_en[7] : begin                   //八分频
                            if(cnt==3)   clk_even<=~clk_even;
                            else if(cnt==7)  clk_even<=~clk_even;
                            else  clk_even<=clk_even;
                        end     
            endcase
    end 
end 

//计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n) begin 
    if(!sys_rst_n) 
        cnt<=4'd0;
    else  begin 
        case(1'b1) 
            fen_en[0] :               ;
            fen_en[1] :               ;
            fen_en[2] : begin 
                            if(cnt==4'd2)
                                cnt<=4'd0;
                            else 
                                cnt<=cnt+1'b1;
                        end 
            fen_en[3] : begin 
                            if(cnt==4'd3)
                                cnt<=4'd0;
                            else 
                                cnt<=cnt+1'b1;
                        end 
            fen_en[4] : begin 
                            if(cnt==4'd4)
                                cnt<=4'd0;
                            else 
                                cnt<=cnt+1'b1;
                        end 
            fen_en[5] : begin 
                            if(cnt==4'd5)
                                cnt<=4'd0;
                            else 
                                cnt<=cnt+1'b1;
                        end 
            fen_en[6] : begin 
                            if(cnt==4'd6)
                                cnt<=4'd0;
                            else 
                                cnt<=cnt+1'b1;
                        end 
            fen_en[7] : begin 
                            if(cnt==4'd7)
                                cnt<=4'd0;
                            else 
                                cnt<=cnt+1'b1;
                        end                         
        endcase
    end 
end 

//奇分频 在下降沿 打拍
always@(negedge sys_clk or negedge sys_rst_n )  begin 
    if(!sys_rst_n) 
        clk_odd_r<=1'b0;
    else begin 
        case(1'b1) 
            fen_en[0] :                             ;
            fen_en[1] :                             ;
            fen_en[2] : clk_odd_r<=clk_odd          ;
            fen_en[3] :                             ;
            fen_en[4] : clk_odd_r<=clk_odd          ;
            fen_en[5] :                             ;
            fen_en[6] : clk_odd_r<=clk_odd          ;
            fen_en[7] :                             ;            
        endcase
    end 
end 

//分频输出 
assign clk_out =fen_en[0]?sys_clk : (fen_en[1]|fen_en[3]|fen_en[5]|fen_en[5])?clk_even:(                clk_odd|clk_odd_r);

endmodule 
`timescale  1ns/1ns
module  tb_fenpin_8();
reg       sys_clk           ;
reg       sys_rst_n         ;
reg[3:0]  in                ;
wire      clk_out           ;

initial  begin    //模拟激励产生
    sys_clk<=1'b0;
    sys_rst_n<=1'b0;
    in<=4'd0 ;
    #20
    sys_rst_n<=1'b1;
    #50
    in<=4'd1;
    #500
    in<=4'd0;
    #20
    in<=4'd2;
    #500;
    in<=4'd0;
    #20
    in<=4'd3;
    #500
    in<=4'd0;
    #20
    in<=4'd4;
    #500
    in<=4'd0;
    #20
    in<=4'd5;
    #500
    in<=4'd0;
    #20
    in<=4'd6;
    #500
    in<=4'd0;
    #20
    in<=4'd7;
    #500
    in<=4'd0;
    #20
    in<=4'd8;
    #500
    in<=4'd0;
    #20
    in<=4'd1;
    
end 

always #10 sys_clk<=~sys_clk ;

fenpin_8   fenpin_8_inst
(
.sys_clk      (sys_clk  )      ,
.sys_rst_n    (sys_rst_n)      ,
.in           (in       )      ,
.clk_out      (clk_out  )
);


endmodule 

 

二分频:

三分频:

五分频:

在这里题目中学会了一种新的奇分频电路。

在这里与之前的做个对比。奇分频电路如下:

module  div                //带负沿触发
#(parameter  N  =  5)      //定义分频参数
(
input     sys_clk       ,
input     sys_rst_n     ,
output    div_clk              
);

// 核心:在上下边沿的计数器 计数至 N/2 翻转  计数至 N-1 再翻转  
//  上下边沿脉冲信号 或运算   即可得到最终的 奇分频结果  占空比50%
reg             clk_pose ;     //上升沿
reg             clk_nege ;     //下降沿
reg [N:0]       cnt_pose ;     //上升沿计数
reg [N:0]       cnt_nege ;     //下降沿计数

always@(posedge sys_clk or negedge sys_rst_n) begin  //在上升沿计数
    if(!sys_rst_n)
        cnt_pose<='d0;
    else if(cnt_pose==N-1)
        cnt_pose<='d0;
    else 
        cnt_pose<=cnt_pose+'d1;
end 
always@(negedge sys_clk or negedge sys_rst_n) begin //在下升沿计数
    if(!sys_rst_n) 
        cnt_nege<=1'b0;
    else if(cnt_nege==N-1)  
        cnt_nege<='d0;
    else 
        cnt_nege<=cnt_nege+'d1;
end 

always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) 
        clk_pose<=1'b0;
    else if(cnt_pose==N/2)  
        clk_pose<=~clk_pose;
    else if(cnt_pose==N-1)  
        clk_pose<=~clk_pose;
    else 
        clk_pose<=clk_pose;
end 
always@(negedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) 
        clk_nege<=1'b0;
    else if(cnt_nege==N/2)
        clk_nege<=~clk_nege;
    else if(cnt_nege==N-1) 
        clk_nege<=~clk_nege;
    else 
        clk_nege<=clk_nege;
end

assign  div_clk= clk_nege |clk_pose ;  //上升沿 和下降沿 或运算 得到 奇分频

endmodule

来自之前的:奇分频电路如何实现? 负沿触发&非负沿触发 - 余你余生 - 博客园 (cnblogs.com)

今天学到的五分频电路如下:

module  fenpin
(
input              sys_clk            ,
input              sys_rst_n          ,
output             clk_out
);

reg              clk_odd    ;  //奇分频 计数翻转 上升沿
reg              clk_odd_r  ;  //奇分频  下降沿 对之前的信号打拍
reg  [3:0]       cnt        ;  //计数器  确定翻转的位置
 


always@(posedge sys_clk or negedge sys_rst_n)  begin  //五分频
    if(!sys_rst_n) begin 
        clk_odd<=1'b0;  
    end 
    else  begin             
        if(cnt==2)   clk_odd<=~clk_odd;
        else if(cnt==4)  clk_odd<=~clk_odd;
        else  clk_odd<=clk_odd;
    end 
            
end 

//计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n) begin 
    if(!sys_rst_n) 
        cnt<=4'd0;
    else  begin 
        if(cnt==4'd4)
            cnt<=4'd0;
        else 
            cnt<=cnt+1'b1;      
    end 
end 

//奇分频 在下降沿 打拍
always@(negedge sys_clk or negedge sys_rst_n )  begin 
    if(!sys_rst_n) 
        clk_odd_r<=1'b0;
    else 
        clk_odd_r<=clk_odd  ; 
end 

//分频输出 
assign clk_out = clk_odd|clk_odd_r;

endmodule 
`timescale  1ns/1ns
module  tb_fenpin();
reg       sys_clk           ;
reg       sys_rst_n         ;
wire      clk_out           ;

initial  begin    //模拟激励产生
    sys_clk<=1'b0;
    sys_rst_n<=1'b0;
    #20
    sys_rst_n<=1'b1;

    
end 

always #10 sys_clk<=~sys_clk ;

fenpin   fenpin_inst
(
.sys_clk      (sys_clk  )      ,
.sys_rst_n    (sys_rst_n)      ,
.clk_out      (clk_out  )
);


endmodule 

 

由此可见这种方法更简单,也更适用。奇分频采取这样的方法,简单快捷。感谢李锐博恩博主,这篇文章是基于他的之前的文章学习。

若有不对的地方,敬请指正,万分感谢。

参考资料:

1、IC/FPGA校招笔试题分析(二)任意切换的时钟分频电路_李锐博恩的博客-CSDN博客