简介:这是一份基于Vivado平台的时序电路设计实验报告,面向数字电路与FPGA初学者,目标是掌握时序逻辑从设计、仿真到综合验证的完整流程。压缩包共232个文件,约928KB,内部以完整工程为主,既有核心Verilog源码(.v)、Vivado工程配置(.xpr)、综合与仿真日志(.rpt/.log),也有一键运行的bat与tcl脚本,可复现编译、仿真、综合各阶段;另附docx实验报告和PDF说明,便于对照阅读。目前已有690人学习下载。资源系统呈现实验目的、设计思路、代码实现、仿真操作、综合结果与常见排错记录,覆盖从需求分析到验证结论的各个步骤,特别适合正在完成同类课程设计或希望用Vivado独立开发时序模块的学生,既能作为课程报告的写作范本,也能当作工程模板快速迁移到计数器、状态机等典型时序电路设计中。 说实话,大学数字电路课里能让人又爱又恨的实验不多,时序电路绝对算一个。组合逻辑的实验,搭完电路通上电基本上就出结果;时序电路不一样,你得跟时钟打交道,跟触发器打交道,还要面对各种“仿真明明过了,板子就是不工作”的诡异问题。这篇文章把我在实验三“时序电路设计”里的完整思路和踩坑过程整理出来,从方案选型到上板调试都覆盖到,希望对正在做类似实验的朋友有帮助。
1. 动手之前先想清楚:异步计数和同步计数差的不是一点
我们这个实验的要求是设计一个模16计数器,用LED显示计数状态。刚拿到题目的时候,很多人第一反应是“计数器嘛,用异步的,一级一级连起来就完事了”。确实,异步计数器结构简单,每个触发器只需要接一个时钟,总能找到一种连法让电路“转起来”。但等你真的去搭、去观察波形,就会发现问题不少。
1.1 异步计数器为什么容易出毛刺
异步计数器又叫纹波计数器,原因就是进位信号像水波一样从低位传到高位。最低位翻转后,次高位才跟着翻转,次高位翻转后,第三位才开始动作。这中间的传播延迟累积起来,会让输出状态出现极其短暂的“中间态”。
举一个最常见的例子:当计数从0111变到1000时,理论上应该是直接跳到8,但实际波形里,高位在翻转过程中可能经历0100、1100这些非法状态。如果在这样的电路后面接了译码器或者控制逻辑,这些瞬间出现的错误状态就可能被后面电路采样到,导致误动作。这个现象在低频LED演示时看不出来,接上示波器或者后续电路就麻烦了。
1.2 我为什么选同步计数方案
同步计数器所有触发器共用同一个时钟,每个触发器是否翻转由组合逻辑根据当前状态决定,从结构上消除了进位传播延迟的累积问题。拿4位二进制计数器来说,最低位每个时钟翻转一次,第二位在Q0为1时翻转,第三位在Q0和Q1都为1时翻转,最高位在Q0、Q1、Q2都为1时翻转。每个触发器的状态更新都发生在同一个时钟边沿,输出自然同步更新,不会产生纹波效应。
做实验的时候,我直接采用同步方案,虽然在驱动方程推导上多花了一些时间,但后续仿真和调试省心太多。这里想说的是,如果实验目的是理解时序概念,异步方案值得搭出来对比观察;但凡是做功能完整的计数器,同步方案就是它的上位替代,别在这上面将就。
2. 触发器选型与驱动方程推演:卡诺图在这里真正派上用场
选触发器和推驱动方程是整个设计最核心的部分。实验指导书通常给出两种选择:JK触发器和D触发器,但很少有人讲清楚在计数器场景下到底该用哪个、为什么。
2.1 JK触发器与D触发器的取舍
先说结论:计数器优先选JK触发器。原因不复杂,因为计数器的本质是“在满足条件下翻转”,而JK触发器在J=K=1时翻转、J=K=0时保持,天然对应这种需求。你不需要额外的组合逻辑去制造翻转条件,直接告诉它“什么时候翻”就行。
D触发器不是不能做计数器,但它有一个特点:输出永远跟随输入。用它做二进制计数时,每个触发器的D端都需要一个异或门来产生“翻转或不翻转”的逻辑。异或门本身是额外的器件,会增加连线和故障点。但这个结论的前提是你在用中小规模集成电路搭建。如果你用的是FPGA或者CPLD,D触发器反而是首选,因为FPGA内部查找表资源丰富,D触发器是基本单元,做计数器的综合结果比JK更好。所以选型要先看实现平台,再做决定。
2.2 四个触发器的驱动逻辑推导
我用的方案是4个JK触发器,从低位到高位分别记为FF0到FF3。因为JK触发器的次态方程是Q+ = JQ' + K'Q,我们希望计数器从当前状态变到下一个状态,所以只需要明确“当前状态在什么条件下,某一级应该翻转”。
推下来其实是这样的规律:
- FF0:每个时钟都翻转,J0=K0=1
- FF1:当Q0=1时翻转,J1=K1=Q0
- FF2:当Q0=Q1=1时翻转,J2=K2=Q0·Q1
- FF3:当Q0=Q1=Q2=1时翻转,J3=K3=Q0·Q1·Q2
这个规律其实很好记:某一位置1的条件,是它前面所有低位都为1。这一点和“加法进位”的逻辑完全一致。建议动手画卡诺图验证一遍,不要直接抄结论。卡诺图的价值在这里体现得淋漓尽致——它能把状态表和驱动方程之间的对应关系理得清清楚楚,以后做序列检测器、状态机还能复用这套方法。
2.3 器件选型与面包板布局建议
芯片型号这一步也有讲究。TTL族里面,74LS76是双JK触发器,一个芯片两颗触发器,两个芯片刚好组成4位计数器;74LS112同样是双JK触发器,但是负边沿触发。用正边沿还是负边沿取决于你的时钟源信号,建议先确认自己手头时钟模块的输出极性再选芯片。CMOS族对应的是74HC76和74HC112,电压和功耗参数不同,学生实验里两个都能用,但实际是CMOS器件输入阻抗很高,悬空引脚容易受干扰,不用的输入引脚一定要接地或者接VCC。
面包板布局方面,我踩过一次坑才学乖:不要把所有芯片排成一长条,那样电源线和地线绕来绕去很容易接错。把两个JK触发器芯片面对面放置,电源线走同一侧,地线走另一侧,驱动逻辑用的与非门芯片放在中间靠近输入端的位置。这样走线最短,排查起来也最方便。
3. 仿真通过只是开始:板级调试中的真实翻车现场
仿真软件里做完功能验证,信心满满去接板子,结果一通电,LED乱跳或者干脆不跳。这种情况在时序电路实验里太常见了,几乎每个做这个实验的人都经历了从“仿真万岁”到“硬件翻车”的完整过程。我把几个大概率会遇到的问题列出来,你们可以提前避开。
3.1 按键做时钟源:一次按下,三次跳变
第一个坑就是拿按键直接当时钟信号。按键是机械结构,按下和释放的时候接触点会弹跳,一个物理动作会在短时间内产生多个脉冲。这些脉冲经过触发器之后,会被当成多个时钟沿处理,于是LED灯就会从0跳到1再跳到3或者更乱的状态。
解决这个问题的标准方案是加消抖电路。最简单的用RC低通滤波加施密特触发器整形,R取10kΩ,C取10μF左右,时间常数远大于机械抖动时间,能把抖动滤掉大部分。更稳妥的做法是用一对与非门搭一个RS触发器消抖电路,利用双稳态特性消除抖动,效果比RC滤波好很多,而且硬件上就是两个与非门的事情,用74LS00就能搞定。
如果你们实验室用的是开发板,板载时钟通常是晶振分频出来的标准方波,不存在抖动问题。但晶振频率太高(常见的是50MHz或100MHz),不经过分频直接送进触发器,LED肉眼根本看不到变化。这时需要加一个分频模块,把频率降到1Hz到2Hz左右才能观察。
3.2 去耦电容和复位释放,两个最容易被忽略的点
第二个坑是电源问题看起来不像电源问题。时序电路在时钟边沿瞬间会有大量触发器同时翻转,瞬间电流需求很大,如果面包板电源线上没有去耦电容,芯片供电电压会瞬间跌落,导致逻辑电平判断错误。
正确做法是每个芯片的VCC和GND之间就近接一个0.1μF的陶瓷电容,电容引脚尽量贴近芯片引脚。同时在面包板电源轨两端并一个10μF到100μF的电解电容,稳定整体供电。这个细节看着不起眼,但加上之后整个电路的稳定性会有一个质的提升。
第三个坑是复位信号的释放时序。用按键控制复位端时,如果复位按键没做消抖处理,复位信号释放瞬间会出现多次高低电平跳变,每一次跳变都可能触发一次复位,导致计数器从中间某个状态开始跑而不是从0开始。解决方式和时钟按键一样,也要消抖。
3.3 用逻辑分析仪替代示波器,效率完全不同
调试时序电路,我最大的体会是示波器虽然在测量模拟信号方面无可替代,但观察数字逻辑信号时效率不够高。示波器两个通道最多同时看两路信号,看4位计数器至少需要清4路信号,还要手动对齐时间轴,非常别扭。
逻辑分析仪在这方面的体验好很多。8通道起步,直接同时采集全部计数输出和时钟信号,一眼就能看出时序关系对不对。现在市面上几十块钱的USB逻辑分析仪就能达到24MHz采样率,对做课程实验完全够用。接上之后用软件触发时钟上升沿,看各通道的信号,哪一位没翻转、哪一位提前翻转,全都清清楚楚。
4. 从计数器到状态机:这个实验真正在教你的通用方法
模16计数器做完之后,这个实验如果没有继续往下延伸,收获其实只发挥了一半。因为计数器的本质是一个特殊的状态机——它的状态按固定顺序循环,从输入来看没有任何条件分支。而时序电路设计的核心方法论,恰恰是状态机设计。
4.1 状态转移图是整个设计的起点
正确的设计流程永远是先把状态图画出来,再写状态表,然后才是推导驱动方程。做计数器的时候状态图很简单:0到15循环,每个状态只有一个确定的次态。但即便如此,画状态图这个动作也是在建立“状态视角”的思维习惯。
我发现很多同学做完计数器直接抄指导书上的驱动方程去连电路,连状态表都没有完整列过一遍。一旦让他做一个序列检测器,比如“检测连续输入101并输出高电平”,就完全不会了。原因就是跳过了状态图这一步,没有建立起“用状态表示历史信息”的概念。序列检测器需要记住“已经收到了什么序列”,这个记忆功能就是靠状态实现的——没必要记住完整输入历史,只需要记住与当前判断相关的信息,这本质上是状态压缩。
4.2 把方法迁移到序列检测器
拿101序列检测器(Moore型)举例,状态设计思路是这样的:
- 初始状态S0:表示尚未收到任何有效序列
- S1:表示已收到1
- S2:表示已收到10
- S3:表示已收到101,输出1
从S3状态继续输入0,应该回到S2状态,因为当前收到的序列末尾是10,仍然有匹配101的可能;输入1则回到S1。这些转移关系画成状态图,再编码状态,用卡诺图化简出触发的驱动方程和输出方程,整个设计流程就完整闭环了。
做计数器实验时如果你主动用状态机的方法论去解构一遍计数器——画出状态图、列出状态表、推驱动方程——再去理解序列检测器就会发现它们是一个东西,只是计数器状态多、转移关系单一,序列检测器状态少、转移条件多一点而已。这种“同一套方法可以打不同场景”的感觉,比多做几个实验更能培养硬件设计能力。
4.3 计数器的另一面:分频器
还有一个容易被忽略的延伸应用是分频。模16计数器从最高位输出得到的信号频率是输入时钟的1/16,从次高位得到的是1/8,以此类推。所以计数器天然就是一个分频器。
分频器在工程实践里太常用了:单片机时钟需要分频、通信协议需要分频、LED扫描需要分频。很多同学在实验课上只把计数器当成一个“数的数”,没有意识到它作为一个频率变换模块的价值。如果实验报告里能把这一点单独拿出来讨论,会显得你对这个实验的理解比其他人深一层。
5. 实验报告怎么写得让老师挑不出毛病
实验做完了,硬件也调通了,最后一个环节是写报告。很多人觉得报告就是交差,抄抄实验目的、贴几张仿真截图就完事。但实际上实验报告是学习成果的直接呈现,有思考的报告和流水账报告在老师眼里差距非常明显。
5.1 报告中一定要出现的图表
首先是状态转移图。这个图是整个设计的灵魂,没有它,后面的驱动方程都成了无源之水。画图的时候要把状态编号标清楚,最好和LED显示对应起来,转移条件也要写明白。
其次是驱动方程推导过程。不要只写最终结论,把卡诺图化简的中间步骤贴出来,让老师看到你是真的推过而不是抄的。最后是仿真时序图,这里有个细节:截图要带时间坐标轴标注,把关键时间点的状态跳变圈出来,比如计数值从0到1、从7到8的跳变位置,时钟沿的对齐关系。不要截一张密密麻麻的完整波形就扔上去,要在图上加标注说明。
5.2 数据分析和问题讨论是真正拉开差距的地方
很多同学原型验证结束后就直接进入结论阶段,这部分其实是最能体现思考深度的段落。直接对比仿真结果和实测结果,如果完全一致,说明设计思路和实现过程没有脱节,值得写出来;如果不一致,更要详细分析原因。
我当时实测时就发现计数器在某个状态停留了大约一个时钟周期的时间才跳走。排查之后发现是复位按钮释放瞬间产生了毛刺,多触发了一次复位信号,导致状态比预期慢了一个节拍。把这个问题写进报告,附上修改前后的逻辑分析仪截图,老师给的评价明显与其他报告不一样。
还有一个小技巧:报告末尾可以写一段“实验思考”。不写套话,就写你在实验过程中真正产生的疑问,比如“为什么同步计数器在高速状态下比异步计数器更可靠”“如果扩展到8位计数器,驱动逻辑的扇入会不会成为瓶颈”“如果在同一个时钟域里挂了多个触发器,时钟偏斜怎么处理”。这些问题不需要有标准答案,但它们证明了你是带着脑子在做实验,而不是在按图施工。
写在最后
这个实验真正的收获不在于你把一个模16计数器调通了,而在于你通过它第一次完整走了一遍时序电路的设计流程:状态定义、驱动方程、仿真验证、硬件实现。这和我后面做单片机系统、做FPGA开发时走的流程是一模一样的。如果手边有逻辑分析仪,建议把计数器的各个输出信号采集下来,观察一下时钟边沿和数据变化的对齐关系,那会给你建立很直观的数字电路“时序感”。
本文还有配套的精品资源,点击获取