IC基础:解决分频器

偶数分频(太简单不写了)

  1. D触发器级联并Q非连D,实现2的n次幂分频
  2. 计数器分频,0和n/2处反转

50%奇数分频

  1. 0,n/2处反转
  2. 将分频后的信号在原时钟negedge打一拍,将两个信号相或
  • Code:
module odd_divider#(
    parameter N,
    parameter N_2
)
(
    input clk,
    input rst_n,
    output clk_N
);
    //==============defination
    reg clk_N_p;
    reg clk_N_n;
    wire clk_N;
    reg [7 : 0] cnt;

    //==============output
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt <= 'd0;
        else if(cnt == N - 1) cnt <= 'd0;
        else cnt <= cnt + 1'b1;
    end


    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) clk_N_p <= 1'b0;
        else if(cnt == 0 || cnt == N_2) clk_N_p <= ~clk_N_p;
    end
    always@(negedge clk or negedge rst_n)begin
        if(!rst_n)  clk_N_n <= 1'b0;
        else clk_N_n <= clk_N_p;
    end
    assign clk_N = clk_N_p || clk_N_n;
endmodule
  • Testbench:
module tb_odd_divider();
    //===================parameter
    parameter PERIOD = 10 / 2;
    parameter N = 7;
    parameter N_2 = 3;

    //===================parameter
    reg clk, rst_n;
    wire clk_N;
    //===================parameter
    initial begin
        clk = 0;
        rst_n = 0;
        #200 rst_n = 1;
	    #1500 $finish;
    end
    always #PERIOD clk = ~clk;
    
    odd_divider#(
        .N (N),
        .N_2(N_2)
    )
    u_odd_divider
    (
        .clk (clk),
        .rst_n(rst_n),
        .clk_N(clk_N)
    );
`ifdef FSDB
initial begin
	$fsdbDumpfile("tb_odd_divider.fsdb");
	$fsdbDumpvars;
    $fsdbDumpMDA();
end
`endif

endmodule 
  • VCS+verdi仿真:

在这里插入图片描述

  • Schematic:
    在这里插入图片描述

任意小数分频

  • 说明:形如M/N分频,明白公式:M / N = Q…R(M个周期有N个脉冲,其中R个Q+1分频时钟,(N - R)个Q分频时钟)
  • Code:
module decimal_divider#(
    parameter M,
    parameter N,
    parameter Q,
    parameter Q_2,
    parameter R
)
(
    input clk,
    input rst_n,
    output o_clk
);
    //================defination
    reg clk_q;
    reg [7 : 0] cnt_q;
    wire add_cnt_q;
    wire end_cnt_q;

    reg clk_q1;
    reg [7 : 0] cnt_q1;
    wire add_cnt_q1;
    wire end_cnt_q1;

    reg [7 : 0] cnt;
    wire add_cnt;
    wire end_cnt;
    //================output
    assign add_cnt_q = (cnt < N - R);
    assign end_cnt_q = add_cnt_q && (cnt_q == Q - 1);
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt_q <= 'd0;
        else if(end_cnt_q) cnt_q <= 'd0;
        else if(add_cnt_q) cnt_q <= cnt_q + 1'b1;
    end
    
    assign add_cnt_q1 = (cnt >= N - R);
    assign end_cnt_q1 = add_cnt_q1 && (cnt_q1 == Q);
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt_q1 <= 'd0;
        else if(end_cnt_q1) cnt_q1 <= 'd0;
        else if(add_cnt_q1) cnt_q1 <= cnt_q1 + 1'b1;
    end
    
    assign add_cnt = end_cnt_q || end_cnt_q1;
    assign end_cnt = add_cnt && (cnt == N - 1);
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt <= 'd0;
        else if(end_cnt) cnt <= 'd0;
        else if(add_cnt) cnt <= cnt + 1'b1;
    end

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) clk_q <= 'd0;
        else if(add_cnt_q && ((cnt_q == 0) || (cnt_q == Q_2))) clk_q <=  ~clk_q;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) clk_q1 <= 'd0;
        else if(add_cnt_q1 && ((cnt_q1 == 0) || (cnt_q1 == Q_2))) clk_q1 <=  ~clk_q1;
    end
    assign o_clk = clk_q || clk_q1;
endmodule 
  • Testbench
module tb_decimal_divider();
    //===================parameter
    parameter PERIOD = 10 / 2;
    parameter M = 21;
    parameter N = 5;
    parameter Q = 4;
    parameter Q_2 = 2;
    parameter R = 1;

    //===================defination
    reg clk, rst_n;
    wire o_clk;
    //===================output
    initial begin
        clk = 0;
        rst_n = 0;
        #200 rst_n = 1;
	    #1500 $finish;
    end
    always #PERIOD clk = ~clk;
    
    decimal_divider#(
        .M(M),
        .N(N),
        .Q(Q),
        .Q_2(Q_2),
        .R(R)
    )
    u_decimal_divider
    (
        .clk (clk),
        .rst_n(rst_n),
        .o_clk(o_clk)
    );
`ifdef FSDB
initial begin
	$fsdbDumpfile("tb_decimal_divider.fsdb");
	$fsdbDumpvars;
    $fsdbDumpMDA();
end
`endif

endmodule 
  • VCS+verdi:

在这里插入图片描述

  • Schematic:
    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA分频器的设计主要分为两种方式:基于计数器的分频器和基于查找表的分频器。 基于计数器的分频器:这种分频器使用FPGA内部的计数器来实现分频功能。首先需要确定分频比例,然后将计数器的初始值设置为所需的分频比例减1,每当计数器计数到0时,产生一个分频后的时钟信号。这种分频器具有简单、灵活的优点,但其最高分频率受到FPGA内部时钟频率的限制。 基于查找表的分频器:这种分频器使用FPGA内部的查找表实现分频功能。分频器的输入是一个时钟信号,输出是分频后的时钟信号。可以通过修改查找表的内容来实现不同的分频比例。这种分频器具有高速、低功耗的优点,但其实现较为复杂。 下面是一个基于计数器的分频器的VHDL代码示例: ```vhdl library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity clock_divider is Port ( clk_in : in STD_LOGIC; clk_out : out STD_LOGIC); end clock_divider; architecture Behavioral of clock_divider is signal count : integer := 0; begin process(clk_in) begin if (rising_edge(clk_in)) then count <= count + 1; if (count = 100) then clk_out <= not clk_out; count <= 0; end if; end if; end process; end Behavioral; ``` 该代码实现了一个将输入时钟信号分频100倍的分频器。其中,计数器的初始值为0,每当计数器计数到99时,产生一个分频后的时钟信号,并将计数器清零。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值