ARTICLE DETAIL

资讯详情

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

运动码表设计实战:用Excel建模状态机,Logisim仿真通关

运动码表设计实战:用Excel建模状态机,Logisim仿真通关 做运动码表这类数字逻辑设计任务很多人的第一反应是直接打开Logisim或者Multisim开始连线搭电路结果往往是一边调线一边挠头状态不知道什么时候该跳输出信号一会儿多一会儿少整个设计变得特别被动。我自己的习惯是反过来的拿到题目第一时间先在Excel里把状态转换表和输出函数表完整列出来把表格当成设计的“施工图”等表格逻辑完全通了再去碰电路元件基本上一次就能通电跑通。这篇文章就围绕“运动码表”这个经典课程设计任务详细拆解如何用Excel完成状态机的建模、状态转换关系的推导、输出函数的化简与落地最后再落到Logisim里仿真验证。整个过程不涉及高深的理论但每一步都会有可直接复制的表格结构、公式写法和实操经验适合正在做数字逻辑课程设计的同学也适合想系统掌握有限状态机建模思路的电子爱好者。1. 整体设计与思路拆解1.1 运动码表到底要做什么先想清楚一个“运动码表”系统的本质。它不是一个单纯往上加计数的计数器而是一个带控制逻辑的时序系统。你把码表拆开看核心模块有三个控制状态机、计时计数器、显示输出。常见的运动码表功能大概是这样的有两个按键一个用于“开始/暂停”切换另一个用于“复位”。按下开始按钮计时开始再按一次同一个按钮计时暂停按复位按钮计时值清回零点。如果处于暂停状态再按开始计时继续跑而不是从头开始这是和普通计时器很不一样的地方。这种逻辑用电路实现本质就是设计一个三状态有限状态机清零等待状态、计时运行状态、暂停保持状态。这个状态机接收按键输入根据当前状态决定下一状态同时产出一组控制信号比如计时使能、清零信号以及给显示器用的数据输出。把需求这样一拆你就知道真正需要解决的问题是什么了——不是“怎么计数”而是“怎么让状态正确地切换并且在合适的时候把正确的信号送到计数器上去”。状态切换的逻辑一旦想清楚了计数器反而只是几个74LS器件或者寄存器的事。1.2 为什么选择Excel来呈现状态转换和输出函数我见过很多同学实验报告里的状态转换表都是从状态转换图上照着抄一遍抄完就丢在一边然后去搭电路了。这样做很容易出问题实际连接完电路后某个输入组合没有定义次态或者两个输出信号冲突电路就表现出“有时正常有时乱跳”的症状。Excel在这里的价值不是因为它能画好看的表格而是因为它能把状态转换和输出函数变成可计算、可检查、可推导的工程文件。理由有三点我一条一条说。第一状态转换表本身就是一张逻辑表“现态输入”确定“次态输出”这正是表格最擅长表达的数据结构。你可以把每一个输入组合都当作一行数据把所有可能的分支全部列出来Excel的公式会自动算出次态和输出比手画真值表快得多也错得少。第二Excel天然适合做卡诺图。卡诺图需要按格雷码的顺序排列输入变量网格的行列结构刚好就是卡诺图的平面展开形式。你在格子里面填1或者0圈出相邻的1来化简这个过程用Excel的操作比在纸上涂改要直观很多而且检查起来也方便。第三表格做完之后可以作为电路仿真的预期基准。Logisim里跑出来的波形和Excel算出来的结果可以一一对照哪个信号不对回溯到表格就能立刻定位问题出在哪一行。所以这个思路很明确先做Excel逻辑模型再做电路实现。表格不是给报告凑页数用的它本身就是设计过程的核心产出物。2. 核心细节解析与实操要点2.1 状态定义和状态编码怎么选现在我们把状态机正式定义一下。运动码表有三个状态我用符号表示S0空闲清零态显示归零计数停止S1计时运行态计数器正常累加S2暂停保持态计数值停在当前值三个状态需要用状态变量来表示。这里有两种常见的编码方案一种是二进制编码用两位二进制数表示三个状态剩下一个编码作为无效态另一种是独热码每个状态用一位寄存器表示三个状态需要三个触发器。对运动码表这种小规模状态机我强烈推荐二进制编码。S0、S1、S2可以分别编码为00、01、10。两位状态变量Q1Q0就够了节省触发器。独热码在状态很多时能简化下一状态逻辑但只有三个状态的时候反而浪费资源而且复位时还要额外处理全零状态麻烦不少。这里有一个新手特别容易忽略的点两位状态变量一共有四种组合00、01、10剩下那个11是无效状态。如果电路在上电时或者受到干扰时进入了11状态状态转换表里必须有明确的处理路径否则系统就会卡死。我们在Excel里做状态转换表的时候也要把这个无效状态的处理考虑进去一般做法是让它无条件回到S0空闲态。2.2 状态转换表应该包含哪些关键列状态转换表的本质可以用一句话概括在什么情况现态下收到什么输入系统会跳到什么状态给出什么输出。我建议列的结构是这样现态输入A输入B次态次态编码Q1Q0计数使能EN清零信号CLR说明S000S00001空闲等待S010S10110按下开始S0X1S00001复位优先S100S10110持续计时S110S21000按下暂停S1X1S00001复位优先S200S21000暂停保持S210S10110按下继续S2X1S00001复位优先这个表有几个值得强调的地方。注意输入B复位信号的优先级问题。当B为1时不管A是什么、当前是什么状态系统都回到S0这就叫“异步优先复位”。在Excel里做这个表的时候优先级一定要在公式里体现出来顺序错了整个逻辑就反了。注意为什么有些行写的是X无关项。当B1时A的取值不影响结果所以这些行可以直接合并成一行用X表示A是任意值。这样表格行数少了一截化简时候也能直接把无关项利用起来圈卡诺图但前提是你必须意识到X代表的是“该条件下这个输入不影响结果”不代表“这个组合不存在”。2.3 输出函数其实不只是显示输出很多初学同学理解“输出函数”条件反射想到的就是数码管上显示什么数字于是状态转换表里只写了次态没有写输出等到连接电路时才发现计数器的使能端该从哪接都不知道。其实在运动码表这个系统里输出函数至少分为两类。第一类是控制类输出包括计数使能EN、清零信号CLR可能还有显示锁存信号。这些信号决定了计时器是否工作、是否需要归零。它们是从状态机引出的重要输出和数码管内容同等重要。第二类是数据类输出就是当前计时值对应的BCD码或者二进制数值用于最终译码驱动显示。数据类输出本质上来自计数器而不是状态机本身但为了便于整体设计经常会把它和状态机的控制信号放在同一个表格里管理。我在做这个表的时候还会添加一列“END”表示某些状态组合下的结束动作但其实这个不是必需的主要看你的设计是否需要。关键是你要建立一个习惯每一次状态跳转发生的时候输出信号应该是什么值都要在表格里有明确的一行对应绝不能靠“差不多能推断出来”。3. 实操过程与核心环节实现3.1 第一步在Excel里建立状态转换总表打开Excel新建一个工作表第一个工作表我命名为“状态转换表”。按下面的列名建表头状态编号 | 状态名 | Q1 | Q0 | A | B | 下一状态编号 | 下一状态名 | Q1 | Q0 | EN | CLR前面三到五行可以先手动填一些基础信息比如状态编号和状态名。为了后续公式自动生成次态编码我会用VLOOKUP或者INDEXMATCH来做查询映射。假设我建立了一个辅助区域就是状态映射表状态名Q1Q0S000S101S210然后在状态转换表里用公式根据Q1、Q0、A、B的当前组合去查出下一状态。为了清晰地演示拿“是否复位B优先”这一条逻辑来说。在“下一状态编号”列可以这样写以第2行为例IF(B21, 0, IF(AND(Q10, Q00, A0), 0, IF(AND(Q10, Q00, A1), 1, ...)))这个公式写起来比较长而且容易出现括号错位我建议你改成查询表的做法。先用辅助列生成一个“状态编码键值”比如Q1*2Q0然后根据这个键值配合A和B查次态表的索引。更省力的办法是直接用条件格式和Excel的“数据验证”功能在A和B列做下拉选项只允许填0和1避免手误输入其他数字导致逻辑判断出错。我实际操作中见过太多因为文字和数字混在一起导致后续查表失败的案例提前用“数据验证”限制输入能把这类低级问题直接扼杀在摇篮里。3.2 第二步用Excel推导输出函数的真值表状态转换表搭好之后输出函数表可以单独放在第二个工作表里。输出函数的本质是把所有输入组合和状态组合列出来然后为每一个输出信号填写它的逻辑值。在这里我们主要处理三个输出信号EN、CLR、以及次态两位Q1、Q0。针对EN逻辑可以描述为当系统处于运行状态S1且没有复位时EN为1其他情况为0。或者等价地说当次态是S1时EN为1。用Excel公式表达如果次态编码的“下一状态名”在G列就可以写IF(G2S1, 1, 0)针对CLR更直接只要B为1或者系统停在S0空闲态CLR就为1IF(OR(B21, AND(Q10, Q00, A0)), 1, 0)当然你可以把多个公式先在Excel里算好然后把计算出来的数值选中复制粘贴成静态值这样表里的所有输出列就变成了标准真值表。这一步很关键——它把动态公式变成了可以用于后续卡诺图化简和电路实现的静态数据。我再强调一个细节在做这个真值表的时候所有状态和输入组合的笛卡尔积都应该完整列出来这里状态有3个有效态加上1个无效态输入有两路各有0和1两种所以理论行数应该是 4×416 行。有效组合当然没有那么多但在Excel里把无效态也列出来并标记为“未使用”能避免后面化简的时候漏掉某个组合。3.3 第三步用卡诺图辅助推导逻辑表达式真值表有了下一步是化简逻辑表达式。这一步在Excel里怎么做我的做法是每个输出信号都单独建一个小型卡诺图区域。拿次态Q0举例输入变量有四个Q1、Q0、A、B。按照卡诺图的规则行变量取Q1和Q0列变量取A和B行列都按格雷码排列00、01、11、10。然后在Excel里的对应位置填上真值表中Q0的值。填完之后人工观察相邻格子把相邻的1圈出来就能写出最简与或表达式。以我上面设计的状态机为例Q0为1的情况下大致包括当前是S0且按下A且未按下B当前是S1且按下A且未按下B当前是S2且按下A且未按下B以及当前是S1且未按下A且未按下B等情形。综合下来次态Q0的逻辑可以化简成类似Q0 ¬Q1 · Q0 · ¬B · A ¬Q1 · ¬Q0 · A · ¬B Q1 · ¬Q0 · ¬B · A ¬Q1 · Q0 · ¬B · ¬A可以看到这里有很多项可以合并核心就变成“A1且B0时状态在S0/S1/S2之间切换A0且B0时保持原运行/暂停状态”。这个本质上就是一个带优先级的转移逻辑。说实话四变量的卡诺图手工圈图还勉强能承受如果输出信号多了每一张都要手工填效率就会偏低。这时候可以利用Excel的公式自动把真值表中的数值填充到卡诺图区域里比如用INDEX/SUMIFS去匹配行坐标和列坐标对应的组合。具体做法是在卡诺图单元格中写一条公式根据该单元格对应的行格雷码和列格雷码去真值表区域查找对应输出值公式拖拽一次就能填满整个图。3.4 第四步把表达式落到Logisim电路里表格推导完成最后一步才是打开Logisim连线。先用两个D触发器作为状态寄存器Q1和Q0输出接出去。触发器的D输入端接次态逻辑组合电路。次态逻辑用与门、或门、非门按卡诺图化简后的表达式逐项搭起来。我搭过这个电路实际顺序是这样的放两个D触发器并联同一个时钟信号时钟就用1kHz左右的脉冲源这是计时基准。触发器的输出Q1、Q0引出作为状态反馈信号接入组合逻辑电路。组合逻辑有三个主要输出D1、D0、EN分别对应次态两位和计数使能。计数器使用一个4位或8位计数器EN端接到组合逻辑的EN输出复位端接到CLR输出。计数器输出接到数码管驱动电路或者译码器。这里有一个非常容易踩的坑D触发器的时钟不能直接接按键。按键按一下产生的不是单个脉冲而是一长串由于机械抖动引起的抖动信号直接接时钟会导致状态机连续跳好几次。解决的办法是在Excel模型设计阶段就应该明确状态机的输入是用“电平信号边沿检测”还是“按钮脉冲”。最简单的处理是在按键输出后加一个同步器和边沿检测电路让状态机只在按键按下的上升沿采样一次输入。这个我在下面问题排查章节再展开说。还有一个是输出信号的展宽问题。EN信号如果是从组合逻辑直接出来的在实际电路中可能会产生毛刺。如果计数器对EN是电平敏感而不是时钟边沿敏感的这些毛刺会被真实捕捉导致多计数。所以在Logisim里我更推荐的做法是让计数器只在时钟上升沿更新而EN只决定“是否允许计数”毕竟是同步时序毛刺问题基本不会扩散。4. 常见问题与排查技巧实录4.1 Excel公式计算结果和预期不符怎么办可能原因一逻辑优先级写反了。我在前面反复强调B信号是复位优先如果公式里把A判断写在B前面那么在A和B同时为1的时候结果就会先执行开始/暂停的逻辑把复位丢掉了。排查方法是在Excel里专门加一行“A1B1”的边界测试如果这行的结果不是S0基本可以断定优先级出了问题。可能原因二引用的单元格范围没有绝对锁定。Excel公式拖拽的时候如果不加美元符号锁定VLOOKUP或者INDEX的查询区域会随着行号下移而偏移导致后几行查不到数据。我从第一次做这表时踩过这个坑后来所有跨区域引用的公式一律用F4锁定区域。可能原因三文本型和数字型数据混用。如果状态编号列输入的是“1”而不是数字1或者用了文本格式的“S0”后续所有逻辑比较都等于白做。建议状态名和状态编码分开两列编码列只放数字状态名列只放文本查询连接时再拼接成字符串。4.2 状态机仿真时按键抖动导致状态乱跳这是我在实物调试中最常遇到的问题。Excel模型里按键被理想化为电平跳变但在真实电路里或者在高精度仿真里一次机械按键会产生毫秒级的反复通断如果这个信号直接送到状态寄存器的时钟端就等于一下子给了好几个时钟周期状态机会直接跳穿比如从S1直接跳到S0甚至跳到无效状态。解决办法有两类。一类是硬件上的去抖电路电容加电阻组成积分电路或者用施密特触发器整形。另一类是逻辑上去抖在状态机前面加一个同步器再采样比如用两级D触发器把按键信号同步到系统时钟域然后只检测时钟边沿这样一次按键只产生一个有效脉冲。考虑到运动码表状态机的时钟本身频率不高我建议在工程实现时直接用“同步采样”思路按键信号过两级D触发器输出接入状态机的组合逻辑作为输入状态机的时钟统一用固定时钟源。这样既解决了抖动又保证了所有状态跳变和时钟边沿严格同步方便后面写实验报告分析波形。4.3 计时器走时不准误差累计如果你用的是固定频率时钟源比如晶振产生的1kHz脉冲那走时精度主要取决于分频是否准确。很多人直接把1kHz时钟接给秒计数器没有做分频结果秒位每个周期都跑得快了几倍。正确的做法是先确定计数器最小时基。如果码表要显示百分秒那需要一个100Hz的计时脉冲。1kHz时钟经过一个模10分频器得到100Hz脉冲再驱动百分秒计数器百分秒计数器每计满100次输出一个进位脉冲给秒计数器秒计数器每计满60次给分计数器进位。这套级联结构需要提前在Excel里把每个计数器的模值列清楚再落到Logisim时会轻松很多。还有一个小坑是D触发器和计数器不要共用一个带有毛刺的时钟源。分频器的输出可能带有组合逻辑毛刺不能直接用来驱动下一级计数器时钟最好是通过寄存器输出的分频信号来驱动。4.4 状态转换和输出函数排查速查表我把上面这些问题整理成一张速查表方便你调试的时候对照排查症状可能原因检查与解决办法状态机跳不到预期状态转换表缺失某个输入组合检查Excel状态转换表是否覆盖所有现态和输入组合A和B同时按下时行为异常优先级未定义或写反在表格中明确B优先并检查公式逻辑顺序计数器没有使能信号EN输出函数没有和状态关联检查EN真值表验证运行状态下是否输出1按键按下后跳了多次状态按键抖动直接触发时钟增加两级同步寄存器按键信号通过同步后再参与逻辑系统上电进入未知状态无效状态未定义次态在状态转换表中补充11状态跳回S0的行仿真波形出现毛刺组合逻辑直接输出控制信号控制信号改用寄存器输出或者用同步计数方式走时快或慢分频模值不对核对分频级联的模数百分秒、秒、分钟是否匹配如果你在实际调试中遇到了不属于以上的症状先回到Excel模型里去检查状态转换表和输出函数表而不是直接去改电路。这是我一直强调的思路逻辑电路只是实现表格才是规格表里写错了电路改来改去也修不好根。最后再分享一个小经验。我第一次做完这个运动码表设计时觉得Excel表不过是个辅助后来在一次调试中因为复位优先级没有在表格里体现清楚实物确实出现了“复位和暂停同时按下时概率性进入计时状态”的怪现象。后来回到Excel把优先级单独加列、重推了次态表达式再改动电路里两处门电路的接法问题半小时解决。从那以后我每次做时序逻辑设计都先老老实实把表填满再动硬件。如果你做完这个码表想继续扩展还可以把状态转换表导出成地址真值表用只读存储器和可编程逻辑器件来实现整个状态机那样连与或门都不用了直接把状态和输入拼成地址输出就是存储单元里的数值。这样表格的价值又升了一级。希望这篇分享能帮你在做运动码表设计的时候少走几步弯路。
返回列表