简介:面向数字逻辑课程学习者与电子工程专业低年级学生的实验报告文档,聚焦同步计数器设计与七段译码显示电路的完整实现过程。内容从移位寄存器型计数器的激励函数、状态表与状态转换图分析入手,完整记录了错误状态表的发现与修正、BCD码输入与七段显示器数字的逐一核对,以及用D触发器配合门电路搭建可预置初始状态的同步模5计数器、经74LS47驱动共阳极七段LED显示等关键环节,并附有实验目的、器件清单、引脚标注与实测结果记录。包内为1个docx文件,约5.1MB,按实验步骤分节排布,便于对照实验箱操作与整理报告。目前已有2234人学习,适合需要参考实验记录写法、理清计数器设计与译码显示思路的读者对照使用。
1. 状态表写错的那一刻,数字逻辑实验才真正开始
数字逻辑实验里最反直觉的一件事:电路接对了,灯也在按顺序亮,状态表照样可以是错的。指示灯只能证明“这些状态被走到过”,不能证明“每个状态只通向唯一一个次态”,更不能证明“所有状态都被走到过”。移位寄存器型计数器的第一次记录就出了问题——记到 1111 就以为循环结束,后面的 0111、0011、0001 整个漏掉,状态图和状态表一起作废,重做。
值得研究的地方不在于多背几种计数器,而在于同步时序电路有一条硬性约束:次态是现态的函数,时钟只负责让这个函数每秒执行一次。状态表写错,等于函数写错;函数对了,电路才会自动走成你想要的环。下面从反馈网络、七段译码、模 5 计数三个环节,把这个函数一层层拆开。
2. 移位寄存器型计数器:反馈函数如何把 16 个状态缩减为一条 8 状态循环
2.1 从电路图倒推激励函数,门电路不是装饰
拿到一张计数器电路图,第一个动作不是数芯片,而是找反馈节点。四只 D 触发器串成一条链,时钟并在一起,这就是“同步”两个字的全部含义:四只触发器在同一时刻、同一个上升沿翻状态,谁也不会抢跑。链的后三级是硬连线,D2=y1、D3=y2、D4=y3,纯粹把前一级的输出搬到下一级,这叫移位。
真正决定这个环长什么样的,只有第一级的 D1。它由一片 7486 异或门、一片 7408 与门和一片 74LS00 与非门组合出来,写成布尔式就是 D1 = y4'·(y1 + y3')。这里 y1 是链首那一位,y4 是链尾那一位。y4' 的反相可以用与非门把两个输入并起来实现,y1 + y3' 的或运算也能用三个与非门凑出来,经典做法是 A + B = ((A'·B')'),代价是门数变多但器件种类不变。实验箱上只给你四片芯片,就得这么互相借用。
def next_state(y): """y = (y1, y2, y3, y4),y1 是链首,对应 D1 的输出""" y1, y2, y3, y4 = y d1 = (1 - y4) & (y1 | (1 - y3)) # D1 = ~y4 & (y1 | ~y3) d2, d3, d4 = y1, y2, y3 # 后三级纯移位,无逻辑 return (d1, d2, d3, d4)这段代码照抄的就是电路图,没有做任何化简,目的是让每一行都能对应到一根连线。注意1 - y4表示取反,在两位取值里 1 减去 y4 等价于 not y4,用减法只是为了让返回的元组里全是 0 和 1,方便直接喂给下一轮。位序是第一个要固定下来的约定:y1 放在最左边,那么 1000 就代表链首为 1、其余为 0,这与实验记录里“0(0000) → 1(1000)”的写法一致。位序一旦前后不一致,状态表就会整体错位,这是后面所有排错的根源。
把函数反复调用八次,就是整条环。
start = (0, 0, 0, 0) y, path = start, [] while True: path.append(y) y = next_state(y) if y == start: # 回到起点才算闭合 break print(len(path), path) # 8 [(0,0,0,0), (1,0,0,0), (1,1,0,0), (1,1,1,0), # (1,1,1,1), (0,1,1,1), (0,0,1,1), (0,0,0,1)]输出正好 8 个状态,而且顺序与实验台上按单脉冲按钮记录下来的那串数字完全一致。这一步的意义在于:状态图是可以先算出来的,实验只是核对。先算后测,错了知道错在哪一位;先测后算,错了只能重来。
2.2 状态表不能只靠抄写,要先计算再核对
回到那次失败的记录。当时按了五次单脉冲,看到 0000 → 1000 → 1100 → 1110 → 1111 → 0111,恰好 1111 之后最高位从 1 变回 0,整排灯看起来像“绕回去了”,于是顺手画了个闭环收工。问题在于 0111 和 0001 只差中间两位,在实验箱那排间距很近的 LED 上,串扰和视角误差很容易让人误判,肉眼看到的“回去了”其实是 0011 和 0001 还没走完。
完整的八状态表长这样,每一行的次态都由next_state()算出来,而不是从示波器上抄:
| 现态 y1y2y3y4 | 次态 y1'y2'y3'y4' | 十进制 |
|---|---|---|
| 0000 | 1000 | 0 → 8 |
| 1000 | 1100 | 8 → 12 |
| 1100 | 1110 | 12 → 14 |
| 1110 | 1111 | 14 → 15 |
| 1111 | 0111 | 15 → 7 |
| 0111 | 0011 | 7 → 3 |
| 0011 | 0001 | 3 → 1 |
| 0001 | 0000 | 1 → 0 |
表里能看出一条清晰的规律:前四拍从左往右依次把 1 填进去,后四拍从左往右依次把 1 清掉。这是 Johnson 计数器的典型波形,只不过反馈项被加长了。状态图的判定标准很简单——每个状态的出度必须为 1,入度也必须为 1,二者缺一,这个环就不成立。出度大于 1 说明有竞争,入度大于 1 说明有状态会被两个前驱合并,这在纯触发器电路里不可能出现,出现了就是接线错了。
还剩 8 个状态没进环:0010、0100、0101、0110、1001、1010、1011、1101。这些叫无效状态,但它们不能不管。上电瞬间四只触发器的初值随机,万一落在无效状态上,电路要么自己走回主环,要么卡在一个独立的小循环里出不来,后者叫死锁。把next_state()对这 8 个状态各跑一次,会得到 0010 → 0001、0101 → 0010、1011 → 0101 这样的路径,全部在四拍之内汇入主环。这叫自启动能力,是判断一个计数器设计能不能用的硬指标,不是加分项。
2.3 反馈项为什么长这样:y4' 决定了电路会不会自锁
有人会问,D1 = y4'·(y1 + y3') 里那个或项是不是多余的。把或项去掉,只留 D1 = y4',再跑一遍那 8 个有效状态,输出序列一模一样。也就是说,在正常循环里,(y1 + y3') 这一项对结果没有任何影响,它的作用全部体现在无效状态的归位路径上:加了它,0100 会先跳到 1010 再绕回来;不加它,0100 会跳到 1010 后走另一条完全不同的路。两条路最终都能回到主环,只是绕的圈数不同。这是设计者为了缩短最坏情况下的归位时间做的取舍,代价是多一个或门。
反过来,如果把 D1 写成 y4 而不是 y4',整个电路会直接失效。y4 是链尾那一位,0000 时 y4=0,于是 D1=0,移位之后还是 0000,四只触发器全部停在零,再也不动。同理,1111 时 y4=1,D1=1,四只全 1 也自锁。全零自锁和全一自锁是移位型计数器最常见的问题,根源就是反馈极性反了。判断方法很直接:把 0000 代进你的 D1 表达式,算出来必须是 1,否则上电就是黑屏。
还有一个容易忽略的细节:74LS74 的置 0 端和置 1 端不能悬空。TTL 输入悬空时电平不确定,会被当成高电平,也会被当成天线捡噪声,结果就是上电瞬间某只触发器被随机置位,你以为是“随机初值”,其实是浮空输入端在乱动。没用的置位/复位端一律接 VCC,这是不用额外代价就能避免的踩坑点。
3. 七段译码驱动器:BCD 到段码的映射到底在算什么
3.1 四根线变七根线:74LS47 内部在做什么
74LS47 的输入是四位 BCD,输出是 a~g 七根段线。内部结构可以理解成两级:第一级是 4 线到 16 线的译码阵列,把 0000~1111 展开成 16 根内部线;第二级是七个或非阵列,每一根段线对应一个或非门的组合,把所有“该段应该亮”的那些输入码或起来。这种结构叫“与或阵列”实现,好处是纯组合逻辑、延迟固定,坏处是只能译固定的十个数,想改成十六进制显示就得换芯片。
关键点在于输出极性。74LS47 的七路输出是集电极开路(OC)结构,而且低电平有效:输出拉低时,电流从外部灌进芯片,那一段才亮。所以它必须配共阳极数码管——数码管的公共端接 VCC,七个段引脚分别串限流电阻接到 74LS47 的输出,芯片把某一段拉低,这一段就导通发光。
# 共阳极段码:bit0~bit6 依次对应 a,b,c,d,e,f,g,1 表示该段熄灭 SEG = {0:0x40, 1:0x79, 2:0x24, 3:0x30, 4:0x19, 5:0x12, 6:0x02, 7:0x78, 8:0x00, 9:0x10} def show(code): bits = format(SEG[code], '07b') # 补足 7 位,高位在前 return ' '.join(f'{name}={b}' for name, b in zip('abcdefg', bits))这段表看起来像“没规律的十六进制”,其实每一位都能推导。以 0 为例,a~f 六段全亮、g 灭,低有效下就是 a~f 为 0、g 为 1,写成二进制 1000000,也就是 0x40。再以 1 为例,只有 b、c 两段亮,其余全灭,就是 1111001,0x79。手推一遍两三个数字,剩下的就能对着数码管逐段验证,不需要硬背。实验箱上用四个拨码开关做输入,就是为了让你把这张表从前到后核一遍,而不是抄一遍。
3.2 1010~1111 的六种输入为什么显示“不规则”
实验记录里有一句话很关键:“对于其他序号,得到的数字不规则。”74LS47 对 1010~1111 这六个非法 BCD 码的标准行为是全部输出高电平,也就是七段全灭,不是显示乱码。真正的“不规则”通常来自三个地方。
第一是输入开关浮空。拨码开关如果不带下拉电阻,断开时输入端悬空,TTL 芯片内部的上拉会让它读到 1,但这个 1 很弱,旁边一根线跳变就能把它拉下来,读数在 1010 和 1011 之间来回跳,段码自然忽明忽暗。第二是 OC 输出关断时的漏电流。手册里 ICEX 一般标到几十微安,七段加起来几百微安,正常室内光线下看不出,但在暗室里凑近看,共阳数码管会有一层极淡的底光,容易被当成“显示了奇怪的东西”。第三是段序接错,比如把 a 和 g 对调,0 会显示成一个少了口的方块,看起来就是乱码,但这种错误在 0~9 里同样会出现,不会只在 1010 之后才出问题。
排查顺序建议从输入端开始量:先万用表量 74LS47 的四个输入脚电平,确认拨码开关真的给到了 0 和 1;再量七根输出脚,看非法码时是不是都拉到 4V 以上;最后量数码管两端的压差。跳过前两步直接怀疑芯片,十有八九是白换片。
3.3 360Ω 是怎么确定的:限流电阻并非随便选
共阳数码管的每一段都是一个 LED,正向压降 Vf 大约 1.8~2.0V;74LS47 输出低电平时 VOL 约 0.4V。串在中间的电阻要分掉剩下的压差,电流由电阻决定:
I = (Vcc - Vf - VOL) / R = (5 - 1.9 - 0.4) / 360 ≈ 7.5 mA7.5mA 对现代高亮 LED 已经足够,段亮度肉眼可见且不刺眼。换成 220Ω,电流约 12mA,亮度提升有限,但八段全亮时芯片要同时灌进近 100mA,接近 74LS47 的接地电流上限,芯片会明显发热;换成 1kΩ,电流只有 2.7mA,在实验箱那种带滤光片的数码管上会暗到看不清,尤其在日光灯下。360Ω 落在中间偏保守的位置,是亮度、芯片功耗和器件清单里现有电阻值三者折中的结果。
清单里只给了 6 只 360Ω,不是 7 只,说明实际接的段数不到七段,常见做法是把小数点那一段空着不接。如果七段全接而电阻不够,段与段之间会抢电流,全亮时(显示 8)整体变暗,这是共阳结构的固有现象,不是故障。
3.4 位序接反会出现的典型现象
四个开关标着 X4X3X2X1,X4 是最高位,对应 74LS47 的权重 8 那个输入脚。如果把这四根线整体接反,输入 0001 会被芯片读成 1000,显示 8 而不是 1;输入 0010 读成 0100,显示 4 而不是 2。于是 1 和 8 互换、2 和 4 互换、3 和 12(无效码,全灭)互换,0、5、6、7、9 里有几个看起来还“差不多对”。这种部分正确、部分错位的现象最误导人,因为你会以为是数码管坏了,而不是线序问题。
判断技巧是只拨最低位那一个开关,看显示的数字是 1 还是 8。是 1 说明位序对,是 8 说明 X1 和 X4 接反了。一个动作就能定位,比挨个试快得多。
4. 用 D 触发器搭同步模 5 计数器:预置端才是真正考验时序的地方
4.1 从“要 5 个状态”到四个次态方程
模 5 意味着循环里只有 0、1、2、3、4 五个状态,用四位二进制表示就是 0000 到 0100,第六拍回到 0000。先把次态表列出来,这一步不能省:
| 现态 D4D3D2D1 | 次态 D4'D3'D2'D1' | 十进制 |
|---|---|---|
| 0000 | 0001 | 0 → 1 |
| 0001 | 0010 | 1 → 2 |
| 0010 | 0011 | 2 → 3 |
| 0011 | 0100 | 3 → 4 |
| 0100 | 0000 | 4 → 0 |
D4 那一列从头到尾都是 0,说明最高位永远不需要置 1,可以直接接地,省掉一个方程。剩下三位各画一张卡诺图,能直接读出:D3 = y1·y2,只有在 0011 这一行它才为 1,下一拍把第三位点亮。D1 在 0000 时置 1、在 0001~0011 时取 y1 的反,两句合并写成 D1 = y4'·y3'·y1'。D2 最麻烦,在 0001 和 0010 时为 1,在 0000 和 0011 时为 0,这正好是 y1 和 y2 相异,于是 D2 = y4'·y3'·(y1 ⊕ y2)。
那个 y4'·y3' 的乘积项不是化简出来的,是故意加上去的使能项。y4=y3=0 恰好圈定了 0000~0011 这四行,把 0100 → 0000 的回绕单独排除在外。如果不加这两项,0100 时算出来的 D1 会是 1,计数器会跑到 5 上,模 5 就变成了模 6。在卡诺图上,这就是把 0100 这一格划进 don't care,让方程在有效状态里最简、在无效状态里随便。
def mod5(y): y1, y2, y3, y4 = y en = (1 - y4) & (1 - y3) # 使能项:只有 0000~0011 为 1 d4 = 0 d3 = y1 & y2 d2 = en & (y1 ^ y2) d1 = en & (1 - y1) return (d4, d3, d2, d1) cur = (0, 0, 0, 0) for _ in range(10): print(format(cur, '04b'), '->', format(mod5(cur), '04b')) cur = mod5(cur)跑出来的序列是 0000 → 0001 → 0010 → 0011 → 0100 → 0000,十拍里循环两圈,长度 5 保持不变。使能项en的写法把 y4'·y3' 提出来共用,省两个与门,这在只有四片芯片可用的实验箱上是实打实的资源节省。
4.2 用异步置位端做预置:一次人机配合的时序交易
实验要求这个模 5 计数器能预置初始状态。74LS74 有两个额外的控制端:置位端(PRE)和复位端(CLR),都是低电平有效,而且都是异步的——只要拉低,触发器的输出立刻变成 1 或 0,不等时钟沿,也不看 D 输入是什么。
预置到 2 的过程是这样的:先按住时钟脉冲不让它发,把 y2 那只触发器的置位端拉低、其余三只的复位端拉低,此时输出稳定在 0010;然后松开置位/复位,让四只触发器回到正常待命状态;最后给一个上升沿,计数器从 2 开始加 1,显示变成 3。三步的顺序不能乱。
乱在哪?如果在置位端还拉着的时候给时钟沿,触发器被异步强制在置位状态,时钟沿对它无效;等你松开置位端的那一瞬间,D 输入线上是什么电平,它下一拍就往哪走,而这时候门电路的组合逻辑还没稳定,结果是跳到一个你没预期的状态。这就是竞争,示波器上表现为一个宽度只有几纳秒的窄脉冲,肉眼完全看不到。
还有恢复时间的问题。74LS74 要求置位端在时钟有效沿到来之前的一小段时间(setup)和之后的一小段时间(hold)内保持稳定高电平,否则触发器可能进入亚稳态——输出既不是 0 也不是 1,而是在中间电压上停留几个纳秒到几十纳秒,然后随机倒向一边。手工按按钮的节奏远远慢于这个时间尺度,所以实验台上几乎碰不到;但如果把预置逻辑接到自动电路里,这就成了必须算进去的余量。
4.3 预置到非法状态会怎样:0101 的那一次实验
实验记录里有一行:预置 2,输入一个上升沿变 3;再预置 4,输入一个上升沿变 0。这验证的是正常路径。但如果手抖预置到了 4 以上的值,比如 0101,会怎样?
把 0101 代进方程:y4=1,使能项 en = y4'·y3' = 0,于是 D2=0、D1=0;D3 = y1·y2 = 0·1 = 0;D4 恒为 0。次态是 0000,下一拍直接回零。也就是说,预置到 5 不会让计数器卡死,只会让数码管上闪一下 5 然后跳回 0。这是使能项设计得好带来的意外收获:所有 0101~1111 的非法状态,下一拍都被拉回 0000,因为 y4 或 y3 一旦为 1,使能项就归零,D2 和 D1 全部清零,D3 也只在 y1y2 同为 1 时才有效,而 0101 里 y1=0,所以 D3 也是 0。
这也解释了为什么预置完成后必须把之前置 1 的那一位再清 0。如果预置 2 时把 y2 的置位端松开就完事,那只触发器的 PRE 脚接下来一直是高电平,没问题;但如果电路里 PRE 是通过开关直接接地的,开关没复位就等于一直拉着低电平,下一次时钟来了它还是被强置 1,计数器就永远停在 2 上不动。看起来像“芯片坏了”,其实是开关没松。
5. 常见问题与排查:那些让实验箱“看起来坏了”的坑
5.1 状态表对不上,指示灯走一半就回起点
现象:按单脉冲记录状态,记到 1111 之后下一拍显示 0111,再按一次跳回 1000,中间两个状态 0011、0001 从来没出现过;或者状态表上的次态列和实际顺序整体错位一位。
原因:一是观察不完整,1111→0111 之后那两位变化集中在中间两段,实验箱上相邻 LED 的串扰让人误判成“已经回去了”;二是位序约定不统一,写状态表时把 y1 当最高位,接线时把 Q1 接在了最低位。
解决:先在纸上用next_state()把 16 个状态全跑一遍,打印出来贴在实验箱边上,测一个划一个,划满 8 个才算完成;位序在电路图第一笔就写死在图纸角落,全篇统一。
5.2 数码管该亮的段暗,不该亮的段微亮
现象:显示 8 时整体发灰,显示 1 时 b、c 两段明显偏暗,其余段有一层底光;或者换一块数码管现象依旧。
原因:共阳/共阴接反、限流电阻阻值偏大、74LS47 输出端漏电流。共阳数码管公共端必须接 VCC,如果接到 GND,整个极性反转,该亮的不亮、该灭的亮,看起来就是乱码。
解决:先量数码管公共端电压,确认是 5V 而不是 0V;再量一段的压差,亮度正常时应在 1.8~2.0V 之间,明显低于这个值说明电流不够,检查 360Ω 电阻有没有接错位置。
5.3 一按预置,计数器就跳到 5 以上甚至停住
现象:预置到 2 之后给时钟,显示不是 3 而是一个随机数字,有时干脆停着不动,断电重开又恢复正常。
原因:置位/复位端在时钟沿附近被释放,违反恢复时间,触发器进入亚稳态;或者某只触发器的置位端一直悬空,被噪声随机拉低。
解决:养成固定顺序——先让时钟静止,再设置置位/复位,等 LED 稳定后松开,最后才发时钟。所有没用的置位/复位脚接到 VCC,一根线的事,能减少一大类随机故障。
5.4 单脉冲按一下,计数跳两格
现象:按一次按钮,数码管从 1 直接跳到 3,中间那个 2 一闪而过或者完全看不到。
原因:机械按钮的抖动。金属触点在闭合瞬间会在几毫秒内反复通断几十次,每一次都被当成一个有效时钟沿,计数器自然多走几拍。这种抖动通常用肉眼看不到,只能通过计数结果发现。
解决:在时钟输入端加一个 RC 低通或者用 74LS00 搭一个 RS 触发器做消抖,把抖动压到触发器识别不出来为止。实验箱上如果自带单脉冲模块,先确认它内部有没有消抖,没有就自己外挂一个。
5.5 整机不工作,四只触发器的输出全为 0
现象:上电后所有 LED 全灭,按时钟没有任何反应,74LS47 的七段输出全部为高电平。
原因:时钟极性搞反。74LS74 是上升沿触发,如果单脉冲模块输出的是下降沿,触发器永远等不到有效沿;也可能是电源或地线接触不良,芯片根本没上电。
解决:万用表量芯片的 VCC 和 GND 引脚,确认 5V 到位;再用示波器或者一个 LED 串电阻直接看时钟脚的跳变方向。这一步不要跳过,很多“芯片坏了”的结论都是在没量电源的情况下得出的。
6. 设计取舍:同步预置和异步置位,差的不是一根线
做到这里会发现一个矛盾:74LS163 是“同步可预置计数器”,它的置数端(LOAD)拉低后,芯片不会立刻装载数据,而是等下一个时钟上升沿才把 D3~D0 装进去;而 74LS74 的置位/复位端是异步的,电平一到,输出立刻变。同一个“预置”功能,两种实现方式的时序特性完全相反。
这个差异在实际工程里很关键。同步预置的好处是干净:所有状态变化都发生在时钟沿,输出不会在时钟间隔里突然跳一下,下游电路看到的永远是一个节拍一个节拍的状态序列。用 74LS163 做模 5,把计数到 4 时产生的进位信号反相后接到 LOAD,下一个时钟沿自动装载 0000,全程不需要人工干预,也不会有毛刺。74LS163 的同步清零端(SR)也是同样的道理,清零动作要等时钟沿才生效,避免了异步清零那种“清零信号一撤、状态又弹回去”的竞争。
异步置位的好处是简单:不用等时钟,按下去就变,适合人工操作的实验场景。这次实验就是典型的人机配合——人按按钮的速度是毫秒级,触发器的建立时间在纳秒级,两者差了六个数量级,只要按顺序操作,异步置位不可能出问题。但把它放进自动回绕的电路里就不行了:假设你用异步置位实现“计到 5 就归零”,那么在第 5 个状态出现的瞬间,置位信号就拉低了,四位输出会经历一个从 0101 直接跳到 0000 的瞬态,中间可能闪过 0100、0001 这些非法组合,下游的译码器会短暂显示错误的数字。这种毛刺在示波器上是几纳秒的尖峰,在数码管上是一闪而过的重影,很容易被当成“显示器坏了”。
我的判断标准很朴素:人操作的部分可以用异步,机器自动的部分一定用同步。实验里用置位端预置,因为按按钮的是人;实验里用 74LS163 做计数,因为回绕是自动的。这两者在同一份报告里并存不是矛盾,恰恰是把两种时序模型各自用在了合适的地方。
后来我养成一个习惯:每搭一个时序电路,先在纸上把“哪些信号是时钟驱动的、哪些是电平驱动的”分两列写清楚,凡是跨列连接的线,都单独标出来看有没有竞争。那次状态表漏掉两个状态的教训,本质上也是同一个问题——只看了几个采样点就下结论,没把全状态空间跑完。从那以后我每次画状态图,都强制用脚本把 16 个状态全枚举一遍,一个都不放过。希望这个习惯也能帮到你。
这份实验报告里记录的接线步骤、状态表修正过程和模 5 计数器的完整方程,都在文档里,对照着电路图一个门一个门地核,比单纯背结论有用得多。
本文还有配套的精品资源,点击获取