八、分频器

分频器是数字系统设计中最常见的基本电路之一。所谓分频,就是把输入信号的频率变成成倍数地低于输入频率的输出信号。

分频器分为偶数分频器奇数分频器,和计数器非常类似,有时候可以说就是一个东西。就像上一节计数器中的时钟信号和led_out。

一、偶分频

第七节,计数器是差不多的就不再进行单独讲解。 这里就简单实现一个8-分频器吧

1、Visio画图

2、代码

module divider_eight(
input wire sys_clk,
input wire sys_rst_n,

output reg clk_flag
);

reg [2:0] cnt;
//给cnt赋值,计数器什么时候清零,什么时候增加
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==1'b0)
        cnt<=3'd0;
    else if(cnt == 3'd7)
        cnt<=3'd0;
    else
        cnt<=cnt+3'd1;
     
//给clk_flag赋值
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==1'b0)
        clk_flag <= 1'b0;
    else if(cnt == 3'd6)
        clk_flag<=1'b1;
    else
        clk_flag<=1'b0;
endmodule

3、仿真

仿真代码:

`timescale 1ns/1ns
module tb_divider_eight();
reg sys_clk;
reg sys_rst_n;
wire clk_flag;

//赋初值
initial
    begin
        sys_clk=1'b1;
        sys_rst_n=1'b0;
        #20
        sys_rst_n=1'b1;
    end 
 initial
    begin
        $timeformat(-9,0,"ns",6);
        $monitor("@time %t:clk_flag=%b",$time,clk_flag);
    end 
always #10 sys_clk=~sys_clk;

divider_eight divider_eight_inst(
.sys_clk  (sys_clk),
.sys_rst_n(sys_rst_n),
         
.clk_flag (clk_flag)
);
endmodule

仿真波形如图:

至于这里为什么要用一个新的clk_flag,当计数器到达最大值的时候保持一个时钟周期的高电平,是为了和系统时间同步,而不是自己单独的去定义一个变量来记录时间。这种方法叫做降频方法。

二、奇分频     

仅就实现分频功能来讲,奇分频和偶分频的差别还是很大的,奇数分频相对于偶数分频要复杂一些,并不是简单的用计数器计数就可以实现。将一个系统时钟进行5分频的奇数分频功能,可以用于将高频的时钟降低为低频的时钟使用。

1、采用分频的方法

由于这里是5分频,不可能计数到2.5,所以只能计数0-4;

通过观察可以发现,第一种是采用上升沿采样,第二种是采用下降沿采样,两者占空比都不是50%。这两种都不是我们想要的时钟信号的波形。而第三种才是我们想要的输出信号的波形。通过观察我们可以得到:第一种波形和第二种波形在组合逻辑下进行或运算可以得到第三种波形(占空比为50%的5分频信号)。那么第一种波形和第二种波形就可以作为中间变量来得到我们的目标波形。

(1)代码

module divider_five(
input wire sys_clk,
input wire sys_rst_n,
output wire clk_out
);
reg [2:0] cnt;
reg  clk_1;
reg  clk_2;

//cnt赋值
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <= 3'd0;
    else if(cnt == 3'd4)
        cnt <= 3'd0;
    else
        cnt <= cnt + 3'd1;
        
//clk_1赋值,这里是上升沿采样
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        clk_1 <= 1'b0;
    else if(cnt == 3'd2)//等于2的时候拉高
        clk_1 <= 1 'b1;
    else if(cnt == 4)//等于4的时候拉低
        clk_1 <= 1'b0;
    else//既不是2也不是4的时候保持原来的值
        clk_1 <= clk_1;

//clk_2赋值,这里是下降沿采样
always@(negedge sys_clk or negedge sys_rst_n)//这里敏感列表不一样
    if(sys_rst_n == 1'b0)
        clk_2 <= 1'b0;
    else if(cnt == 3'd2)//等于2的时候拉高
        clk_2 <= 1 'b1;
    else if(cnt == 4)//等于4的时候拉低
        clk_2 <= 1'b0;
    else//既不是2也不是4的时候保持原来的值
        clk_2 <= clk_2;

//clk_out赋值,取clk_1和clk_2的逻辑或运算,使用组合逻辑进行赋值就不会延迟一个周期
assign clk_out = (clk_1 | clk_2);

endmodule

对应的rtl代码综合出来的rtl视图如图:

(2)仿真

仿真代码:

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

//赋初值
initial
    begin
        sys_clk=1'b1;
        sys_rst_n=1'b0;
        #20
        sys_rst_n=1'b1;
    end 
 initial
    begin
        $timeformat(-9,0,"ns",6);
        $monitor("@time %t:clk_out=%b",$time,clk_out);
    end  
always #10 sys_clk=~sys_clk;
divider_five divider_five_inst
(
.sys_clk  (sys_clk),
.sys_rst_n(sys_rst_n),
.clk_out  (clk_out)
);
endmodule

仿真波形如图:

(3)绑定管脚和上板验证

2、采用降频的方法

采用降频的方法的意思其实就是,当计数达到我们所想要得到的数之后,给一个脉冲信号,之后开始重新计数。而采用分频的方法的话,就是在我们计数目标时间内,一半为高电平一半为低电平。这就是这两种方法的区别。

(1)VIsio画图

(2)代码

module divider_five(
input wire sys_clk,
input wire sys_rst_n,
output reg clk_flag
);
reg [2:0] cnt;
/* reg  clk_1;
reg  clk_2; */

//cnt赋值
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <= 3'd0;
    else if(cnt == 3'd4)
        cnt <= 3'd0;
    else
        cnt <= cnt + 3'd1;
    
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        clk_flag <= 1'b0;
    else if(cnt==3'd3)
        clk_flag<=1'b1;
    else
        clk_flag<=1'b0;
endmodule

(3)仿真

仿真代码:

`timescale 1ns/1ns
module tb_divider_five();
reg sys_clk;
reg sys_rst_n;
wire clk_flag;

//赋初值
initial
    begin
        sys_clk=1'b1;
        sys_rst_n=1'b0;
        #20
        sys_rst_n=1'b1;
    end 
 initial
    begin
        $timeformat(-9,0,"ns",6);
        $monitor("@time %t:clk_flag=%b",$time,clk_flag);
    end  
always #10 sys_clk=~sys_clk;
divider_five divider_f_inst
(
.sys_clk  (sys_clk),
.sys_rst_n(sys_rst_n),
.clk_flag  (clk_flag)
);
endmodule

仿真波形:

这里就不再上班验证测量频率了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值