20、状态机在工业控制中的应用:PLC状态机、安全联锁状态机

工业控制,说白了就是让机器按人的意志干活。但机器这东西,你让它动起来容易,让它不出错、不出事故,那才是真功夫。我在工业自动化领域摸爬滚打十几年,见过太多因为状态混乱导致的设备故障——电机该停的时候没停,阀门该关的时候没关,轻则废料,重则伤人。

所以今天咱们聊聊状态机在工业控制里的两个典型应用:PLC状态机和安全联锁状态机。这两个东西,一个管效率,一个管安全,缺一不可。

PLC状态机:让设备按部就班地跑

PLC(可编程逻辑控制器)是工业控制的大脑。你想想看,一条生产线上的机械臂、传送带、传感器,它们之间怎么配合?靠的就是状态机。

我习惯把PLC程序拆成若干个状态,每个状态对应设备的一个动作阶段。比如一个简单的物料搬运系统,可以分成这么几个状态:

状态 动作 触发条件
IDLE(空闲) 等待启动信号 系统上电或复位完成
PICK(抓取) 机械臂下降、夹爪闭合 启动按钮按下且物料到位
LIFT(提升) 机械臂上升至安全高度 夹爪夹紧信号确认
MOVE(移动) 水平移动到目标位置 提升到位信号
PLACE(放置) 机械臂下降、夹爪松开 移动到位信号
RETURN(返回) 机械臂回到原点 放置完成信号

每个状态只做一件事,做完就切换到下一个状态。这样做的好处是什么?逻辑清晰,调试方便,出了问题一眼就能看出卡在哪个状态。我在项目中遇到过,一个同事把所有逻辑写在一个梯形图里,几百行,出了故障根本查不了。后来我帮他改成状态机结构,半天就定位到了问题——原来是传感器信号抖动导致状态跳转异常。

核心原则:PLC状态机设计要遵循"一状态一动作"原则。每个状态只执行一个明确的动作,不要在一个状态里干三件事。这样既好写,也好查。

安全联锁状态机:保命的逻辑

安全联锁,这个词听着就严肃。没错,它确实是保命的。在工业现场,有些设备一旦误动作,后果不堪设想。比如冲压机、切割机、高温炉,这些设备必须有一套独立于控制系统的安全逻辑。

安全联锁状态机,说白了就是一套故障安全的状态切换规则。它跟普通状态机最大的区别在于:安全状态是最高优先级。任何异常信号,不管真假,先切到安全状态再说。

我给大家画个图,看看安全联锁状态机的基本结构:

SAFE(安全状态) RUN(运行状态) FAULT(故障状态) 启动条件满足 急停/异常 严重故障 手动复位 安全联锁状态机:安全状态永远是最高的优先级

看到没?从运行状态到安全状态,箭头是红色的。这意味着任何异常信号都会强制切回安全状态。我曾经在一个冲压机项目里,操作员的手套被夹住,幸好安全联锁状态机在50毫秒内切到了安全状态,机器立刻停机。要是晚那么一丁点,后果不敢想。

警告:安全联锁状态机必须独立于主控逻辑。不能用同一个CPU既跑控制程序又跑安全逻辑。这是国际标准IEC 61508的要求,也是血的教训换来的。

代码实现:PLC状态机的C语言骨架

虽然PLC通常用梯形图或ST语言编程,但底层逻辑用C语言实现更清晰。我给大家写个简单的状态机骨架,你们可以移植到任何嵌入式平台上:

/* 状态枚举 */
typedef enum {
    STATE_IDLE,
    STATE_PICK,
    STATE_LIFT,
    STATE_MOVE,
    STATE_PLACE,
    STATE_RETURN,
    STATE_SAFE,      /* 安全状态 */
    STATE_FAULT      /* 故障状态 */
} SystemState;

/* 状态机结构体 */
typedef struct {
    SystemState currentState;
    uint32_t    timeout;      /* 状态超时计数器 */
    uint8_t     safetyInput;  /* 安全输入信号 */
} StateMachine;

/* 状态处理函数指针 */
typedef void (*StateHandler)(StateMachine *sm);

/* 状态表 */
StateHandler stateTable[] = {
    [STATE_IDLE]   = handleIdle,
    [STATE_PICK]   = handlePick,
    [STATE_LIFT]   = handleLift,
    [STATE_MOVE]   = handleMove,
    [STATE_PLACE]  = handlePlace,
    [STATE_RETURN] = handleReturn,
    [STATE_SAFE]   = handleSafe,
    [STATE_FAULT]  = handleFault
};

/* 主循环 */
void runStateMachine(StateMachine *sm) {
    /* 安全联锁:最高优先级 */
    if (sm->safetyInput == 0) {
        sm->currentState = STATE_SAFE;
        return;
    }

    /* 调用当前状态的处理函数 */
    if (stateTable[sm->currentState] != NULL) {
        stateTable[sm->currentState](sm);
    }
}

这段代码的核心就两点:状态表驱动安全优先。状态表让代码结构清晰,安全优先让系统永远把安全放在第一位。我在实际项目中,还会加一个看门狗定时器,如果某个状态卡住超过设定时间,自动切到故障状态。

小技巧:工业控制中,状态切换一定要加防抖处理。传感器信号在工业现场很容易受干扰,我习惯在状态切换前加一个20ms的延时确认,避免误触发。

避坑指南:我踩过的几个坑

做工业控制这么多年,有些坑我是一步一步踩过来的。分享给你们,希望你们少走弯路:

  • 状态爆炸问题:我曾经在一个项目里设计了30多个状态,结果自己都搞混了。后来我学会了用层次状态机,把大状态拆成子状态,逻辑瞬间清晰了。
  • 安全联锁不能只靠软件:软件再可靠,也有bug。安全联锁必须配合硬件——比如安全继电器、光栅、急停按钮。软件只是最后一道防线。
  • 状态切换要记录日志:工业设备出故障,最怕查不到原因。我习惯在每个状态切换时,把时间戳、旧状态、新状态、触发条件都记录下来。这样事后分析,一目了然。
  • 不要用延时做状态切换:有些新手喜欢用delay()做状态切换,这在工业控制里是大忌。延时期间CPU被阻塞,安全联锁就失效了。要用定时器轮询。

嗯,说到这,我想起一个项目。当时一个客户说他们的设备偶尔会"死机",查了两个月没找到原因。我过去一看,发现他们的状态机里有一个状态没有超时保护,一旦传感器信号丢失,就永远卡在那个状态里。加上超时保护后,问题再没出现过。所以,每个状态都要有超时处理,这是铁律。

总结一下

PLC状态机让设备按流程跑,安全联锁状态机保命。两者结合,才能做出既高效又安全的工业控制系统。我个人习惯在设计阶段就把状态图画出来,然后对着图写代码,这样不容易漏掉边界情况。

工业控制容不得半点马虎。你写的每一行代码,都可能关系到操作员的生命安全。所以,敬畏之心,不可少


公众号:蓝海资料掘金营,微信deep3321