最早被顺序功能图吸引,是在改造一台四工位转盘机的时候。当时我正被梯形图折磨:每个工位都有伸出、夹紧、检测、复位,还要在各工位之间做互锁和时序配合,稍微改一个节拍,就要把几十个线圈的置位复位逻辑重新理一遍。后来我把这套控制用顺序功能图(SFC,Sequential Function Chart)重写,整个流程最后只有十几个步,哪个工位卡住、哪一步没走完,监控画面上一目了然。顺序功能图是IEC 61131-3标准里的一种编程语言,它把控制逻辑组织成“步-转换”的结构,特别适合描述按顺序、可能分支、可能并行执行的工艺流程。这篇文章就从基本结构入手,聊聊步、转换、动作、分支这些元素到底怎么用,以及在现场调试中容易踩的坑。
1. 初看顺序功能图:它和梯形图的本质区别在哪
很多人第一次打开顺序功能图编辑器,第一反应是“这玩意儿不是工艺流程图吗?”没错,SFC画出来就是那样,纵向从上到下一步一步排。梯形图更多模拟继电器电路,左右母线、触点、线圈,逻辑本质是“如果条件满足,输出导通”;而SFC本质是“当前处在哪个状态,执行哪些动作,满足什么条件后进入下一个状态”。它强调的是状态,不是导通。这是一个思维切换点,想通了再看下面的结构会容易很多。
1.1 SFC更像“工序图”而不是“电路图”
如果让车间老师傅画一张设备动作流程,他大概率会画成:上电复位 → 取料 → 定位 → 加工 → 下料 → 回到取料。每一步是一个工序,工序和工序之间是“前一步完成”的条件。顺序功能图几乎是这张工序图的直接映射,步对应工序,转换条件对应“前一步完成且允许继续”的判断。
梯形图则把所有工序堆在同一张网络里,虽然也能用置位复位模拟状态机,但是阅读性很差。一个设备有十几个动作,每个动作用两个辅助继电器表示状态,程序写到后面,别人根本不敢动。而SFC把状态显式画出来,当前在哪一步、下一步条件是什么,一眼就能看到。这就是它最大的价值:可读性和可维护性。
1.2 SFC解决的是哪类问题:顺序逻辑的锅不该用梯形图硬背
我自己的判断标准是:只要设备动作可以写成“先做什么,再做什么,如果怎么样就做什么”,就适合用SFC。装配机、灌装线、包装线、物流分拣、过程控制,这些都是典型场景。
反过来,如果任务是模拟量PID闭环、高速计数、需要微秒级响应的中断处理,那就不适合用SFC。这些东西仍然交给梯形图、ST或者专用功能块处理,SFC只负责流程层的调度。顺序功能图不是万能语言,它擅长的是“流程性”任务,不是“调节性”任务。把这点想明白,就不会出现用SFC写PID然后抱怨“跑不动”的情况。
1.3 一台小型灌装机:全文案例设定
为了让后面讲结构时有实物参考,我设定一台小型灌装机,流程很简单:推瓶到位 → 夹紧 → 灌装 → 封口 → 放行,然后循环。更具体一点:
- 初始步:上电复位,等待启动按钮。
- Step10 推瓶:推瓶气缸伸出,把空瓶推到灌装位。
- Step20 夹紧:夹紧气缸动作,固定瓶子。
- Step30 灌装:灌装阀打开,灌到设定液位或时间到。
- Step40 封口:封口气缸下行,完成压盖。
- Step50 放行:夹紧松、推瓶退回,成品离开。
这个案例虽然简单,但足够覆盖单序列、选择分支、并行分支、跳转循环这些核心结构。后面每一章我都会拿它举例。
2. 五个基础元素,把顺序功能图的结构骨架搭起来
顺序功能图的基本结构可以拆成五样东西:步、转换、有向连线、动作和初始步。把它们搞明白了,基本就能看懂绝大多数SFC程序。
2.1 步(Step):状态的最小单元
步用一个矩形框表示,里面写编号或名称。它是SFC里状态的最小单元。运行过程中,一个步要么是“活动”的,要么是“非活动”的。活动步对应的动作会被执行,非活动步对应的动作不执行。
步的名称我建议按照“动作对象+序号”来写,比如Step30_灌装,不要写成S30这种没有信息的编号。现场调试时,活动步一高亮,你看名字就知道设备在干什么。名字起得好,SFC程序就成功了一半。
2.2 转换(Transition)与转换条件:什么时候“走下一步”
转换是步与步之间的横向短粗线,它不是一个主动的执行机构,而是一个“闸门”。每个转换都必须配套一个布尔条件,写在短粗线旁边。这个条件可以是传感器信号、比较指令、定时器状态,也可以是ST表达式。
执行的规则是:前级步处于活动状态,并且转换条件为真,转换才能被触发。转换一旦触发,前级步变成非活动,后续步变成活动。条件持续为真,就会立即触发转换;如果只想在某个瞬间触发一次,就要考虑沿信号或者让条件在步切换后自然消失。
2.3 有向连线:执行方向的唯一表达
有向连线就是连接步和转换的纵向线段,表示执行方向。默认从上到下,可以不画箭头;但从下往上跳转、循环回退时,必须用箭头标明方向。
这里有个容易忽略的规则:有向连线不能自己表示“或”的逻辑。你不能画两条线从一个步出来直接进两个步,必须用专门的分支结构。同理,两条线也不能直接汇成一个步,必须用会合结构。这些分支和会合后面单独讲。
2.4 动作与动作修饰符:每一步到底干什么
动作附属于步,画在步的右侧,用一个横向矩形框表示。每个步可以挂多个动作。动作可以是一个变量输出,比如Q0.0置位;也可以是一个功能块调用,比如电机启动、阀门打开、定时器启动。
动作修饰符决定动作的执行方式,常用几个我整理成了表格:
| 修饰符 | 含义 | 使用场景 |
|---|---|---|
| N | 非存储,步活动期间持续执行,步结束自动停止 | 普通气缸输出、阀门开闭 |
| P/P1 | 脉冲,步变为活动时执行一次扫描周期 | 触发计数、发一个启动脉冲 |
| S | 置位,步活动后输出保持,直到被R复位 | 需要保持的回路 |
| R | 复位,对指定输出复位 | 清除S动作保持的输出 |
| L | 时限,步活动时执行,最长执行限定时长 | 限制某动作的持续最大时间 |
| D | 延时,步活动后延时执行动作 | 需要等待稳定再动作的场合 |
2.5 初始步:上电后从哪开始
初始步是整个SFC的入口,用双线边框的矩形框表示,和普通步有明显区别。PLC上电、程序复位或安全复位后,初始步成为活动步。没有初始步,整个SFC程序启动后根本不知道从哪开始。
初始步里通常放系统初始化动作,比如清报警、复位所有输出、进入等待模式。很多新手容易漏掉初始步,或者把初始步直接当成步0使用,却没有给步0写转换条件,导致程序一直在初始步不往下走。记住:初始步也有转换条件,条件满足后才能进入正常流程。
3. 单序列结构:先会走,再学跑
单序列是顺序功能图里最简单的结构,也是所有复杂结构的基础。它就是一个步、一个转换、再一个步,像糖葫芦一样串下去。
3.1 步-转换-步到底怎么执行
SFC的执行逻辑其实很固定,每个扫描周期做三件事:
- 扫描当前活动步,执行这些步对应的动作。
- 扫描与活动步相连的转换条件。
- 对满足条件的转换执行步切换:当前活动步变为非活动,转换后面的步变为活动。
这样一个周期完成一次状态更新。从外部看,步和步之间的切换几乎是瞬间完成的,不像继电器电路需要几十毫秒的动作累积。这也是为什么有些转换条件如果设计得不好,会出现一步刚进去就被“踢”出来的现象。
3.2 一个没有分支的灌装流程拆解
我们把灌装机的基本流程写成单序列:
| 步 | 关联动作 | 转换条件 |
|---|---|---|
| Init | 输出复位,报警清除 | 启动按钮按下并确认在原点 |
| Step10 推瓶 | 推瓶气缸伸出 | 推瓶到位传感器X1 |
| Step20 夹紧 | 夹紧气缸动作 | 夹紧到位传感器X2 |
| Step30 灌装 | 灌装阀打开+定时器启动 | 定时器到或液位开关到 |
| Step40 封口 | 封口气缸下行 | 封口完成传感器X3 |
| Step50 放行 | 夹紧松开,推瓶退回 | 推瓶后退到位且放行位无瓶 |
| 回跳 | — | 放行完成信号+循环允许 |
注意转换条件用的是“完成信号”,不是单纯的时间。虽然灌装可以用定时器,但最好有液位开关作实际判断,定时器只做超时备用。如果完全靠时间,瓶子大小有一点差异就会出问题。单序列结构能跑顺以后,再考虑分支并行。
3.3 单序列最容易犯的错:转换条件一直为真导致“连跳”
这是我在现场遇到最多的一个问题。假设Step30灌装完成后,完成信号M30被置位;但Step30还没活动之前,M30因为某种原因已经为真了,比如上一步复位时没有清除它。结果Step30一激活,转换条件立刻满足,这个步只存在一个扫描周期就被切出去,动作还没来得及执行,流程已经跳到下一步。这种“鬼步”很难查。
解决办法有两个方向。一个是转换条件里尽量用“前级动作的结果”,并且这个结果必须在进入本步前被复位;另一个是给完成信号加上升沿,让转换条件只在信号从0变1的时候成立一次。具体用哪种取决于平台支持,但思路是一致的:转换条件不能长期为真,否则SFC就会像连发枪一样停不住。
4. 选择分支与跳转:让流程学会“看情况办事”
单序列只能解决一条路走到黑的流程,实际设备经常要根据检测结果选择不同路径,这就轮到选择分支和跳转登场。
4.1 选择分支结构:多路选一路
选择分支的画法是:当前步下方先连一个转换,转换下面画一条水平单线,然后从这条单线分出几条纵向连线,每条线各自接一个转换条件和后续步。语义是:哪条分支的转换条件先满足,就进入哪条分支;其他分支不被激活。
要注意的是,选择分支各条件的“先满足”在PLC扫描里是按顺序扫描的。有些平台约定从左到右有优先级,有些按编号顺序,具体看手册。如果不做互斥,可能出现两个条件同时为真,走了平台默认的那条,但不是工艺想要的那条。所以后面我会强调互斥设计。
4.2 跳转与循环结构
跳转在SFC里本质是一条有向连线,连到非相邻的步。可以向后跳,形成循环,比如灌装机放行完成后再跳回推瓶步;也可以向前跳,跳过不需要的工序,比如检测到空瓶不需要灌装,直接跳到放行。
还有一种跳转用于异常处理:某步超时或报警,跳到一个专门的故障处理步,处理完再根据条件跳回正常流程。跳转是好东西,但要用得克制。我一般只在两条路径上使用:正常循环回跳、异常故障跳转。如果为了省步到处乱跳,程序会变得和意大利面一样乱,那就失去SFC的意义了。
4.3 转换条件的互斥与优先级设计
选择分支最忌讳的是两个分支的转换条件同时为真,尤其是在平台没明确优先级的时候,结果不可预期。正确的做法是让条件天然互斥。
举灌装机的例子,假设要选配方A或配方B,如果条件分别是“配方A选中”和“配方B选中”,而操作员把两个都勾上了,就会出问题。更好的写法是:
- 走配方A条件:
当前配方 = 配方A - 走配方B条件:
当前配方 = 配方B
用枚举变量比较,天然只有一个为真。如果是多个传感器选择,可以加入“且其他条件不满足”的互斥逻辑。别嫌麻烦,这一步能挡掉很多调试现场的灵异事件。
4.4 实例:给灌装机加一个“清洗模式”
回到灌装机,我在Step30灌装完成后加一个选择分支:
- 普通模式:灌装完成 且 工艺模式=普通 → 进入Step40封口。
- 清洗模式:灌装完成 且 工艺模式=清洗 → 进入Step35管路清洗步。
Step35执行清洗阀打开、清洗泵启动,等清洗完成信号到位后,跳回Step30再进行一次清水灌装,或者直接跳到封口步,看工艺需求。这个结构就体现出了选择分支的直观性:操作员切换模式后,SFC自动决定走哪条路,梯形图写这种逻辑需要大量辅助继电器,SFC只需要两条分支线。
5. 并行分支与会合:真正体现SFC威力的结构
如果SFC只能做选择和跳转,那它和普通状态机差别不大。并行分支才是它真正强的地方:一个条件满足,同时激活多个步,让几个工序并行推进。
5.1 并行分支:一条转换触发多个步
并行分支的画法和选择分支很像,但关键区别是横线数量。选择分支用“一条水平单线”,并行分支用“一条水平双横线”。双横线下方引出多条纵向连线,各自连到不同的步。
语义上,当前面的转换条件满足后,双横线后面的所有步都在同一个扫描周期内变成活动步。也就是说,这些步全部同时激活,各自执行自己的动作,互不等待。直到它们走到会合点为止。
5.2 为什么叫“并行”而不是“同时”
很多初学者会纠结:PLC是单核循环扫描的,怎么可能并行?这里说的“并行”是指这些步在同一个扫描周期里都处于活动状态,而不是多个CPU核心同时执行。
对于扫描周期动辄几毫秒到十几毫秒的PLC来说,输出刷新到气缸、电机这种执行机构上,效果就是“看起来同时启动”。如果工艺上有严格的时间同步要求,比如两个动作必须在1ms内同时触发,那不应该靠SFC的并行分支,而要选择带硬件中断或专用运动控制方案。理解这个边界,调试时才不会误判。
5.3 会合结构与等待陷阱
并行分支不能永远分开跑,最终要会合。会合的画法是:各分支的纵向线汇聚到一条水平双横线,双横线上方是每个分支的最后一步,双横线下方通常跟着一个转换条件,再进入公共后续步。
关键规则是:必须所有并行分支都到达各自的最后一步,并且会合转换条件为真,才能继续往下走。只要任何一个分支没到,整个流程就停在那里等待。这就是并行结构最大的坑:某一路传感器坏了,或者某一路动作慢了,整个设备会停在会合点前,而且看起来毫无原因。
我调试并行结构时,一定会给每个分支的最后一步加超时监视,或者做一个诊断变量,实时显示每个分支的到达状态。否则设备一卡,你都不知道是哪一路没到。
5.4 灌装机里的并行实例
灌装机在进入灌装前,可以先做两个动作预位:灌装头下降、瓶身举升。这两个动作互相独立,可以并行。
SFC结构可以这样安排:
- Step20夹紧完成后,转换条件“夹紧到位”满足。
- 进入并行分支,同时激活Step21灌装头下降 和 Step22瓶身举升。
- Step21完成后等待,Step22完成后等待。
- 会合条件“灌装头下降到位 且 瓶身举升到位”满足。
- 进入Step30灌装。
这样做的好处是节拍更短,如果串行执行,先降灌装头再举瓶,多花一个动作周期。并行分支的应用场景很多,但前提是各分支动作之间没有物理干涉。如果两个气缸在同一空间运动,可能撞车,那绝不能并行。
6. 动作块、活动步与SFC引擎:系统是怎么记住“到哪一步了”
理解SFC的执行机制,比背结构图形更重要。现场排查时,只有知道PLC内部怎么维护活动步,才能快速定位问题。
6.1 活动步列表机制
几乎所有PLC的SFC实现,在内部都维护一个“活动步集合”。程序启动时,初始步被放入这个集合;每执行一个转换,旧的步从集合中移除,新的步加入集合。
每个扫描周期,SFC引擎做的事是固定的:
- 根据活动步集合,执行所有活动步关联的动作。
- 扫描与活动步相连的转换条件。
- 对所有满足条件的转换,执行步切换,更新活动步集合。
设备不动,第一件事不是翻梯形图,而是看在线监控里当前活动步是哪一步。如果活动步卡在某处,就说明它对应的转换条件没有满足;如果活动步在预期之外,就说明转换条件或跳转逻辑出了问题。
6.2 动作修饰符的细节:N、P、S、R怎么选
动作修饰符的选型直接影响安全性和恢复逻辑。我再展开说一下:
- N动作最安全,步一结束就自动消失,不容易留尾巴。绝大多数普通输出我都用N。
- 但是如果步结束时动作立刻消失会导致执行机构突然断电,比如某个夹紧气缸靠输出保持,你用N动作就会在步切换瞬间松夹,这就不行了。这时候需要S/R,或者让N动作驱动一个自保持回路。
- P动作只在步激活的那一个周期有效,适合发一个启动脉冲。比如触发伺服使能、触发一次数据记录。
- S/R动作必须成对使用,而且要在合适的时机复位。否则跳转时会留下一个“鬼输出”,设备恢复后莫名其妙动作。
我的选择原则很简单:动作是否应该随着步结束而消失?应该就用N;不应该就考虑S/R;只是一瞬间的触发,用P。每个动作都要回答这个问题,回答清楚了就不会乱。
6.3 平台差异:CODESYS、西门子GRAPH、三菱STL
不同品牌对SFC的实现有差别,但核心结构相通。我列一个对比表,方便你在实际工程里对照:
| 平台 | 实现方式 | 特点 |
|---|---|---|
| CODESYS | SFC作为POU类型 | 步和转换可在属性中配置;动作可内嵌ST/LD/FBD;支持并行、选择、跳转 |
| 西门子S7-GRAPH | 专门的GRAPH功能块 | 转换条件用LAD/FBD编写;有互锁、监控功能;每个FB需要背景DB |
| 三菱STL | SFC块+STL指令 | 步编号用S;用OUT/MC类指令描述转换;写法接近梯形图风格 |
| 欧姆龙SFC | SFC程序段 | 步和转换类似IEC风格;动作支持多种语言 |
在线监控都支持高亮当前活动步,但详细功能差别不小。比如西门子GRAPH里能直接给每一步加监控时间和互锁条件,CODESYS则需要自己写超时逻辑。跨平台跳槽时,不要拿原来的操作习惯生搬硬套,先看手册里的执行顺序和默认优先级。
7. 现场调试SFC必须养成的几个习惯
结构学完了,最后聊聊现场调试。这部分更像经验总结,很多坑我都是真金白银换回来的。
7.1 先把“步名”当程序注释写清楚
我刚做项目时图省事,步名写成S0、S1、S2。结果现场一动设备,监控上S3高亮,我还要去翻动作表才知道S3是推瓶还是夹紧。后来全部改成Step10_推瓶、Step20_夹紧这种名字,调试效率提升非常明显。动作块的命名也一样,最好让人一看就知道是“灌装阀开”还是“清洗泵启”。
7.2 卡死排查的完整链路
设备停在某个位置不动,我的排查顺序固定如下:
- 打开在线监控,看当前活动步是哪一步。
- 看该步关联的动作有没有执行:输出点有没有亮,执行机构有没有动作。
- 看下一步的转换条件对应的输入信号是否满足。如果不满足,查传感器、查机械限位、查接线。
- 如果转换条件是定时器到,看定时器是不是在计时,定时器有没有一直被复位。
- 如果是并行结构,看所有分支是不是都到达会合前的步。
- 检查有没有被S/R保持的输出,误导了某个完成信号。
这个链路我打印出来贴在调试台旁边,几乎所有SFC卡死都能套进去。大多数问题不是SFC本身跑错,而是外围信号达不到转换条件。
7.3 超时监视必须加上
SFC本身不知道“某一步停留太久”,如果你不加超时,传感器坏了,程序可以永远停在那里。所以我在关键工艺步都会加超时监视。
举个例子,Step30灌装正常用液位开关判断,但万一液位开关坏了,灌装阀一直开着会溢瓶。我会加一个定时器,超过5秒还没完成就置报警并跳转到故障处理步。用结构化文本表达大概是:
IF Step30_灌装.ACTIVE THEN Timer30(IN := NOT Timer30.Q, PT := T#5S); IF Timer30.Q THEN Alarm_TimeOut := TRUE; 跳转到故障步 := TRUE; END_IF; END_IF不同平台写法不同,但思路一样:每个可能造成设备长时间等待的步,都要有个兜底时间。这个时间不能太短,要留出正常工艺的余量,否则会误报警。
7.4 急停与复位策略
急停信号必须硬接安全回路,直接切断危险输出,这是底线,不能指望SFC程序内部处理。但急停解除后,SFC怎么恢复生产,是需要仔细设计的。
我见过三种常见做法:
- 暂停当前SFC:急停期间所有步冻结,解除后从当前步继续。适合短时急停、设备本身安全。
- 跳转到安全复位步:急停时SFC跳到专门的安全复位步,把所有执行机构退回到安全位置,再手动确认后返回主流程。
- 全部复位回初始步:直接回原点,重新走正常流程。适合流程简单、复位成本低的设备。
我个人更推荐第二种,灵活性好,又能避免S/R动作残留。注意:如果你想用第三种“全部复位”,一定要确认所有S动作都被清除,否则会出现“步在初始步,输出还在动”的惊险画面。
7.5 定时器和边沿的“重入”坑
SFC步动作里用TON定时器时,最忌讳多个步共用一个定时器实例。步A把定时器启动后还没复位,流程切到步B时定时器继续用旧值,动作逻辑就乱了。我的习惯是每个步的定时器单独建实例,多建几个无关紧要,复用才是隐患。
另一个坑是转换条件用沿触发。有些平台支持转换条件“上升沿有效”,有些不支持。如果信号一直接通,没有沿处理就可能出现步连跳。稳妥的做法是用R_TRIG功能块把转换条件边沿化,或者把条件设计成“完成信号+一个短脉冲标志”。宁可多写一个沿,也不要赌那个扫描周期恰好抓到信号边沿。
说到底,顺序功能图的基本结构并不复杂:步、转换、连线、动作、分支,再加一个清晰的初始步,所有复杂设备都是这些元素的组合。难的是把这些结构放到真实设备上,处理好信号竞争、输出保持、并行等待这些细节。我始终觉得,用SFC最大的价值不是少写几行程序,而是让设备状态可以被讨论、被审查。调试现场两个人站在触摸屏前,指着当前活动步说“问题在这”,这种效率是梯形图很难给的。如果你正准备把某段顺序逻辑改成SFC,建议先从一个单序列的工位开始,跑顺了再加分支,再上并行,一次别贪多。SFC的结构本身足够可靠,真正需要小心的,永远是结构外面的输入信号和输出动作。