常用数字电路模块之三:计数器与分频器(二))

2023-11-15

三、分频电路

  (1)简单的计数器

  计数器实质是对输入的驱动时钟进行计数,所以计数器在某种意义上讲,等同于对时钟进行分频。例如一个最大计数长度为N=2^n(从0计数到N-1)的计数器,也就是寄存器位数位n,那么寄存器最高位的输出为N=2^n分频,次高位为N/2分频...例如下面的代码:

module test#(parameter N=3)(


input clk,
input rst_n,
output clk_div
);




reg [N-1:0] div_reg        ;//分频计数器
always @(posedge clk or negedge rst_n)
    if (rst_n == 1'b0 )
        div_reg    <= 0 ;
    else
        div_reg    <= div_reg + 1'b1 ;


assign clk_div = div_reg[N-1] ;


endmodule

 该代码描述的将一个3位的计数器最高位输出,也就是计数长度为8(计数从0~7)波形如下所示: 

可以看到最高位的输出为输入时钟的8分频。

 

  当N不是2的整数次幂时,即N≠2^n时,从0计数到N-1,其最高位作为时钟输出(占空比不一定为 1:1)是输入时钟的1/N,也就是N分频。我们来举个例子,比如最大计数长度为5的计数器,即从0计数到4后又返回0,那么需要定义一个三位的寄存器。寄存器的计数过程为:

  000-001-010-011-100-000-001-010-011-100-000-001-010-011-100-000-001-010-011-100······

我们取最高位,得到的信号变化就是:

  0-0-0-0-1-0-0-0-0-0-1-0-0-0-0-1-0-0-0-0-1···

 代码如下所示:

module test#(parameter N=3)(
input clk,
input rst_n,
output clk_div
);




