一、状态机基础:什么是状态机?

大家好,我是你们的FPGA讲师。今天咱们聊聊状态机——这个数字设计里绕不开的核心概念。

说实话,我刚开始学FPGA那会儿,觉得状态机特别神秘。什么「状态」、「转移」、「输出」,听着就头大。后来做项目做多了才发现,状态机其实就是个「有限状态的自动机」。说白了,就是系统在不同时刻处于不同状态,根据输入决定下一步去哪。

1.1 什么是状态机?

状态机,全称有限状态机(Finite State Machine,FSM)。它描述了一个系统在有限个状态之间切换的行为。

举个例子:你按一下按键,灯亮了;再按一下,灯灭了。这就是一个最简单的两状态机——「亮」和「灭」。每次按键就是输入,状态就切换一次。

我在项目中遇到过这样一个场景:一个通信协议解析模块,需要根据接收到的数据包类型,决定下一步是等待、解析还是报错。用状态机来设计,逻辑清晰得不得了。

状态机有三个核心要素:

  • 状态:系统当前所处的模式或阶段
  • 输入:触发状态变化的条件
  • 输出:当前状态下产生的行为

嗯,这里要注意:状态机的状态数量是有限的,不能无限多。所以叫「有限」状态机。

1.2 Moore型与Mealy型状态机的区别

这是面试常考题,也是实际设计中必须搞清楚的。

Moore型状态机:输出只取决于当前状态。

Mealy型状态机:输出取决于当前状态和输入。

听起来差不多?其实差别大了去了。

我个人的习惯是:如果输出需要快速响应输入变化,用Mealy型;如果输出需要稳定、不受输入毛刺影响,用Moore型。

对比项 Moore型 Mealy型
输出依赖 仅当前状态 当前状态 + 输入
输出时序 滞后一个时钟周期 输入变化立即响应
状态数量 通常较多 通常较少
抗毛刺能力 强 弱
典型应用 按键消抖、协议解析 高速数据通路、流水线控制

关键区别一句话总结:Moore型输出稳定但慢一拍,Mealy型响应快但容易受输入毛刺影响。

我曾经在一个高速数据采集项目中,用了Mealy型状态机做数据包解析。结果输入信号有毛刺,输出乱跳。排查了两天才发现是状态机类型选错了。后来改成Moore型,加了一级寄存器,问题就解决了。

1.3 状态转移图的基本画法

状态转移图,是描述状态机最直观的方式。你想想看,一堆文字描述状态切换,谁看得懂?一张图就全明白了。

基本画法规则:

  • 圆圈:表示一个状态
  • 箭头:表示状态转移方向
  • 箭头上的标签:表示转移条件(输入)
  • 状态内部或旁边:标注输出

下面我用一个按键消抖的例子,画一张Moore型状态机的状态转移图。

按键消抖Moore型状态机 - 状态转移图 IDLE 输出: 0 WAIT 输出: 0 PRESSED 输出: 1 RELEASE 输出: 0 key_in=1 cnt==20ms key_in=0 cnt==20ms key_in=0 key_in=1 key_in=1 key_in=0 图例: 状态 转移方向 key_in=1 转移条件 输出: 0 状态输出

这张图里,我画了4个状态:

  • IDLE:空闲状态,等待按键按下
  • WAIT:等待消抖计时完成
  • PRESSED:确认按键按下,输出高电平
  • RELEASE:等待释放消抖计时完成

每个箭头上的条件,就是状态转移的「触发器」。比如从IDLE到WAIT,条件是key_in=1(按键按下)。

我的小技巧:画状态转移图时,先画所有状态,再画转移箭头。别一上来就画箭头,容易乱。我习惯用不同颜色区分不同状态,这样一眼就能看出当前在哪个阶段。

1.4 状态机设计的基本步骤

做状态机设计,我总结了一个「三步法」:

  1. 画状态转移图:把逻辑关系可视化
  2. 写状态编码:给每个状态分配二进制码
  3. 写HDL代码:用Verilog或VHDL实现

嗯,这里要注意:状态编码方式会影响电路面积和速度。常用的有二进制编码、格雷码、独热码。我个人的习惯是,状态少于8个用二进制编码,多于8个用独热码。

避坑指南:我曾经在一个项目中,状态编码用了二进制,结果状态转移时出现了「竞争冒险」,导致状态跳到了非法状态。后来加了「default」分支才解决。所以写状态机时,一定要处理所有未定义状态!

1.5 小结

状态机是数字设计的基石。Moore型和Mealy型各有优劣,选型时要根据实际需求来。状态转移图是沟通设计的利器,画好了,代码写起来就顺了。

下一节,我们会用按键消抖这个经典案例,手把手带你写一个完整的状态机代码。到时候你就知道,状态机其实没那么可怕。


可可精品资料库