数字电路把一定电压范围解释成逻辑 0 或 1。范围之间有噪声裕量,超出范围可能得到错误或不确定结果。逻辑抽象便于推理,但芯片引脚仍然有电气限制、传播延迟和负载能力。

组合逻辑只看当前输入

与、或、非门可以组成多路选择器和加法器。对一位全加器,输入为 a、b、进位 cin:

sum  = a XOR b XOR cin
cout = (a AND b) OR (cin AND (a XOR b))

三个输入一共有八种组合,可以穷举验证 sum+2×cout=a+b+cin。这比只试 1+1 更能发现公式或接线错误。组合电路存在传播延迟,多个路径延迟不同时可能出现毛刺,不能把任意组合输出直接当成时钟。

时序逻辑保存历史

触发器在指定时钟边沿采样输入,下一状态由当前状态和输入共同决定。建立时间要求输入在边沿前保持稳定,保持时间要求输入在边沿后继续稳定。异步输入不满足要求时可能引起亚稳态;同步器降低传播风险,却无法把概率变成绝对零。跨时钟域的多位数据还需要握手、异步 FIFO 等结构,不能简单给每个位各接两级触发器。

软件状态机使用同样的状态转移思想。按键可能在几毫秒内反复跳变,如果每个电平边沿都解释为一次按下,一次操作可能触发多次。

本页消抖器每 1 ms 接受一个已同步的数字样本。只有连续三个样本都与当前稳定状态不同,才更新状态并发出事件。候选电平回到稳定状态时计数归零。这会增加约几毫秒确认延迟,适合慢速按键;它会吞掉短脉冲,不适合计数编码器。

穷举和序列实验

下载 逻辑与状态机脚本,执行 python logic.py。它穷举全加器的八组输入,并向消抖器注入带反跳的按下、释放序列。预期只产生一次按下和一次释放,最终输出 PASS。

这是离散行为模型,不计算门延迟、亚稳态或电气波形。真实按键输入需要合适的上下拉;机械输入、硬件滤波和同步措施应根据芯片和电路决定。使用逻辑分析仪时记录采样率、阈值和原始波形,软件采样日志不能替代引脚上的测量。

设计时先写清楚什么

为每个状态写出含义、进入条件、退出条件和异常事件处理。把状态更新集中到一个位置,可以避免“这个回调设成连接中,另一个回调又设成离线”的竞态。输出依赖当前状态的 Moore 模型较容易解释;输出也直接依赖输入的 Mealy 模型可能更快响应,设计时要分析组合路径。

练习:把阈值改为五个样本,构造一个四毫秒短脉冲并解释为何不会触发;再加入长按事件,保证一次长按只发出一次通知。为每条状态转移写一个输入序列,检查不存在无法退出的状态。

面试自查:锁存器与边沿触发器如何区别?组合逻辑为什么会有毛刺?两级同步器解决了什么,又没解决什么?状态机测试为何需要覆盖序列而不只是覆盖单个输入?

参考:Nand to Tetris:布尔逻辑实验、Nand to Tetris:时序逻辑与存储器实验、Altera 数字逻辑与 HDL 先修要求。