reg [N-1:0] div_reg        ;//分频计数器
always @(posedge clk or negedge rst_n)
    if (rst_n == 1'b0 )
        div_reg    <= 0 ;
    else if(div_reg == 3'd4)//从0计数到4,然后返回到0,5分频
        div_reg    <= 0;
    else
        div_reg    <= div_reg + 1'b1 ;




assign clk_div = div_reg[N-1] ;


endmodule

仿真波形如下所示:

由此可以看到,每一个分频后的时钟周期=5倍原来的时钟周期,因此是5分频。

 

  那么这个情况是不是也可以包含第一种情况呢?我们那设置为8分频看看,即前面的3'd4改成3'd7,得到的仿真波形如下所示:

可以看到,计数器的最高位输出也是输入频率的1/N。

 因此我们得到结论:一个最大计数长度为N(从0计数到N-1)的计数器,其最高位的输出,是输入频率的N分频。

  通常 ASIC 和 FPGA 中,时钟都是全局信号,都需要通过 PLL 处理才能使用,但某些简易场合,采用计数器输出时钟也是能够使用的,只是需要注意时序约束。

 

  (2)偶数倍分频(占空比50%)

   偶数分频,也就是2分频、4分频、6分频...这个还是比较简单的,N(N当然是2的倍数)分频,那么计数到N/2-1,然后时钟翻转:

 例如N=6时,代码如下所示:

module test#(parameter N=6)(
input clk,
input rst_n,
output clk_div
);
reg div_reg ;
reg [N-1:0] div_cnt        ;//分频计数器
always @(posedge clk or negedge rst_n)
    if (rst_n == 1'b0 )begin
        div_cnt    <= 0 ;
        div_reg    <= 0 ;
    end
    else if(div_cnt == (N/2 - 1))begin
        div_cnt    <= 0;
        div_reg    <= ~div_reg ;
    end
    else
        div_cnt    <= div_cnt + 1'b1 ;




assign clk_div = div_reg ;

仿真波形如下所示:

当N=2的仿真波形如下所示:

  (3)奇数倍分频

    ①占空比接近50%

   对于占空比不是50%的计数分频,我们可以直接用上面的计数器方法,这里就不说了,我们介绍其他接近50%的占空比的方法,比如下面使用的状态机分频:

  

   

上图的状态机除了用一般的状态机设计方式之外,我们也可以用简单的计数器实现,这种方法如下所示:

  假设时钟分频是N,则设置一个计数器,计数长度是N(即从0计数到N-1),然后在计数器为计数到(N-1)/2的时候,翻转一下分频时钟信号;在计数器计数到为N-1的时候,再翻转一下时钟。

代码如下所示:

module test#(parameter N=3)(//N分频,这里是3分频
input clk,
input rst_n,
output clk_div
);




reg [N-1:0] div_cnt        ;//分频计数器
reg div_reg ;
always @(posedge clk or negedge rst_n)begin
    if (rst_n == 1'b0 )begin
        div_cnt    <= 0 ;
        div_reg        <= 1 ;
    end else if (div_cnt == (N-1)/2)begin//计数到(N-1)/2,进行翻转和继续计数
        div_reg        <= ~div_reg;
        div_cnt    <= div_cnt + 1'b1 ;
    end else if ( div_cnt == (N-1) )begin//计数到N-1,进行清零和翻转
        div_cnt        <= 0 ;
        div_reg        <= ~div_reg;
    end else
        div_cnt    <= div_cnt + 1'b1 ;




end
assign clk_div = (N == 1)?clk:div_reg ;//注意这里


endmodule

代码中我们需要注意,在N= 1的情况,也就是不分频的情况。仿真电路如下图所示:

3分频,N = 3:

5分频,N= 5 :

不分频,即N=1的仿真如下所示:

②占空比50%

产生具有50%占空比的奇数分频时钟的算法如下所示,假设N分频(N是计数):

  设置一个计数长度为N的上升沿计数器,和一个信号寄存器;信号寄存器在上升沿计数器为(N-1)/2的时候进行翻转,然后再在计数到N-1的时候进行翻转(这里相当于得到一个N分频信号A)。

  再设置一个计数长度为N的下降沿计数器,和另一个信号寄存器;信号寄存器在下降沿计数器为(N-1)/2的时候进行翻转,然后再在计数到N-1的时候进行翻转(这里相当于得到一个N分频信号B)。

  将A和B相或就可以得到占空比50%的奇数分频信号;代码实现如下:

module test#(parameter N=5)(//N分频
input clk,
input rst_n,
output clk_div
);


reg sig_r ;//定义一个上升沿翻转的信号
reg sig_f ;//定义一个下降沿翻转的信号
reg [N-1:0]    cnt_r;//上升沿计数器
reg [N-1:0]    cnt_f;//下降沿计数器


wire clk_f ;
assign clk_f = ~clk ;//用来触发下降沿计数器的时钟
                    //由于同时使用上升沿和下降沿触发器不好,因此我们为同一边沿,都使用上升沿触发
                    //只不过是将时钟进行反向
always @(posedge clk or negedge rst_n)begin//上升沿计数
    if(rst_n == 1'b0)begin
        sig_r    <= 0 ;
        cnt_r    <= 0 ;
    end else if( cnt_r == (N-1)/2 )begin
        sig_r    <= ~sig_r ;
        cnt_r    <= cnt_r + 1 ;
    end else if ( cnt_r == (N-1) )begin
        sig_r    <= ~sig_r ;
        cnt_r    <= 0 ;
    end else
        cnt_r    <= cnt_r + 1 ;
end


always @(posedge clk_f or negedge rst_n)begin//下降沿计数
    if(rst_n == 1'b0)begin
        sig_f    <= 0 ;
        cnt_f    <= 0 ;
    end else if( cnt_f == (N-1)/2 )begin
        sig_f    <= ~sig_f ;
        cnt_f    <= cnt_f + 1 ;
    end else if ( cnt_f == (N-1) )begin
        sig_f    <= ~sig_f ;
        cnt_f    <= 0 ;
    end else
        cnt_f    <= cnt_f + 1 ;
end


assign clk_div = sig_f || sig_r ;




endmodule

仿真波形如下所示:

3分频:

5分频:

(4)任意整数倍分频(接近50%)

  在前面中,我们知道了一个最大计数长度为N(从0计数到N-1)的计数器,其最高位的输出,是输入频率的N分频,因此最简单的任意分频电路就是设计一个计数器,然后最高位输出就是分频的频率了。虽然这这种方法很简单,但是很显然,这种方法的占空比是很糟糕的。因此我们要用其他的方法,也就是用其他的组合方式。

   ①占空比接近50%任意整数分频

  这种方法是取自偶数分频和奇数分频里面的接近50%占空比,实现的代码如下所示:

module test #( parameter cfactor= 5)(
  input clk,
  input rst_n,
  output clk_div
);
reg clk_loc;
//reg [15:0] cnt;//allowed maximum clock division factor is 65536
reg [7:0] cnt;//allowed maximum clock division factor is 256




assign clk_div = (cfactor==1)? clk : clk_loc;
//assign clk_div = ((rst==1) || (cfactor==1))? clk : clk_loc;




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




endmodule


2分频的仿真图,如下所示:  

5分频的仿真波形如下所示:

②占空比50%的任意整数分频(重点)

这种方法是取自偶数分频和奇数分频都是50%占空比的组合,代码如下所示:

module test#(parameter N=1)(//N分频
input clk,
input rst_n,
output clk_div
);




//奇数分频
reg sig_r ;//定义一个上升沿翻转的信号
reg sig_f ;//定义一个下降沿翻转的信号
reg [N-1:0]    cnt_r;//上升沿计数器
reg [N-1:0]    cnt_f;//下降沿计数器




wire clk_f ;
assign clk_f = ~clk ;//用来触发下降沿计数器的时钟
                    //由于同时使用上升沿和下降沿触发器不好,因此我们为同一边沿,都使用上升沿触发
                    //只不过是将时钟进行反向




always @(posedge clk or negedge rst_n)begin//上升沿计数
    if(rst_n == 1'b0)begin
        sig_r    <= 0 ;
        cnt_r    <= 0 ;
    end
    else begin
        cnt_r    <= cnt_r + 1 ;
        if( cnt_r == (N-1)/2 )begin
            sig_r    <= ~sig_r ;
        end else if ( cnt_r == (N-1) )begin
            sig_r    <= ~sig_r ;
            cnt_r    <= 0 ;
        end
    end
end




always @(posedge clk_f or negedge rst_n)begin//下降沿计数
    if(rst_n == 1'b0)begin
        sig_f    <= 0 ;
        cnt_f    <= 0 ;
    end
    else begin
        cnt_f    <= cnt_f + 1 ;
        if( cnt_f == (N-1)/2 )begin
            sig_f    <= ~sig_f ;
        end else if ( cnt_f == (N-1) )begin
            sig_f    <= ~sig_f ;
            cnt_f    <= 0 ;
        end
    end
end




//偶数分频
reg div_reg ;
reg [N-1:0] div_cnt        ;//分频计数器
always @(posedge clk or negedge rst_n)begin
    if (rst_n == 1'b0 )begin
        div_cnt    <= 0 ;
        div_reg    <= 0 ;
    end
    else begin
        div_cnt    <= div_cnt + 1'b1 ;
        if(div_cnt == (N/2 - 1))begin
            div_cnt    <= 0;
            div_reg    <= ~div_reg ;
        end
    end
end
assign clk_div = (N == 1)?clk:
                ( N%2 == 1)?(sig_f || sig_r ): div_reg;//这里用来输出分频值。对2的取余操作是综合的


endmodule

仿真波形如下所示:

5分频:

    

6分频:  

 

   

 总结:本文介绍了计数器及其功能,主要是介绍了作为分频器的功能。对于分频器,如下所示:

          

作者:IC_learner

博客链接:https://www.cnblogs.com/IClearner/p/7208871

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常用数字电路模块之三:计数器与分频器(二)) 的相关文章

随机推荐

  • 拍乐云远程视频银行解决方案,为金融数字化注入“新活力”

    中国银行业协会在今年发布的 中国银行业客服中心与远程银行发展报告 2020 中指出 随着数字化融入经济生活的方方面面 我国银行业正在快速迭代升级 用户对银行的数字化服务也提出了更高的要求 一是从被动接受现有服务转向主动要求个性化服务 二是从
  • c++学习之set/multiset容器

    一 set基本概念 简介 所有元素在插入时都会被自动排序 本质 set multiset属于关联式容器 底层结构是用二叉树实现的 set multiset区别 set不允许有重复的元素 multiset可以有重复的元素 二 set构造和赋值
  • 【python学习】-使用sklearn对数据进行线性回归,并绘制回归线

    使用sklearn对数据进行线性回归 并绘制回归线 基本思想 代码实现 在科研工作中 有时得到一组或者几组数据 为了研究数据之间是否存在线性关系 一般会想到拟合数据 看下数据的线性关系 严格地说 是使用线性模型研究两个或多个变量之间规律的一
  • “元宇宙”,究竟离我们有多远?(下)

    目录 引言 由 Z世代 引入 元宇宙 1 黑客帝国 究竟什么才是真实的世界 1 1 故事背景 1 2 矩阵 Matrix 矩阵计算与AI革命 1 3 D j vu 1 4 红蓝药丸 1 5 绿色代码雨 附源码 1 6 元宇宙 2 专访 时隔
  • css控制页面打印(分页、屏蔽不需要打印的对象)

    样式 注 不需要打印的对象要用上 Noprint 样式 需要换页处理的对象要用上 PageNext 样式 因为最后一页不用加入换页符 所以要控制最后一页不要使用该样式 个人感觉用PAGE BREAK BEFORE属性控制第一页要方便一些
  • Spark集群安装部署

    目录 一 环境准备 二 安装步骤 三 使用Standalone模式 四 使用Yarn模式 一 环境准备 由于Spark仅仅是一种计算机框架 不负责数据的存储和管理 因此 通常都会将Spark和Hadoop进行统一部署 由Hadoop中的HD
  • 完美解决jenkins安装插件失败(修改下载源)

    从jenkins官网上下载的jenkins 在安装的过程中 会有安装插件一环 第一个为默认安装 第二个为手动 选择默认安装之后 会遇到 安装插件失败 或者卡在安装插件这个地方非常久 久到怀疑人生 久到想卸载重装 在这里 我们可以选择 手动安
  • HTML与CSS3网页设计基础

    HTML基础 1 HTML的简介 HTML 称为 超文本标记语言 提供了很多标签 用于标记网页中的各种元素 HTML的语言特点 1 不区分大小写 2 用不同的标签来标记网页中的不同内容 比如超链接 标题 段落 图片等等 3 标签分为 单独出
  • Flutter 遇到的异常 持续更新

    org gradle wrapper GradleWrapperMain 类无法加载 解决方案 如果你用的是androidStudio3 0以上的版本 新建一个android工程的时候在gradle wrapper里面默认会有一个gradl
  • VMware虚拟机安装Windows Server 2016教程

    想必同学们已经开学了 也都进入了军训阶段吧 而很多计算机网络专业的同学们要开始接触到Windows Server了 这也是计算机网络技术专业的专业基础课程 想当年我们实训课学习使用的好像是2008版的 也不晓得现在各个学校会用到哪个版本实操
  • 均方误差(MSE)

    均方误差 Mean Squared Error MSE 在相同测量条件下进行的测量称为 等精度测量 例如在同样的条件下 用同一个游标卡尺测量铜棒的直径若干次 这就是等精度测量 对于 等精度测量来说 还有一种更好的表示误差的方法 就是 标准误
  • SpringBoot 引入了common模块 导致的依赖包结果版本不一致问题

    分享一下我之前遇到的问题 首先我是使用Idea自带的Spring Initializr
  • 多分类学习

    多分类问题 现实中常遇到多分类学习任务 有些二分类学习方法可直接推广到多分类 但在更多情形下 我们是基于一些基本策略 利用二分类学习器来解决多分类问题 所以多分类问题的根本方法依然是二分类问题 通常地 使用的是拆分法 也就是将一个多分类转换
  • 在Vue下如何用js代码将13位的时间戳数据转换成正常显示的时间?

    问题描述 在使用Vue时 如果页面没有渲染完成 通过js代码是拿不到页面上数据的 而我们又想通过js操作数据时 就需要通过一些特别的方法 网上有各种方法 但是大部分都解释的比较模糊 这是我的一些小总结 由于不是专门玩前端的 但是又不想用vu
  • linux 挂载目录

    这本阿里P8撰写的算法笔记 再次推荐给大家 身边不少朋友学完这本书最后加入大厂 Github 疯传 史上最强悍 阿里大佬 LeetCode刷题手册 开放下载了 挂载的基本概念 前面讲过 Linux 系统中 一切皆文件 所有文件都放置在以根目
  • 网络故障排除之Traceroute命令详解

    概要 遇到网络故障的时候 你一般会最先使用哪条命令进行排障 除了Ping 还有Traceroute Show Telnet又或是Clear Debug等等 今天安排的 是Traceroute排障命令详解 给你分享3个经典排障案例哈 一 Tr
  • linux的应用线程同步与驱动同步机制

    同步机制 在 Linux 应用程序和内核中的驱动程序中 有一些常见的同步机制用于实现线程或进程之间的同步和数据访问保护 下面是它们的一些主要机制 Linux 应用程序中的同步机制 互斥锁 Mutex 用于保护共享资源 确保只有一个线程可以访
  • 华为机试题74-参数解析

    描述 在命令行输入如下命令 xcopy s c d e 各个参数如下 参数1 命令字xcopy 参数2 字符串 s 参数3 字符串c 参数4 字符串d e 请编写一个参数解析程序 实现将命令行各个参数解析出来 解析规则 1 参数分隔符为空格
  • 窥孔优化(Peephole Optimization)

    窥孔优化 Peephole Optimization 是编译器中的一个技术 用于优化生成的中间代码或目标代码 该优化方法通过查看代码的小部分 或称为 窥孔 来识别并提供更高效的代码替代方案 1 基本概念 定义 窥孔优化涉及观察编译器输出中的
  • 常用数字电路模块之三:计数器与分频器(二))

    三 分频电路 1 简单的计数器 计数器实质是对输入的驱动时钟进行计数 所以计数器在某种意义上讲 等同于对时钟进行分频 例如一个最大计数长度为N 2 n 从0计数到N 1 的计数器 也就是寄存器位数位n 那么寄存器最高位的输出为N 2 n分频