一、状态机基础:什么是状态机?
大家好,我是你们的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型状态机的状态转移图。
这张图里,我画了4个状态:
- IDLE:空闲状态,等待按键按下
- WAIT:等待消抖计时完成
- PRESSED:确认按键按下,输出高电平
- RELEASE:等待释放消抖计时完成
每个箭头上的条件,就是状态转移的「触发器」。比如从IDLE到WAIT,条件是key_in=1(按键按下)。
我的小技巧:画状态转移图时,先画所有状态,再画转移箭头。别一上来就画箭头,容易乱。我习惯用不同颜色区分不同状态,这样一眼就能看出当前在哪个阶段。
1.4 状态机设计的基本步骤
做状态机设计,我总结了一个「三步法」:
- 画状态转移图:把逻辑关系可视化
- 写状态编码:给每个状态分配二进制码
- 写HDL代码:用Verilog或VHDL实现
嗯,这里要注意:状态编码方式会影响电路面积和速度。常用的有二进制编码、格雷码、独热码。我个人的习惯是,状态少于8个用二进制编码,多于8个用独热码。
避坑指南:我曾经在一个项目中,状态编码用了二进制,结果状态转移时出现了「竞争冒险」,导致状态跳到了非法状态。后来加了「default」分支才解决。所以写状态机时,一定要处理所有未定义状态!
1.5 小结
状态机是数字设计的基石。Moore型和Mealy型各有优劣,选型时要根据实际需求来。状态转移图是沟通设计的利器,画好了,代码写起来就顺了。
下一节,我们会用按键消抖这个经典案例,手把手带你写一个完整的状态机代码。到时候你就知道,状态机其实没那么可怕。
可可精品资料库