ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

移位寄存器分频原理与Verilog实现:从偶数到奇数分频

移位寄存器分频原理与Verilog实现:从偶数到奇数分频 简介这是一份面向数字逻辑电路学习者及计算机相关专业学生的技术文档专门讲解如何用移位寄存器实现分频。文档以74LS194和74LS138为核心从固定比分频器到可编程分频器层层递进给出具体电路图和波形分析并总结分频系数计算规律便于读者直接套用设计。资源为单个docx文件容量仅98KB内容精炼但覆盖完整适合快速查阅或课堂补充。目前已有994人学习是数字电路分频章节的实用参考资料。通过学习可清晰理解移位寄存器在时钟管理、频率合成中的应用掌握根据地址输入控制分频比的编程思路为后续通信系统或控制系统设计打下基础。1. 从一道实验题说起移位寄存器为什么能分频1.1 这个标题背后的真实需求先说个挺有意思的现象。很多人在数字逻辑电路课上学完触发器、时序逻辑之后做的第一个综合性实验往往就是“用移位寄存器实现分频”。这个题目看起来简单实际上暗藏不少门道——它考的不仅是你知不知道移位寄存器能移位更考你能不能把“移位”这个动作跟“分频”这件事的本质联系起来。“数字逻辑电路 用移位寄存器分频”这个课题本质上是想让你搞清楚三件事触发器级联成移位寄存器后数据每移一位输出相对于输入时钟到底滞后了多少个周期如何利用这种滞后关系让输出波形频率变为输入时钟的整数分之一偶数分频容易做奇数分频和50%占空比才是真正拉开差距的地方。这个知识点在工程里并不冷门。FPGA开发中常见的时钟分频、串行通信中的波特率生成、数字信号处理里的时钟同步底层都离不开移位寄存器分频这套思路。我当年调试一块音频编解码芯片的MCLK时钟树时就亲手用移位寄存器搭过一版3分频虽然最后量产换成了PLL但那次的经验让我把“分频”这件事彻底吃透了。1.2 这篇博文给你解决什么问题如果你是正在学数字逻辑电路的学生这篇内容能帮你把实验报告里“只会画图、不会讲原理”的尴尬补上如果你是刚入门FPGA的开发者这里面的Verilog代码和时序图画法可以直接抄作业哪怕你已经工作多年偶尔回看这些基础电路也常会有“原来当年没真懂”的感慨。我把这个课题拆成了五个部分先说移位寄存器分频的原理本质再讲偶数分频和奇数分频的实现套路然后给出Verilog代码和Wavedrom时序图的实操方法最后汇总几个我实际踩过的坑。每个部分的结论都基于仿真和实测不是PPT层面的推演。注意本文所有实现均采用同步时序设计所有触发器共用一个时钟源这是保证分频电路稳定工作的最基本前提。任何异步级联的“ripple计数器”式分频在工程上都不推荐后面我会专门讲原因。2. 移位寄存器分频的核心原理移位即延时延时即分频2.1 从D触发器的“一拍”说起要理解移位寄存器分频先得建立一个概念一个D触发器在时钟上升沿到来时会把输入端的值“锁存”到输出端输出的变化比输入慢一个时钟周期。这一拍的时间差就是时序电路的灵魂。类比一下日常生活你喊一嗓子山谷里隔一会儿传来回声。如果回声源不止一个而是排成一串你的喊声会依次经过它们每一站都延迟一步。移位寄存器就是这么一串“回声站”——数据从第一级传到第二级、第三级每传一级就晚一个时钟周期。分频的本质是把“周期”这个概念从时间域转换到“级数”域既然输出每经过一拍才变化一次那它变化的节奏自然就比输入时钟慢。慢多少取决于你让数据在寄存器链里绕了多少圈。下面这个示意图展示了4级移位寄存器的数据流动时钟周期: [1] [2] [3] [4] [5] [6] [7] [8] 输入数据: 1 0 1 0 1 0 1 0 Q1输出: - 1 0 1 0 1 0 1 Q2输出: - - 1 0 1 0 1 0 Q3输出: - - - 1 0 1 0 1 Q4输出: - - - - 1 0 1 0你看Q4的输出相比输入整整晚了4拍。如果你把Q4的信号反馈回输入端这个延迟就会形成“振荡”——每4拍输出翻转一次8拍完成一个完整周期于是从Q4看出去频率恰好是输入时钟的1/4。这就是4分频。2.2 两种基本分频结构对比用移位寄存器实现分频大体有两条路线。我把它们列个表对比一下方便你理解为什么绝大多数情况下我们选第二种。结构方式实现思路优点缺点典型应用环形计数器分频移位寄存器输出反馈到输入数据循环移动结构简单各输出相位均匀分频比N需要N个触发器资源消耗大顺序脉冲发生器、多相时钟生成移位寄存器反馈逻辑分频将若干级输出组合成反馈函数再送回输入分频比灵活可配置性高反馈逻辑需要设计分析稍复杂可编程分频器、序列发生器、时钟管理我实际用下来环形计数器适合分频比不大、但需要多路等间隔相位输出的场合比如三相无刷电机的换相控制。而“移位寄存器反馈逻辑”这种结构更有通用性——你只需要改变反馈连接方式就能在同一个移位寄存器上实现不同分频比。2.3 分频比与寄存器级数的数学关系对于“反馈型”分频器有一个非常实用的结论如果要实现N分频输出时钟周期是输入时钟的N倍你需要一个M级的移位寄存器其中M通常等于N偶数分频或者和N存在明确关系奇数分频。具体来说N为偶数时寄存器级数M N数据从第一级移到最后一级再取反反馈回第一级N为奇数时如果要严格的50%占空比最少需要M N级但反馈的取法要把“赶上沿”和“赶下沿”两种路径组合起来这个下一节细讲。这个结论的推导逻辑其实来自“周期定义”一个完整周期包含高电平和低电平两个阶段。如果高低电平的持续时间相同50%占空比那么每一段持续的时间就是N/2个输入时钟周期。你要让输出在N/2个时钟后翻转就得让信号经过N/2拍的延迟再反向。移位寄存器天然提供整数的拍数延迟所以N必须能被2整除这就是偶数分频“顺理成章”的原因奇数分频的难点也正在于这个“N/2不是整数”。在实际工程里我建议你选分频方案时先问自己两个问题占空比有没有严格要求输出相位精度需不需要对齐输入时钟边沿如果两个都不要求计数器分频比移位寄存器分频更省资源如果要求严苛移位寄存器方案才有不可替代的优势。3. 偶数分频最基础也是最容易出错的地方3.1 用移位寄存器实现2分频的三种等价画法2分频是分频电路的基本功。用移位寄存器实现时一个不太为人知的事实是级数不同效果一样但信号路径完全不同。方法一一级D触发器Q非端反馈回D端。这是教科书上“T触发器”的标准接法但严格来说它只用了一个触发器算不上“移位寄存器”。方法二两级D触发器串联Q1→D2Q2反馈到D1。这种接法数据在两个触发器之间绕圈每两个时钟周期Q2翻转一次。好处是Q1和Q2输出正好相位相差一个时钟周期如果需要两路正交时钟这种结构天然提供。方法三只用一级D触发器但D端接前一级的互补输出即Q非。本质上等同于方法一。实际做实验时很多同学喜欢用方法二因为“更像移位寄存器”。但从可维护性角度其实方法一最简洁——一个触发器解决2分频何必多耗一个FF资源。3.2 4分频和8分频级联的两种接法别搞混4分频、8分频这类2的幂次分频有两种实现思路很多人一开始很容易混。思路A把2分频电路级联。2分频的输出接下一级的时钟输入形成“异步级联”。这种方法电路画起来简单但每一级的输出相对输入时钟都有固定的传播延迟级数多了之后各级输出的时钟歪斜会越积越大时序分析非常痛苦。思路B用4级/8级移位寄存器同步级联所有触发器共用一个时钟反馈从最后一级取。这种方法才是标准的“移位寄存器分频”。举个例子4分频用寄存器链实现module divide_by4_shiftreg ( input wire clk, input wire rst_n, output wire clk_out ); reg [3:0] shreg; always (posedge clk or negedge rst_n) begin if (!rst_n) begin shreg 4b0000; end else begin shreg {shreg[2:0], ~shreg[3]}; end end assign clk_out shreg[3]; endmodule这里的关键点是~shreg[3]——这是反馈逻辑让数据在寄存器链里取反循环。你仔细算一下初始shreg全部为0第一个时钟上升沿后shreg变为4b0001因为~shreg[3] ~0 1第二个上升沿变为4b0011以此类推数据逐渐填充到第8个时钟后shreg回到全0刚好完成一个周期。clk_out取的是最高位shreg[3]它的波形是“前4拍为0后4拍为1”周期为8个输入时钟周期所以频率是输入时钟的1/8等等这里要注意了——我上面写的这个代码实际是2N分频因为反馈里有一个取反操作寄存器链里的数据每N拍翻转一次输出完整周期需要2N拍。这就是一个非常经典的翻车点移位寄存器反馈分频时如果反馈逻辑里带了反相器分频比输出的是2×M分频M为寄存器级数如果不带反相器直接反馈得到的是环形计数器输出周期为M拍但通常不能构成等宽方波。3.3 偶数分频实操中的三个常见翻车点第一初始化状态不对。仿真时如果寄存器初值全0前几个周期的输出波形并非理想方波需要先经过“预填充”阶段。实验之前最好先置一个非全0的初值或者干脆用复位信号把电路置成已知状态否则你的示波器上会看到一段“毛刺期”。第二把“移位寄存器”和“计数器”的效果混为一谈。功能上二者都能分频但计数器的输出是二进制编码移位寄存器的输出是“独热码”或“密勒码”。如果你后级电路需要的是脉冲序列而非方波选移位寄存器更自然如果你只需要一个分频时钟纯计数器反而省逻辑门。第三占空比不是50%的情况。偶数分频如果反馈取反输出天然50%占空比因为高低电平各占M拍但如果直接取某个中间级输出而不加反馈得到的可能是M对M的等宽输出也可能是高电平M1拍、低电平M2拍的不等宽波形。画原理图之前先把波形图画出来能避免很多低级错误。4. 奇数分频与50%占空比难题的真正解法4.1 为什么奇数分频这么让人头疼先说个必须认清的现实用普通的单链移位寄存器做3分频、5分频、7分频如果要求输出严格50%占空比直接用“最高位反馈取反”的办法行不通。原因前面提过——奇数N除以2不是整数你没法让信号在N/2拍精确翻转。那是不是说移位寄存器就不能做奇数分频了当然不是。工程上常见的思路有两种思路一双沿采样法用两个移位寄存器链一个在时钟上升沿工作一个在时钟下降沿工作最后把两路输出相或。这是最经典、也最容易理解的奇数分频50%占空比实现方式。思路二状态机法把移位寄存器拆成“状态寄存器”用组合逻辑直接生成输出。本质上是在用有限状态机做分频只是状态编码用了移位形式。我重点讲思路一因为它在工程里最实用。4.2 5分频50%占空比双沿采样法的详细拆解以5分频为例。5分频要求输出周期是输入时钟的5倍占空比50%意味着高电平持续2.5个时钟周期低电平也持续2.5个时钟周期。问题是沿触发逻辑没法直接产生半拍——但你有两个边沿可以用啊。具体做法先不管占空比用上升沿分频产生一个高电平2拍、低电平3拍的输出clk_pos这用普通的3级移位寄存器反馈就能做到再用下降沿分频产生一个高电平2拍、低电平3拍、相对clk_pos延迟半个时钟周期的输出clk_neg然后把clk_pos和clk_neg相或得到的高电平时间是“2拍 重叠的0.5拍”吗不是——正确的相或结果是高电平从clk_pos的上升沿开始到clk_neg的下降沿结束高电平持续时间是2拍加0.5拍即2.5拍低电平也是2.5拍。合计5拍占空比50%。下面是一个5分频的Verilog参考代码基于D触发器级联实现双沿采样module divide_by5 ( input wire clk, input wire rst_n, output wire clk_out ); reg [4:0] shreg_pos; reg [4:0] shreg_neg; // 上升沿采样的移位寄存器链实现5分频不等宽 always (posedge clk or negedge rst_n) begin if (!rst_n) shreg_pos 5b00001; else shreg_pos {shreg_pos[3:0], shreg_pos[4]}; end // 下降沿采样的移位寄存器链实现相位偏移半个时钟周期 always (negedge clk or negedge rst_n) begin if (!rst_n) shreg_neg 5b00001; else shreg_neg {shreg_neg[3:0], shreg_neg[4]}; end assign clk_out shreg_pos[0] | shreg_neg[0]; // 相或合成50%占空比 endmodule注意这段代码里shreg_pos用的是循环右移最高位反馈到最低位这种接法会让shreg_pos[0]输出一个只有1拍高电平的脉冲序列在循环5拍后重复。shreg_neg同理但晚半拍。两者相或后合并出高电平2.5拍、低电平2.5拍的波形。4.3 奇数分频的电路级实现7474和门电路的组合如果你做实验用的是74系列芯片而不是FPGA电路图可以这样搭用两片7474双D触发器搭出两条独立的5级环形移位寄存器不对一片7474只有2个触发器5级需要3片有点浪费。更经济的做法是用741648位串入并出移位寄存器实现5级循环移位再用两个触发器分别产生原始时钟沿采样后的相移版本最后用一个或门合成。对做实验的同学我建议搭电路之前一定先把波形图用仿真器画出来。没有仿真波形直接接线十有八九会在示波器上看到一堆莫名其妙的现象尤其是反馈线接错导致的“分频比翻倍”或“占空比完全错乱”。我这里提供一个Wavedrom编辑器的时序图描述片段方便你在画波形图时直接参考。Wavedrom的语法非常简单适合快速验证时序逻辑{ signal: [ { name: clk, wave: p......... }, { name: q0, wave: 0.1..0.... }, { name: q1, wave: 0.01..0... }, { name: q2, wave: 0.001..0.. }, { name: clk_out, wave: 0.1.0.1.0. } ]}上面这个例子里q0、q1、q2分别是移位寄存器各级输出clk_out是某个组合后的输出信号。你可以用这个框架不断修改直到自己调出符合预期的5分频50%占空比波形。4.4 n和n1分频切换时的相位误差问题不少通信系统里的可变速率的时钟需要动态在n分频和n1分频之间切换比如小数分频器常见于PLL的Σ-Δ调制器。这时候一个关键问题就来了n分频和n1分频的相位差是多少切换瞬间会不会出现毛刺或相位跳变先说结论分频比从n切换为n1的瞬间输出时钟的相位会有一个阶跃式突变——这个突变并不是理想的“瞬间对齐”而是取决于切换时刻在分频周期中的位置。简单推导一下假设n分频时输出周期为n·Tclkn1分频时输出周期为(n1)·Tclk。在切换发生的那一个周期里输出高电平或低电平的长度会突然多出或者少掉1个Tclk这就造成输出时钟的“瞬时频率”偏离标称值。如果你在PLL设计里用移位寄存器做多模分频器必须记住切换时刻要把分频器先置于预置态比如把寄存器链清零或预置特定值再切换反馈逻辑才能避免输出一个极窄的毛刺脉冲。我在实验室里实测过不做预置直接切换输出波形上会出现一个宽度只有几纳秒的glitch这在纯数字逻辑里不明显但接到模拟锁相环的鉴频鉴相器上会直接导致环路失锁。5. Verilog实现与Wavedrom时序图实操5.1 二分频、三分频、五分频的Verilog模板直接抄这部分给一段可以直接跑的模板代码覆盖2分频、3分频50%占空比、5分频50%占空比。// 二分频 module div2 ( input wire clk, input wire rst_n, output wire clk_out ); reg q; always (posedge clk or negedge rst_n) begin if (!rst_n) q 1b0; else q ~q; end assign clk_out q; endmodule // 三分频50%占空比双沿相或法 module div3 ( input wire clk, input wire rst_n, output wire clk_out ); reg [2:0] pos; reg [2:0] neg; always (posedge clk or negedge rst_n) begin if (!rst_n) pos 3b001; else pos {pos[1:0], pos[2]}; end always (negedge clk or negedge rst_n) begin if (!rst_n) neg 3b001; else neg {neg[1:0], neg[2]}; end assign clk_out pos[0] | neg[0]; endmodule你要注意两点第一三分频的代码里pos和neg都是3位循环移位寄存器循环周期为3拍pos[0]输出一个每3拍出现1拍高电平的窄脉冲。neg[0]是晚半拍的同样窄脉冲。相或后两段窄脉冲之间的间隔被填上形成1.5拍高电平1.5拍低电平的输出。第二初始化值必须是3b001不能是3b000否则电路永远不动作。5.2 用Wavedrom Editor画时序图的具体姿势Wavedrom Editor网上的在线版本即可是我目前见过最顺手的数字时序图工具。画二分频时钟的核心思路是把时钟信号用连续电平描述把分频输出信号按“延迟翻转”规律描述。二分频时序图可以这样写{ signal: [ { name: clk, wave: p................ }, { name: clk_div2,wave: 0.1..0..1..0..1.. } ]}.代表一个时钟周期的间隔0和1代表低电平和高电平。如果你需要带箭头、标注捕捉沿Wavedrom也支持配置node和edge字段。实操提示画时序图时不要手动数点容易数错。先确定“一个完整输出周期占几个输入时钟周期”再决定.的个数。比如二分频一个输出周期占2个输入周期所以clk_div2从0到1中间隔一个.从1到0中间隔一个.就不会画错。5.3 从波形图反推电路连接一个高效调试闭环我发现很多人调试分频电路时习惯“接好线再看波形”遇到问题就蒙圈。我更推荐“先画波形、再写代码/接线、最后对照波形验证”的三步流程先画出期望输出波形用Wavedrom根据波形确定寄存器级数和反馈逻辑在仿真器里跑一遍把仿真波形和Wavedrom波形叠在一起对比。这样做的好处是你能把“设计错误”和“实现错误”区分开。比如你期望5分频但仿真出来是10分频那大概率是反馈多加了反相器如果你期望高电平2.5拍但仿真出来高电平只有2拍那多半是相或的合成时机不对。这种“先画图再接线”的习惯能让你少走很多弯路。6. 分频电路常见问题与排查技巧实录6.1 实测踩坑记录占空比不对、相位乱跳、复位无效我在带学生做这个实验时最常见的故障可以归为三类。我按出现频率排个序并给出排查步骤故障一占空比不是50%。排查顺序先看输出波形低电平和高峰各占几拍。如果是偶数分频检查反馈路径上是否意外多了反相器如果是奇数分频检查双沿采样的两个链是否确实一个用posedge一个用negedge。我曾经见过一个同学把两个always块全写成了posedge结果两条链相位完全相同相或后输出高电平还是2拍、低电平3拍跟没做一样。故障二输出频率是预期的两倍或一半。这通常是反馈逻辑选错了点。移位寄存器分频的输出频率取决于你从哪一级引出信号以及反馈是否取反。你可以用波形图反推在纸上画出每一级寄存器的波形再标出反馈信号的变化规律基本能定位问题。故障三复位信号无效电路上电后状态随机。FPGA里还好说如果是74芯片搭的电路上电初始状态不定是正常的。解决办法是实验前手动按一下复位键把寄存器链置为已知初值或者在设计上让反馈逻辑能从全0状态自恢复。注意环形移位寄存器如果进入全0状态就永远锁死在全0了有的同学没考虑到这一点复位一释放电路纹丝不动还以为芯片烧了。6.2 一张排查速查表照着查就行现象可能原因快速定位方法输出波形完全不变反馈逻辑没有取反或寄存器初值为全0检查反馈路径和初始化值分频比是预期的2倍反馈中多加了反相器去掉反相器再仿真占空比明显不对称奇数分频时双沿采样合成时机不对分别查看两条链的波形确认相差半拍后相或输出有毛刺异步级联导致时钟歪斜累积改为所有触发器共用一个时钟源频率漂移或抖动分频切换瞬间未预置状态产生窄脉冲切换前对分频器预置初值复位后电路不起振寄存器全0无法自恢复检测复位逻辑用非全0初值6.3 一个颠覆认知的案例改成“共时钟”之后一切都对了有一次我帮一个师弟调一个8分频电路他发现输出波形总有随机毛刺频率也不稳定。我第一反应是电源去耦不够但加了电容没用。后来拿示波器一量发现他把三个2分频电路级联每一级的输出直接接到下一级的时钟输入——也就是异步级联。这在低速下问题不大但在几十兆赫兹时钟下每一级D触发器的clk-to-q延迟累加起来第三级的时钟边沿已经被“抖”得不成样子。问题的根源根本不是逻辑错误而是时序余量不够。后来我把三级2分频改成8位移位寄存器同步分频结构所有触发器共用一个时钟毛刺立刻消失。这个案例给我们的启发是分频电路的“看起来正常”和“真的可靠”之间隔着一条叫做时序分析的鸿沟。如果你在工程里遇到在实验室怎么都复现不了的随机故障先怀疑异步设计这是绝大多数时序问题的来源。6.4 给实验报告加分的几个细节最后说点掏心窝的建议。如果你在做课程实验想要让报告或者演示脱颖而出可以顺手做这几件事用示波器的“余晖模式”观察分频输出波形的抖动对比同步结构和异步级联的差别在Verilog仿真里加一段断言assert自动检查占空比是否在49%~51%之间体现出你的工程素养如果你用的是FPGA尝试用Vivado或Quartus里的“时钟资源报告”看分频后信号被分配到了哪个时钟网络顺便了解为什么门控时钟在FPGA里不推荐。这些内容虽然不会直接改变分频电路的逻辑但能证明你对“分频”这件事的理解不止于“画个波形图”。我在实际项目中养成的习惯是每个分频器设计完成后都要额外画一个“分频切换瞬间”的时序图专门检查切换边界有没有毛刺、占空比有没有突变。这个习惯救过我至少两次——一次是通信板卡上的可变速时钟需要动态切换另一次是MCU外部晶振失效后切换到内部RC时钟用的就是移位寄存器分频做的无缝切换。分频这个东西表面上看是数字逻辑课的基础题但真到了需要“可靠工作”的场合每一处细节都经得起推敲才算合格。本文还有配套的精品资源点击获取
返回列表