2. 状态机基础:有限状态机(FSM)的基本概念、Moore机与Mealy机的区别

说到嵌入式低功耗设计,状态机是个绕不开的话题。我做了这么多年嵌入式,发现很多功耗问题其实不是硬件选型的问题,而是软件逻辑混乱导致的。状态机,说白了就是让芯片知道「我现在在干嘛,接下来该干嘛」。它不乱跑,功耗自然就降下来了。

2.1 什么是有限状态机?

有限状态机(FSM)是一个数学模型。它描述了一个系统在有限个状态之间如何切换。你想想看,一个嵌入式设备无非就是:待机、运行、休眠、唤醒……这些状态来回切换。

一个标准的FSM包含五个要素:

  • 状态集合:系统所有可能的状态,比如 {IDLE, RUN, SLEEP}
  • 输入集合:触发状态变化的事件或条件
  • 转移函数:当前状态 + 输入 → 下一个状态
  • 初始状态:系统上电后的第一个状态
  • 输出函数:每个状态(或转移)产生的动作

核心要点:FSM在任何时刻只能处于一个状态。这个「唯一性」是低功耗设计的关键——芯片不会同时干两件事,功耗自然可控。

我在一个物联网传感器项目里遇到过这种情况:设备明明该休眠了,却因为某个中断标志没清,在IDLE和SLEEP之间反复横跳。一测电流,平均功耗比预期高了3倍。后来用状态机一梳理,问题立刻暴露——转移条件没写完整。

2.2 Moore机与Mealy机:两种输出方式

FSM根据输出产生的方式,分为两种经典类型:Moore机和Mealy机。这个区别很重要,直接影响到你的代码结构和功耗表现。

对比项 Moore机 Mealy机
输出依赖 只依赖当前状态 依赖当前状态 + 当前输入
输出时机 状态进入后立即生效 输入变化时立即响应
响应速度 慢一拍(需等待时钟沿) 快(组合逻辑直接输出)
抗干扰能力 强(输出稳定) 弱(输入毛刺可能直通输出)
状态数量 通常较多 通常较少
低功耗场景 适合休眠/唤醒类设计 适合高速响应类设计

我的经验:低功耗设备我倾向于用Moore机。为什么?因为输出只跟状态挂钩,不会因为输入抖动就乱动外设。你想想看,一个无线模块如果因为输入毛刺频繁发射,那功耗就崩了。

2.3 代码对比:Moore vs Mealy

光说概念太虚,咱们直接看代码。下面是一个简单的电源管理状态机,用C语言实现两种风格。

Moore机实现

// Moore机:输出只依赖当前状态
typedef enum {
    POWER_OFF,
    POWER_IDLE,
    POWER_ACTIVE
} power_state_t;

power_state_t current_state = POWER_OFF;

void moore_machine(power_event_t event) {
    power_state_t next_state = current_state;
    
    // 转移逻辑
    switch (current_state) {
        case POWER_OFF:
            if (event == EVT_WAKE) next_state = POWER_IDLE;
            break;
        case POWER_IDLE:
            if (event == EVT_ACTIVATE) next_state = POWER_ACTIVE;
            if (event == EVT_TIMEOUT)  next_state = POWER_OFF;
            break;
        case POWER_ACTIVE:
            if (event == EVT_IDLE)     next_state = POWER_IDLE;
            if (event == EVT_SHUTDOWN) next_state = POWER_OFF;
            break;
    }
    
    // 状态切换后,根据新状态输出
    if (next_state != current_state) {
        current_state = next_state;
        switch (current_state) {
            case POWER_OFF:    disable_peripherals(); break;
            case POWER_IDLE:   enable_low_power();   break;
            case POWER_ACTIVE: enable_full_power();  break;
        }
    }
}

Mealy机实现

// Mealy机:输出依赖当前状态 + 输入
void mealy_machine(power_event_t event) {
    switch (current_state) {
        case POWER_OFF:
            if (event == EVT_WAKE) {
                enable_low_power();      // 转移时立即输出
                current_state = POWER_IDLE;
            }
            break;
        case POWER_IDLE:
            if (event == EVT_ACTIVATE) {
                enable_full_power();     // 转移时立即输出
                current_state = POWER_ACTIVE;
            }
            if (event == EVT_TIMEOUT) {
                disable_peripherals();   // 转移时立即输出
                current_state = POWER_OFF;
            }
            break;
        case POWER_ACTIVE:
            if (event == EVT_IDLE) {
                enable_low_power();      // 转移时立即输出
                current_state = POWER_IDLE;
            }
            if (event == EVT_SHUTDOWN) {
                disable_peripherals();   // 转移时立即输出
                current_state = POWER_OFF;
            }
            break;
    }
}

注意:Mealy机的输出在转移过程中产生。如果输入信号有毛刺,输出也会跟着抖。我曾经在一个按键检测模块里用了Mealy机,结果按键抖动直接导致外设反复开关,功耗飙升。后来换成Moore机,加了一个状态做去抖,问题才解决。

2.4 状态机与低功耗的关系

状态机对低功耗的意义,我总结为三点:

  1. 状态可预测:你知道设备当前在干什么,功耗模型可以精确计算。
  2. 转移可控:每个转移条件都是显式定义的,不会出现意外唤醒。
  3. 输出可管理:外设的开关与状态绑定,不会漏关。

说白了,没有状态机的代码就像没有交通灯的路口——谁都能走,迟早撞车。而状态机就是那个交通灯,让系统有条不紊地运行。

2.5 一张图看懂FSM

下面我用SVG画一个典型的电源管理状态机,展示Moore机的结构。这个图我在培训时经常用,新手一看就明白。

电源管理有限状态机 - Moore机示例 电源管理FSM(Moore机) POWER_OFF 输出: 关闭所有外设 POWER_IDLE 输出: 低功耗模式 POWER_ACTIVE 输出: 全速运行 (初始状态) EVT_WAKE EVT_ACTIVATE EVT_IDLE EVT_TIMEOUT EVT_SHUTDOWN 说明 • 每个状态有独立的输出动作(Moore机特征) • 转移由事件触发,事件不携带输出信息

看图技巧:注意每个状态框内都写了「输出: xxx」。这就是Moore机的特点——输出跟状态绑定,跟你怎么进来的没关系。你从OFF到IDLE,输出是低功耗模式;从ACTIVE到IDLE,输出也是低功耗模式。输出完全由当前状态决定。

2.6 实际选型建议

到底用Moore还是Mealy?我个人的经验是这样的:

  • 低功耗场景优先用Moore机:输出稳定,不会因为输入抖动导致外设误动作。我做的电池供电设备,90%都用Moore机。
  • 高速响应场景用Mealy机:比如协议解析、数据采样,需要输入一来就立刻输出。但要注意加输入滤波。
  • 混合使用也可以:有些状态用Moore,有些转移用Mealy输出。但我不建议新手这么干,容易把自己绕晕。

一句话总结:Moore机稳,Mealy机快。低功耗设计,稳字当头。