ARTICLE DETAIL

资讯详情

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

锁存器原理与工程应用:从RS、D锁存器到触发器区别及实战避坑

锁存器原理与工程应用:从RS、D锁存器到触发器区别及实战避坑 我最早对锁存器有直观认识不是在上课而是在实验室里调一块板子。当时的现象很诡异主控已经执行完复位操作但某个状态输出仍然维持着复位前的电平像“赖着不走”。揪了半天最后定位到一条不起眼的信号线上——那里藏着一个记忆单元也就是数字电路基础里被很多人忽略的锁存器。锁存器这个题目教材里通常就是半页式子、一张真值表背完就扔。可它恰恰是理解整个数字系统记忆行为的第一块砖寄存器、计数器、状态机、RAM的存储阵列底层都站着一个类似的存储单元。这篇文章不打算按课本顺序抄一遍而是从一个工程师用它的角度把这几个问题讲透锁存器到底在解决什么问题RS锁存器和D锁存器怎么工作它和触发器到底差在哪里真实项目里哪里会用到它以及我在调试中踩过的几个坑。不管你是正在学数字电路基础的学生还是刚接触FPGA和单片机的开发者接下来的内容应该都能对得上你心里的那些“问号”。1. 锁存器到底解决了什么问题先说一个很基本的问题数字电路凭什么能“记住”东西1.1 组合逻辑的“失忆”困境学数字电路基础大多数人最早接触的是组合逻辑与门、或门、非门、异或门。这些电路的共同特点是输出只由当前输入决定输入一撤输出立刻回到默认状态。换句话说组合逻辑没有记忆。我举个特别直观的例子。假设你给实验室的门装一个报警灯逻辑很简单门磁开关断开灯亮。用组合逻辑做就是一根导线的事。但问题来了——如果门只是被人推开一下然后马上关上灯亮了一下又灭掉等管理员过来的时候根本不知道刚才有人进来过。我们真正想要的是门被打开过一次灯就一直亮着直到管理员手动复位。这就是典型的“记忆需求”。这种需求在数字系统里无处不在。CPU要知道程序执行到哪一步计数器要记住数到了几状态机要记住当前处于哪个状态。所有这些场景都指向同一个抽象概念一个存储单元。而存储单元在最低层就是一位二进制信息的保持。1.2 记忆的最小单位一位二进制信息一位二进制信息就是0或者1锁存器干的活就是把这个值“留存住”。你可以把它想成一个门上的碰珠锁推开门手松开门保持打开再推一下门关上。碰珠就是“保持机构”。锁存器也一样它内部有一种结构能让输出稳定停在两个状态之一要么输出高电平要么输出低电平不会自己飘走。组合逻辑提供不了这种机制因为组合逻辑没有任何“维持过去状态”的结构。要让电路记住东西必须引入一个关键元素——反馈。也就是把电路的输出引回输入端。一旦输出参与决定输入电路就有了一条“记忆路径”。从锁存器出发往上是寄存器、计数器、状态机、RAM阵列。这些复杂模块的记忆行为本质上都是在回答同一个问题我怎么把某个时刻的一个bit留住。所以数字电路基础课把锁存器放在触发器之前是有道理的——你先搞清楚“怎么样能记住一个状态”再去谈“什么时刻去记住”逻辑才顺。2. 从RS锁存器开始最简单的记忆单元把“保持”落实到逻辑门层面最基础的一种实现就是两个逻辑门交叉相连。这就是RS锁存器也叫SR锁存器。2.1 交叉反馈产生的双稳态结构RS锁存器最经典的实现是两个或非门交叉反馈。什么叫交叉反馈就是门1的输出接到门2的输入门2的输出又接回门1的输入。这样一来两个逻辑门形成了一个闭环电路的状态不再只由外部输入决定还与它自己刚才的输出有关。这里我不纠结门级画法直接给功能定义因为不同教材上输入线的命名位置偶尔会不一样但功能逻辑是统一的SSet置位端S有效时输出Q变为1。RReset复位端R有效时输出Q变为0。如果用或非门实现可以把行为写成两个布尔方程Q NOT(R OR Q) Q NOT(S OR Q)Q就是Q的反相输出。如果你手头的教材把两根输入线的名字换过了以功能为准别死记符号位置。这里要提醒的一点是RS锁存器不一定只能用或非门搭用两个与非门也能搭。区别在于或非门版本是S、R高电平有效与非门版本是S、R低电平有效符号上通常标成S和R真值表行为正好反过来。很多人背了或非门版本的真值表看到与非门版本就懵其实只要记住一条或非门的输入端为1起主导作用与非门的输入端为0起主导作用。搞清楚这个两个版本都不会记混。2.2 真值表逐行拆解保持、置位、复位与禁态RS锁存器的功能一张锁存器真值表就能概括。我按S、R的顺序列出来SRQnext状态说明00Q保持记忆101置位Q写入1010复位Q写入011不定禁止状态重点看S0、R0这一行。这是锁存器区别于组合逻辑的核心功能——保持。假设当前Q1、Q0代入方程算一下Q NOT(0 OR 0) 1Q NOT(0 OR 1) 0状态稳定住了。反过来当前Q0、Q1也一样两条保持路径都成立。这就是双稳态的含义电路能稳定停在两种状态中的任意一种不像组合逻辑那样被输入“推着走”。S1、R0这行是置位。S有效输出Q被强制写成1Q变成0。R1、S0这行是复位输出Q被清成0。这两行相当于给记忆单元提供了“写入”通道想存1就拉高S想存0就拉高R。2.3 S与R同时有效的后果为什么是“不定”真值表里最后一行S1且R1很多人背下来“禁止”但没想过为什么禁止。我来推一遍当S1、R1代入方程Q和Q都被拉成了0。问题就出在这里——Q和Q原本应该是互补关系一个高一个低现在两个同为低这个状态本身是自相矛盾的。真正麻烦的是后续。假如S和R同时从1撤回到0两个门会同时进入“释放”状态最后谁先翻、谁后翻取决于门延迟的微小差别。有的芯片可能偏向Q1有的可能偏向Q0甚至同一块芯片在不同温度下结果都不一样。工程上最怕这种不可重复的行为所以严格禁止这个输入组合。我在实际设计中给自己定了一条规矩只要电路里出现RS锁存器必须证明任意时刻S和R不可能同时有效。这个检查看起来多余但后面第6章你会看到我差点在这里吃过亏。3. 门控D锁存器让记忆听从统一指挥RS锁存器能记忆但用起来有两个难受的地方。第一S和R不能同时有效设计约束太强第二输入一变输出就变没有一个统一的时间控制。门控D锁存器就是为了同时解决这两个问题而来的。3.1 消灭禁态把S和R合并成一个D端RS锁存器的禁态根源在于S和R是两个独立输入可以被同时拉高。那如果我把S和R合并成一个输入D会怎么样做法是在RS锁存器前面加一道控制逻辑让电路只有一个数据输入D再配一个控制端CPClock Pulse有些教材写成EN或G。CP作为总开关当CP无效时两个输入端的信号都被挡住锁存器保持当CP有效时S端获得D的值R端获得D的反相也就是D。由于D和D天然相反永远不可能同时为1RS锁存器的禁态从结构上被消灭了。这种结构叫门控D锁存器也叫透明锁存器、D型锁存器。它把“记忆单元”和“写入控制”合成了一体是工程上使用最广泛的锁存器类型74HC573、74LS373这些芯片内部就是8个这样的D锁存器。3.2 “透明”与“锁存”的动态行为D锁存器的行为可以这样描述CP0时锁存器处于保持状态输出Q不变。CP1时锁存器处于透明状态输出Q跟随D变化。D是0Q就是0D是1Q就是1。真值表如下CPDQnext状态说明0XQ保持100跟随QD111跟随QD“透明”这个词用得很形象。CP1的时候锁存器相当于一扇开着的门屋外D端的风可以毫无阻挡地吹进来输出跟着输入变CP0的时候门关上了屋里保留的是关门那一瞬间的内容。这个“跟随保持”的行为是理解D锁存器所有特性的一条主线。后面我讲工程坑的时候还会回来用到它。3.3 D锁存器最容易产生的误解学完边沿触发器再回头看D锁存器很容易产生一个误解以为CP从0跳到1的那一瞬间输出会“采样”一下D然后保持。这是错的。D锁存器不是边沿采样是电平采样。CP只要保持高电平哪怕这个高电平持续10毫秒D在这10毫秒里翻转100次Q就会跟着翻转100次。真正把值“固定”下来的是CP由高变低这个动作——门关上了最后看到的那个值被保留。我经常跟同学说锁存器看“电平”触发器看“边沿”。这两个词记住了很多含混的概念自然就分开了。D锁存器的透明窗口越长外部噪声进入存储状态的概率就越大这一点在干扰环境下尤其致命。4. 锁存器与触发器一字之差行为差之千里如果只说一个数字电路初学者最常犯的概念混淆那一定是在锁存器和触发器之间。两者都能存储一位数据但存储方式完全不同。4.1 电平敏感与边沿敏感的对比我用一张表把核心差异列出来对比项锁存器触发器敏感方式电平敏感边沿敏感控制端有效期间全程透明输出随数据变化只在边沿瞬间采样其余时间输出不变对数据毛刺的容忍度低透明窗口内毛刺会漏过相对高只在边沿附近需要数据稳定典型芯片74HC573、74LS37374HC74、74HC574时序分析难度相对复杂存在透明时间窗标准模型每个时钟沿分析一次打个比方。锁存器像是一扇一直开着的窗户外面有什么动静屋里全程都看得到直到你把窗户关上才算定格了最后一幕。触发器则像一台快门相机只在按下快门的那一瞬间记录画面其他时间不管外面发生什么都不关心。大多数同步数字电路偏爱触发器正是因为触发器的行为“规矩”所有状态更新都对齐到时钟边沿整个系统可以按统一的节拍推进时序分析模型简单清晰。锁存器的透明窗口让输出在一个高电平周期内可能变化多次给时序分析带来很多麻烦。这里有个额外的提醒在Verilog或VHDL里如果组合逻辑的always块或process块里没有把每个分支的输出都写全综合工具会默默推断出一堆锁存器。这一点我第6章会专门讲这里先按下不表。4.2 时序分析里的time borrowing锁存器虽然给时序分析添麻烦但它在高速芯片设计中并没有被淘汰反而有一个非常实用的特性time borrowing有时也叫cycle stealing。先说触发器的约束。触发器要在时钟边沿之前的一段时间保证数据稳定这个时间叫建立时间Tsu边沿之后还要稳定一小段时间叫保持时间Th。数据必须在这段“窗口”内准备好否则触发器就可能进入亚稳态。锁存器不一样。它只要保证数据在透明窗口结束之前稳定就行并不要求数据一定在时钟边沿前准备好。换句话说如果上一级电路逻辑延迟比较大它可以从下一级电路的时钟周期里“借”一点时间过来用。这就是time borrowing名字的来历时间余量不是死的可以在流水级之间挪动。举个例子流水线里第一级如果算得慢第二级算得快用锁存器就能让第一级多占一点时间第二级少占一点整个流水线的总延迟不变但每一级压力均衡了。用触发器做这件事就很难因为每个边沿都是固定的裁判。当然对初学者来说time borrowing知道概念即可。除非你做的是高速ASIC或者特殊时钟方案否则日常项目里更多接触的是触发器的标准时序约束。5. 锁存器在真实项目里承担的角色讲了这么多原理回到现实锁存器真的会被用在电路里吗答案是会而且用得不少。工程里它主要扮演三类角色。5.1 地址/数据复用总线的“分拣员”最经典的应用是单片机系统的地址锁存。以8051内核的单片机为例P0口是分时复用的先输出低8位地址紧接着又切换成数据总线。外部存储器或者外设需要区分这两个阶段否则地址和数据就会混在一起。做法是用一个74HC5738位D锁存器。ALE信号在地址阶段输出高电平此时573处于透明状态P0上的地址直接通过到达573的输出端随后P0切换到数据阶段ALE拉低573锁存输出端仍然稳定保持着刚才的地址。外部存储器靠这个被“冻结”的地址完成访问。这里有个细节值得注意74HC573有两个控制引脚LE锁存使能和OE输出使能。LE决定是否透明OE决定输出端是否允许驱动总线。很多人只关注LE忘了OE低电平有效结果锁存器一直没输出找了半天才发现是悬空或者接反了。5.2 异步短脉冲的“抓住不放”第二个常见应用是捕捉异步事件。外部电路经常会产生一个很窄的脉冲比如传感器比较器跳变、机械开关抖动后的一个有效沿。如果CPU正在忙其他事情轮询IO口的时候这个脉冲可能已经消失了。这时候需要一个能“抓住不放”的存储单元。事件脉冲过来先把锁存器置成1状态被保存下来CPU处理完当前任务读到这个标志再主动发一个清除信号把锁存器复位。这个场景用RS锁存器或者带异步置位/复位的触发器更合适因为脉冲已经消失普通D锁存器无法保持一个已经过去的输入。你如果硬用D锁存器就得保证CP高电平时D一直维持这往往做不到。所以我在项目里看到有人直接用不带反馈的D锁存器做事件捕捉都会提醒一句要么加反馈要么换带置位的结构。5.3 采样保持与输出缓冲里的锁存思想锁存思想并不只在独立锁存器芯片里出现。ADC前面的采样保持电路本质就是“采样”和“保持”两个模式的切换与D锁存器的透明/保持如出一辙。移位寄存器74HC595的并行输出端也带了一级输出锁存目的是在内部移位过程中不让并行输出抖动保证外部负载看到的信号是稳定的。这些场景没有专门叫“锁存器”但底层的理解方式完全一样先把一个值在合适的时刻抓住再让外界在一个稳定窗口内使用它。数字系统里很多设计归根到底都是在做“什么时候该抓”和“抓完怎么稳住”这两件事。6. 我在工程中踩过的锁存器相关的坑下面这三个坑都是我实际调板子或者看同事代码时遇到的。每一个都很有代表性写出来给大家提个醒。6.1 综合工具悄悄给我“送”了个锁存器第一次遇到“锁存器”这个单词是在综合工具的告警里。当时我写了一段Verilog组合逻辑仿真波形怎么看怎么对结果综合上板之后行为完全不对。打开综合报告里面有一行让我后背发凉的告警Inferring latch for signal y。问题出在这段代码always (*) begin if (sel) y a; end组合逻辑块里sel为假的分支没有给y赋值。我的本意是“sel为假时y保持”但组合逻辑是不能“保持”的。综合工具为了满足这个不完整描述就推断出一个锁存器来sel为高时透明跟随sel为低时锁存保持。这个行为看起来像是满足了需求但问题是它引入了电平敏感的逻辑而不是我预想的纯组合逻辑。后续的时序、毛刺、功耗全都偏离了预期。解决办法很直接补全所有分支或者给输出赋默认值。always (*) begin if (sel) y a; else y b; end这之后我给自己定了一个规矩所有组合always块里每个if必须有else每个case必须有default并且让default等于一个明确值而不是注释掉。同时综合报告里的“Inferring latch”告警看到之后必须逐条查清楚不允许直接关掉窗口。6.2 上电后状态居然靠“猜”RS禁态惹的祸第二个坑发生在板级电路。一个设备里用了RS锁存器S端接一个按键输入R端接复位信号。理论上系统上电后S和R都应该是无效电平锁存器处于保持状态状态输出由复位逻辑决定。但实测发现这个输出在上电后有概率是0有概率是1完全没有规律。排查链路是这样的我先用示波器同时抓S和R的波形结果发现上电瞬间有一小段窗口S和R同时为高。这意味着RS锁存器那一刻处于真值表里最脏的一行——禁态。等两个信号都释放之后锁存器进入了哪个状态取决于两个门的延迟竞争于是表现出随机性。根因找到了S端的上电毛刺和R端复位释放信号存在一段重叠设计时没有把这个边界情况考虑进去。修复方案是给S端增加RC延迟和下拉电阻把上电毛刺削掉同时调整复位逻辑保证复位信号释放之前S端已经稳定为低。这次之后我养成了习惯电路里只要出现RS锁存器我就会把所有输入组合尤其是真值表里那个“禁止”项从头到尾推一遍并确认时序上绝对不会发生“同时有效”的情况。6.3 透明窗口放进了毛刺电平敏感电路的经典事故第三个坑和D锁存器的透明特性直接相关。有一块采集板卡用门控D锁存器做数据保持。CP端定时器产生一个宽度几十微秒的高电平窗口D端接着经过比较器的传感器信号。理论上窗口结束之后Q保持的就是那个时刻的传感器状态。但实测数据里偶尔会出现一个完全不合理的大跳变。用逻辑分析仪把CP和D同时抓下来放慢看发现问题出在几十微秒的透明窗口内D上有一个很窄的毛刺宽度只有几百纳秒恰好在这个窗口内翻转了一次。因为D锁存器在高电平期间是透明的这个毛刺直接穿透到Q端并且被当成有效数据锁存了下来。这个问题的本质不是毛刺本身而是我用了电平敏感器件来处理可能带有噪声的信号。修法有几种D端加RC滤波给透明窗口加窄或者直接把D锁存器换成边沿D触发器。边沿触发器只在时钟边沿前后一个极短窗口内对数据有要求毛刺穿过整个高电平区间的风险就小得多。这个坑告诉我锁存器本身的电平敏感特性不是bug但如果你没有意识到这一点在噪声环境里硬拿它当触发器用它就会变成bug。7. 三个自问省掉无数半夜调试这些年调过的板子、看过的代码多了我对锁存器的态度也慢慢固定下来。现在我接手一个设计只要是和记忆单元相关的部分都会问自己三个问题。第一这个地方真的需要锁存器吗如果可以用边沿触发器解决我会优先换触发器。锁存器少一个边界情况后半夜就少一通折腾。第二如果必须用锁存器透明窗口会持续多久窗口内有没有可能进来毛刺这个问题直接决定我需不需要在数据端加滤波或者把窗口尽量缩短。第三RS锁存器里S和R有没有可能在任意时刻同时有效这个问题几乎是个信仰级别的检查项只要电路里有RS锁存器我就默认禁态一定会在某个角落冒出来非得证明它不会才放心。实践里还有一个我挺推荐的做法学锁存器的时候别只看真值表。拿几块门电路芯片在面包板上搭一次RS锁存器手工拨动开关亲眼看看置位、复位、保持和禁态这四种行为再写一段漏掉else的RTL代码跑一遍仿真看看综合工具是怎么偷偷给你“送”锁存器的。这两件事做完比背十遍真值表都管用。数字电路基础这套东西说到底还是得动手摸过才算真正学会。
返回列表