第一次编程测试(分频器)

一,分频器

  1. 定义
    分频器(Divider)是一种电子电路或设备,用于将输入信号的频率降低到较低的频率。它常用于数字系统、通信系统和计时应用中。
  2. 原理
    整数分频器使用计数器来实现频率的降低。计数器根据输入信号的边沿触发进行计数,当计数值达到预设的分频比时,输出一个脉冲,并将计数器清零重新开始计数。例如,一个2分频器会在每两个输入信号边沿之间输出一个脉冲,将输入信号的频率降低为一半。
  3. verilog代码实现
    在这里所了解的分频器主要是整数分频器,其主要的实现分为奇数分频和偶数分频:
    1.偶数分频:即在每个时钟上升沿使计数器+1,当计数器小于N/2-1时使得输出时钟为低,当大于等于N/2-1小于N-1时使输出时钟为高
    2.奇数分频:奇数分频的方法有许多种这种展示一下我所理解的跟同学所理解的方法
    (1)如果想要计数分频但是寄存器不可以计数分数所以我们可以使用两个中间输出时钟
    一个对上升沿敏感。一个对下降沿敏感,分别计数,当分得的时钟高电平比低电平多一个周期时将两个中间时钟相与(即低电平向高电平借用0.5周期),当分得的时钟低电平比高电平多一个周期时将两个中间时钟相或(即高电平向低电平借用0.5周期)
//第一种方法
module pre_N #(parameter N = 8) (
    input       wire        clk,    //系统时钟
    input       wire        rst_n,  //系统复位
    output      wire        clk_out //调频后信号
);

reg     clk_out_r;//调频后的时钟
wire    add_cnt;//计数开始使能
wire    end_cnt;//计数结束使能
wire    add_cnt1;//判断奇偶
reg     [5:0] cnt;//计数寄存器
reg     clk_out_a;
reg     clk_out_b;
reg     [5:0] cnt_a;
reg     [5:0] cnt_b;
wire     clk_out_ab;

assign add_cnt1 = (N%2==0)?1:0;
//计数模块
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 6'b0;
    end
    else if (add_cnt) begin
        if (end_cnt) begin
            cnt <= 6'b0;
        end
        else begin
            cnt <= cnt + 1'b1;
        end
    end
    else begin
        cnt <= cnt;
    end
end

assign add_cnt = 1;
assign end_cnt = add_cnt&&(cnt == N/2-1);

//时钟分频模块
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_out_r <= 1'b0;
    end
    else if (end_cnt) begin
        clk_out_r <= ~clk_out_r;
    end
    else begin
        clk_out_r <= clk_out_r;
    end
end

//上升沿分频模块
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_out_a <= 1'b0;
        cnt_a <= 1'b0;
    end
    else begin
        if (cnt_a <N-1) begin
            if (cnt_a < (N-1)/2) begin
                clk_out_a <= 1'b0;
            end
            else if (cnt_a >=(N-1)/2) begin
                clk_out_a <= 1'b1;
            end
            else begin
                clk_out_a <= clk_out_a;
            end
            cnt_a <= cnt_a + 1;
        end
        else begin
            clk_out_a <= 1'b0;
            cnt_a <= 1'b0;
        end
    end
end

always @(negedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_out_b <= 1'b0;
        cnt_b <= 1'b0;
    end
    else begin
        if (cnt_b <N-1) begin
            if (cnt_b < (N-1)/2) begin
                clk_out_b <= 1'b0;
            end
            else if (cnt_b >=(N-1)/2) begin
                clk_out_b <= 1'b1;
            end
            else begin
                clk_out_b <= clk_out_b;
            end
            cnt_b <= cnt_b + 1;
        end
        else begin
            clk_out_b <= 1'b0;
            cnt_b <= 1'b0;
        end
    end
end
assign clk_out_ab = clk_out_a|clk_out_b;
assign clk_out = (N%2==0)?clk_out_r:clk_out_ab;
endmodule

(2)使用组合逻辑对电频敏感,每次电频转换都使计数器+1,当计数器加到N-1时使输出电频翻转

module pre_N_2 #(parameter N = 7)(
    input   wire        clk     ,
    input   wire        rst_n   ,
    output  wire        clk_out        
);

reg			[5:0]	cnt	   	;
wire				add_cnt	;
wire				end_cnt	;
reg                clk_out_r;

always @(clk)begin //对于上升沿下降沿都进行计数
   if(!rst_n)begin
        cnt <= 'd0;
    end 
    else if(add_cnt)begin 
        if(end_cnt)begin 
            cnt <= 'd0;
        end
        else begin 
            cnt <= cnt + 1'b1;
        end 
    end
end 

assign add_cnt = 1;
assign end_cnt = add_cnt && cnt == N-1;

always @(clk)begin 
    if(!rst_n)begin
        clk_out_r <= 'd0;
    end 
    else if(end_cnt)begin 
        clk_out_r <= ~clk_out_r;//计满翻转
    end 
    else begin 
        clk_out_r <= clk_out_r;//未计满保持
    end 
end

assign clk_out = clk_out_r;
endmodule
  1. tb文件
`timescale 1ns/1ns

module pre_N_tb ();

reg clk;
reg rst_n;
wire    clk_out;

parameter CYCLE = 20;
parameter N     = 5;

always #(CYCLE/2) clk = ~clk;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #(20)
    rst_n = 1'b1;
    #(1000)
    $stop;
end


pre_N #(.N(N)) pre_N_inst(
        .clk        (clk),
        .rst_n      (rst_n),
        .clk_out    (clk_out)
);
endmodule
`timescale 1ns/1ns

module pre_N_2_tb ();

reg clk;
reg rst_n;
wire    clk_out;

parameter CYCLE = 20;
parameter N     = 5;

always #(CYCLE/2) clk = ~clk;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #(20)
    rst_n = 1'b1;
    #(1000)
    $stop;
end


pre_N_2 #(.N(N)) pre_N_2_inst(
        .clk        (clk),
        .rst_n      (rst_n),
        .clk_out    (clk_out)
);
endmodule
  1. 仿真波形
    在此只展示一个
    第一次编程测试(分频器)_第1张图片

二.总结

对于分频器主要需要注意的是整数分频有奇数分频跟偶数分频,分频器主要是对时序逻辑电路中时钟理解的考察,其中的难点主要是奇数分频,只要掌握其中的方法还是比较好做,只要掌握时序逻辑电路的时钟信号的理解分频器还是很简单得。

你可能感兴趣的:(FPGA学习,fpga开发)