列表

详情


VL41. 任意小数分频

描述

请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号

注意rst低电平复位

提示:

其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。

设小数为nn,此处以8.7倍分频的时钟周期为例。

首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53clkout时钟周期是10clkin时钟周期的8.7倍。

信号示意图:

波形示意图:


输入描述


输入信号 clk_in rst 
类型 wire

输出描述

输出信号  clk_out
类型  wire

原站题解

Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
    reg [6:0] cnt;
    reg [3:0] cnt1, cnt2;
    reg clk_MN;
    assign clk_out = clk_MN;
    
    always @(posedge clk_in, negedge rst) begin
        if(!rst)
            cnt <= 7'd0;
        else begin
            if(cnt == M_N-1)
                cnt <= 7'd0;
            else
                cnt <= cnt+1;
        end
    end
    
    always @(posedge clk_in or negedge rst) begin 
         if(!rst) begin
              cnt1 <= 4'b0;
              cnt2 <= 4'b0;
         end else if(cnt<=c89-1'b1) begin
              cnt2 <= 4'd0;
             if(cnt1 == div_e - 1'b1)
                   cnt1 <= 4'd0;
              else
                   cnt1 <= cnt1 + 1'b1;
          end else if(cnt>c89-1'b1) begin
              cnt1 <= 4'd0;
              if(cnt2 == div_o - 1'b1)
                   cnt2 <= 4'd0;
              else
                   cnt2 <= cnt2 + 1'b1;
           end
        end
 
        always @(posedge clk_in or negedge rst) begin
             if(!rst)
                  clk_MN <= 1'b0;
             else begin
                 if(cnt<c89) begin
                     if(cnt1 == 4'd0 || cnt1 == div_e/2)
                           clk_MN <= ~clk_MN;
                       end
                  if(cnt>=c89) begin
                      if(cnt2 == 4'd0 || cnt2 == (div_o - 1'b1)/2)
                        clk_MN <= ~clk_MN;
                    end
               end 
        end

//*************code***********//
endmodule

Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
    parameter M_N = 8'd87; 
    parameter c89 = 8'd24; // 8/9时钟切换点
    parameter div_e = 5'd8; //偶数周期
    parameter div_o = 5'd9; //奇数周期
//*************code***********//
    reg [3:0] clk_cnt;
    reg [6:0] cyc_cnt;
    reg div_flag;
    reg clk_out_r;
     
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            clk_cnt <= 0;
        else if (~div_flag)
            clk_cnt <= (clk_cnt==(div_e-1))?0:clk_cnt+1;
        else
            clk_cnt <= (clk_cnt==(div_o-1))?0:clk_cnt+1;
    end
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            cyc_cnt <= 0;
        else
            cyc_cnt <= (cyc_cnt==(M_N-1))?0:cyc_cnt+1;
    end
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            div_flag <= 0;
        else
            div_flag <= (cyc_cnt==(M_N-1)||cyc_cnt==(c89-1))?~div_flag:div_flag;
    end
    
    always@(posedge clk_in or negedge rst)begin
        if(~rst)
            clk_out_r <= 0;
        else if (~div_flag)
            clk_out_r <= clk_cnt<=((div_e>>2)+1);
        else 
            clk_out_r <= clk_cnt<=((div_o>>2)+1);
    end
    
    assign clk_out = clk_out_r;
//*************code***********//
endmodule

Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg [7:0] cyc_cnt; //对clk_in进行计数,达到M_N后清零。
reg div_flag; //8/9分频标志。当div_flag==0时是8分频;当div_flag==1时是9分频。
reg [3:0] clk_cnt; //用于产生分频输出。当div_flag==0时,计数最大值是div_e-1;当div_flag==1时,计数最大值是div_o-1。
reg clk_out_r; //根据clk_cnt和div_flag产生分频输出。
	always@(posedge clk_in,negedge rst)begin
		if(~rst)
			clk_cnt <= 4'd0;
		else if(~div_flag)
			clk_cnt <= clk_cnt==(div_e-1)? 0:clk_cnt+1;
		else
			clk_cnt <= clk_cnt==(div_o-1)? 0:clk_cnt+1;
	end
	
	always@(posedge clk_in,negedge rst)begin
		if(~rst)
			cyc_cnt <= 8'd0;
		else
			cyc_cnt <= cyc_cnt==(M_N-1)? 0:cyc_cnt+1;
	end
	
	always@(posedge clk_in, negedge rst)begin
		if(~rst)
			div_flag <= 1'b0;
		else
			div_flag <= cyc_cnt==(M_N-1)||cyc_cnt==(c89-1)? ~div_flag:div_flag;
	end
	
	always@(posedge clk_cnt, negedge rst)begin
		if(~rst)
			clk_out_r <= 1'b0;
		else begin
			if(div_flag==0)
				clk_out_r <= clk_cnt<=((div_e>>2)+1);
        else
            clk_out_r <= clk_cnt<=((div_o>>2)+1);
		end
	end
	assign clk_out = clk_out_r;

//*************code***********//
endmodule

Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
    
    reg    [7:0]    cnt;
    reg             div_flag;    //0 进行8分频   1 进行9分频
    reg    [4:0]    cnt_e;        //对偶数分频进行计数
    reg    [4:0]    cnt_o;        //对奇数分频进行计数
    reg             clk_out_r;
    
    always @(posedge clk_in or negedge rst) begin
        if (rst == 1'b0) begin
            cnt <= 'd0;
        end
        else begin
            cnt <= (cnt == (M_N-1)) ? 'd0 : (cnt + 1'b1);  
        end
    end
    
    always @(posedge clk_in or negedge rst) begin
        if (rst == 1'b0) begin
            div_flag <= 1'b0;
        end
        else if (cnt == (M_N-1)) begin
            div_flag <= 1'b0;
        end
        else if (cnt == (c89-1)) begin
            div_flag <= 1'b1;
        end
    end
    
    always @(posedge clk_in or negedge rst) begin
        if (rst == 1'b0) begin
            cnt_e <= 'd0;
        end
        else begin
            cnt_e <= (div_flag == 1'b1)   ? 'd0 :
                     (cnt_e == (div_e-1)) ? 'd0 : (cnt_e+1);
        end
    end
    
    always @(posedge clk_in or negedge rst) begin
        if (rst == 1'b0) begin
            cnt_o <= 'd0;
        end
        else begin
            cnt_o <= (div_flag == 1'b0)   ? 'd0 :
                     (cnt_o == (div_o-1)) ? 'd0 : (cnt_o+1);
        end
    end
    
    always @(posedge clk_in or negedge rst) begin
        if (rst == 0) begin
            clk_out_r <= 1'b0;
        end
        else if (div_flag == 0) begin
            clk_out_r <= (cnt_e <= ( (div_e>>2) + 1 ) );    // 小于一半计数值的时候就为1,否则为0
        end
        else if (div_flag == 1) begin
            clk_out_r <= (cnt_o <= ( (div_o>>2) + 1 ) );    // 小于一半计数值的时候就为1,否则为0
        end
    end
    
    assign clk_out = clk_out_r;
    
    
    
    
    
    
    
    
    
    
    
    


//*************code***********//
endmodule

Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期

 
    reg[6:0]cnt;
    always@(posedge clk_in or negedge rst)
        begin if(~rst) 
                cnt<=7'd0;
                else begin if(cnt==86)
                    cnt<=0;
                    else cnt<=cnt+1;
            end
            end
            
            reg[2:0]cnt_8;
            reg[3:0]cnt_9;
    always@(posedge clk_in or negedge rst)
        begin if(~rst)
            begin 
             cnt_8<=0;  
             cnt_9<=0;
            end
            
            else begin if(cnt<c89) 
                    cnt_8<=cnt_8+1;
                else begin if(cnt_9==div_o-1)
                cnt_9<=0;
                else cnt_9<=cnt_9+1;
                end
            end
        end
            
    reg clk_r;
    always@(posedge clk_in or negedge rst)
        begin if(~rst)
            clk_r<=0;
            else begin 
                if(cnt<c89)
                    begin if(cnt_8<4)
                    clk_r<=1;
                else clk_r<=0;
                end
            else begin
                if(cnt_9<4)
              clk_r<=1;
            else clk_r<=0;
            end
        end
        end
            
        assign clk_out=clk_r;
   
endmodule

上一题