

干了12年PLC,整理了项目中最常用、重复率最高的SCL代码片段,每个都有注释!
为什么要标准化SCL代码?
深耕 PLC 调试 12 年,踩过无数现场大坑!见过太多项目同一条产线、同款设备,两位工程师写的程序两套逻辑,一人写的 FB 晦涩难懂,接手的人连动都不敢动,改一行全线停机。
很多人误以为标准化会束缚编程思路,恰恰相反:标准化不是捆住创造力,而是用极低的沟通成本,换来设备长期稳定、随手可维护。
整理了近 3 年 20 + 西门子落地项目实战沉淀的 6 套通用标准化模板,全部经过量产产线实测有基本的异常处理和注释。你直接复制到TIA Portal里改改I/O地址和设备参数就能用。
模版1:状态FB---
所有顺序控制的核心骨架
别再拿 M 点置位复位写顺序控制了!改用 CASE 状态机编程,代码可读性直接翻倍,现场调试至少省一半时间。给大家一套冲压设备完整工作循环标准框架:FB100_StateMachine 状态机 FB 源码,直接复制就能改 IO 投产。
// --- 隐式状态定义 --- //
IDLE=0 //待机WAIT_PART=1 //等待上料CLAMP=2 //工件夹紧PRESS=3 //冲压加工UNCLAMP=4 //松夹EJECT=5 //下料顶出DONE=6 //单循环完成ERROR=99 //故障报错CASE #State OF0: // IDLE 待机状态IF #Start AND NOT #Busy THEN #Timer(IN:=FALSE); #State := 1;END_IF;1: // WAIT_PART 工件检测#PartDetect := #PartSen;IF #PartSen THEN #State := 2;ELSIF #Timer.Q THEN #Alarm := '工件超时未到位'; #State := 99;ELSE #Timer(IN:=TRUE, PT:=T#5S);END_IF;2: // CLAMP 夹紧工件#ClampOut := TRUE;IF #ClampFB THEN #Timer(IN:=FALSE); #State := 3;ELSIF #Timer.Q THEN #Alarm := '夹紧超时'; #State := 99;ELSE #Timer(IN:=TRUE, PT:=T#2S);END_IF;3: // PRESS 冲压工序#PressOut := TRUE;#Timer(IN:=TRUE, PT:=#PressTime);IF #Timer.Q THEN #PressOut := FALSE; #State := 4;END_IF;4: // UNCLAMP 松开夹具#ClampOut := FALSE;IF NOT #ClampFB THEN #State := 5;END_IF;5: // EJECT 下料顶出#EjectOut := TRUE;IF #EjectFB OR #Timer.Q THEN #EjectOut := FALSE; IF #CycleCnt < #TargetCnt THEN #CycleCnt += 1; #State := 0; ELSE #State := 6; END_IF;ELSE #Timer(IN:=TRUE, PT:=T#2S);END_IF;6: // DONE 整循环结束#Busy := FALSE;#Done := TRUE;IF NOT #Start THEN #State := 0;END_IF;99: // ERROR 故障统一处理#Error := TRUE;#Busy := FALSE;IF #Reset THEN #State := 0; #Alarm := ''; #Error := FALSE;END_IF;END_CASE;
这套标准状态机三大核心规范:所有运行状态统一在 FB 头部注释定义,一目了然;每一个工步自带定时器超时保护,杜绝设备卡死;全部故障归集到 99 号 ERROR 状态,复位逻辑统一写一处。这套骨架我用了6年,从单工位到18站生产线全是一个结构。
模板2:配方管理FC---
多品种换型不再重新下载程序
产线换产品型号就改配方号,不用动一行PLC代码。核心思路是用ARRAY OF UDT存配方数据,用配方号索引加载。
FC200_RecipeLoader 关键逻辑
// 自定义配方UDT,统一所有产品工艺参数TYPE RecipeDataSTRUCT Speed : INT; // 运行速度百分比 0-100 PressTime : TIME; // 冲压保压时间 TempSet : INT; // 加热设定温度 ℃ TorqueLimit : REAL; // 扭矩保护上限 Nm EnableCheck : BOOL; // 视觉检测使能开关END_STRUCT;END_TYPE// 全局DB配方存储区,批量存放多型号参数RecipeDB: ARRAY[1..50] OF RecipeData// FC核心加载逻辑// 1. 先校验配方号合法性,防止越界报错IF #RecipeNo < 1 OR #RecipeNo > 50 THEN #Error := TRUE; #Diag := '配方号超出存储范围'; RETURN;END_IF;// 2. 读取对应编号整套配方数据#TempRecipe := "RecipeDB"[#RecipeNo];// 3. 参数安全校验,拦截非法数值避免撞机IF #TempRecipe.Speed < 0 OR #TempRecipe.Speed > 100 THEN #Error := TRUE; #Diag := '速度参数超出0~100合理区间'; RETURN;END_IF;// 4. 正常输出全部工艺参数#SpeedOut := #TempRecipe.Speed;#PressTimeOut := #TempRecipe.PressTime;#TempSetOut := #TempRecipe.TempSet;#TorqueLimitOut := #TempRecipe.TorqueLimit;#VisionEnable := #TempRecipe.EnableCheck;#Error := FALSE;#Loaded := TRUE;
这套标准化配方模板 3 大硬核优势:
1、换型零改程序:HMI 仅下发配方编号,整套速度、温度、扭矩参数自动一次性加载,调试工时大幅压缩;
2、内置双层安全校验:配方号边界校验 + 工艺参数区间校验,杜绝操作工误输入非法数值,规避设备撞机风险;
3、无限扩容无负担:现有 50 套配方不够用,只需修改数组上限为 ARRAY[1..200],整套加载逻辑完全不用改动。
模板3:故障自动重试FB---
减少不必要的停机
通信瞬断、气缸偶发不到位是产线最常见的误停机原因。与其让操作工按复位,不如让PLC自动重试一次。但重试必须有次数上限,不能无限循环。
FB300_Retry 核心逻辑
// 接口参数 // #DoAction : BOOL 触发动作 // #FeedbackOK : BOOL 反馈信号 // #Timeout : TIME 超时时间 // #MaxRetries : INT 最大重试次数 // #ActionCmd : BOOL 输出到执行器 // #RetryCount : INT 当前重试次数(STAT) // #Failed : BOOL 最终失败标志 // #InProgress : BOOL 正在执行 #InProgress := #DoAction AND NOT #Failed; IF #DoAction AND (#RetryCount = 0) THEN // 首次触发 #ActionCmd := TRUE; #RetryTimer(IN:=TRUE, PT:=#Timeout); #RetryCount := 1; END_IF; IF #InProgress THEN IF #FeedbackOK THEN // 成功 #ActionCmd := FALSE; #RetryTimer(IN:=FALSE); #RetryCount := 0; #InProgress := FALSE; ELSIF #RetryTimer.Q THEN // 超时,准备重试 #ActionCmd := FALSE; #RetryTimer(IN:=FALSE); WAIT(100); // 等待100ms再重试 #ActionCmd := TRUE; #RetryTimer(IN:=TRUE, PT:=#Timeout); #RetryCount += 1; END_IF; // 超过最大重试次数 IF #RetryCount > #MaxRetries THEN #ActionCmd := FALSE; #InProgress := FALSE; #Failed := TRUE; END_IF; END_IF; // 复位 IF NOT #DoAction THEN #RetryCount := 0; #Failed := FALSE; #ActionCmd := FALSE; #RetryTimer(IN:=FALSE); END_IF;
这个FB我主要用于气缸夹紧检测、RFID读取、视觉拍照触发三个场景。设置2-3次重试,每次超时后等待100ms再试。实践下来,约70%的偶发失败一次重试就成功了,产线综合效率OEE提升了3-5%。
模块4:数据日志FC---
产线数据直接记到DB
不用搭配上位机做数据存储!单靠 PLC 就能自主保存产量、报警、换型日志,一套环形缓冲区数组搞定,存满自动覆盖最早数据,零额外硬件成本。
FC400_LogWriter 环形缓冲区
// 日志单条记录结构体,统一所有事件格式TYPE LogEntrySTRUCT Timestamp : DT; // 事件精确时间戳 EventType : INT; // 事件类型:0=产量 1=报警 2=产品换型 Value : REAL; // 对应数值(产量数值/故障代码/配方号等) Desc : STRING[20]; // 事件简短文字描述END_STRUCT;END_TYPE// 日志存储DB全局变量定义LogDB.Data : ARRAY[0..999] OF LogEntry; // 1000条环形缓存池LogDB.HeadPtr : INT; // 写入指针LogDB.Count : INT; // 当前有效记录总数// FC400_LogWriter 日志写入核心逻辑#Idx := "LogDB".HeadPtr;// 写入当前事件全部信息"LogDB".Data[#Idx].Timestamp := LDT();"LogDB".Data[#Idx].EventType := #EventType;"LogDB".Data[#Idx].Value := #Value;"LogDB".Data[#Idx].Desc := #Desc;// 环形指针循环前进,触底归零实现循环覆盖"LogDB".HeadPtr += 1;IF "LogDB".HeadPtr >= 1000 THEN "LogDB".HeadPtr := 0;END_IF;// 记录总数上限锁死1000,不超缓冲区容量IF "LogDB".Count < 1000 THEN "LogDB".Count += 1;END_IF;
方案四大实用亮点
1、无需上位机:数据全部存在 PLC 自带 DB 块,S7-1200 就能独立存储,省去工控机、数据库成本;
2、自动循环覆盖:1000 条缓存存满后,新数据自动顶掉最早日志,不会出现存储溢出报错;
3、时间戳精准省心:直接调用 LDT () 获取毫秒级系统时间,不用手动拼接日期、时分秒;
4、对接 HMI 超简单:HMI 直接读取 LogDB 数组,可分页展示近百条日志,支持一键导出 CSV 归档。
硬件占用说明
1000 条完整日志缓冲区仅占用约 80KB 的 DB 存储空间,西门子 1200 系列 PLC 内存完全够用,完全不影响程序运行。
模块5:模块化阀组FB---
一个FB管所有气缸
一条产线几十个气缸,每个都要写伸出缩回、到位检测、超时报警。用UDT+FB封装,一个FB实列化N次就行。
FB500_Cylinder UDT+FB封装
// 气缸配置UDT —— 所有气缸参数统一标准化TYPE CylinderConfigSTRUCT ExtendTime : TIME; // 伸出超时时间 RetractTime : TIME; // 缩回超时时间 Name : STRING[16];// 气缸设备名称(报警文本直接带出)END_STRUCT;END_TYPE// FB500_Cylinder 标准气缸控制核心逻辑// 输入:Cfg(UDT参数)、Cmd控制指令// 反馈:SolA/SolB电磁阀输出、PosFB/PosBK到位检测、报警、故障CASE #Cmd OF0: // 指令0:停止复位 #SolA := FALSE; #SolB := FALSE; #Timer(IN:=FALSE);1: // 指令1:气缸伸出 #SolA := TRUE; #SolB := FALSE; #Timer(IN:=TRUE, PT:=#Cfg.ExtendTime); IF #PosFB THEN #Done := TRUE; #Cmd := 0; ELSIF #Timer.Q THEN #Alarm := '伸出超时:' + #Cfg.Name; #Error := TRUE; END_IF;2: // 指令2:气缸缩回 #SolA := FALSE; #SolB := TRUE; #Timer(IN:=TRUE, PT:=#Cfg.RetractTime); IF #PosBK THEN #Done := TRUE; #Cmd := 0; ELSIF #Timer.Q THEN #Alarm := '缩回超时:' + #Cfg.Name; #Error := TRUE; END_IF;END_CASE;
现场调用极其简单,所有气缸只需要一行代码实例化调用,无需重复写逻辑:
"Cyl_Clamp1"(Cfg:=Cfg_Clamp1, Cmd:=2); // 夹紧缸缩回"Cyl_Clamp2"(Cfg:=Cfg_Clamp2, Cmd:=1); // 夹紧缸伸出
每个实例独立运行,互不干扰。维护时只看实例名就知道控制哪个气缸。
模块6:看门狗定时器FC---
没人做但你早晚需要
设备空闲超3分钟自动回原点、通信断线5秒报警、操作员离开10分钟自动停机——这些需求每个项目都有,但每次写的都不一样。统一用一个FC搞定。
FC600_Watchdog 统一接口
// 接口: // #Trigger : BOOL 触发计时(设备运动信号) // #IdleTime : TIME 空闲警戒时间 // #AlarmOut : BOOL 超时报警 // #TimeLeft : TIME 剩余时间(给HMI显示倒计时) // #Reset : BOOL 手动复位 // #WarnFlag : BOOL 提前预警(剩余5秒时置位) IF #Trigger THEN // 设备在动,重置计时器 #Timer(IN:=FALSE); #Timer(IN:=TRUE, PT:=#IdleTime); #AlarmOut := FALSE; #WarnFlag := FALSE; END_IF; IF NOT #Trigger AND NOT #Reset THEN #Timer(IN:=TRUE, PT:=#IdleTime); #TimeLeft := #IdleTime - #Timer.ET; IF #Timer.ET >= #IdleTime - T#5S AND NOT #Timer.Q THEN #WarnFlag := TRUE; // 提前5秒预警 END_IF; IF #Timer.Q THEN #AlarmOut := TRUE; END_IF; END_IF; IF #Reset THEN #Timer(IN:=FALSE); #AlarmOut := FALSE; #WarnFlag := FALSE; END_IF;
HMI上绑定TimeLeft显示倒计时,操作员看到还剩5秒预警就知道要动一下了。和流水线急停联锁——空闲超时自动停输送带,既省电又安全。
写在最后:
先抄后改,逐步内化
分享的这 6 套 PLC 标准化模板,不是一成不变的标准答案,而是经过数百次现场量产验证的通用开发起点。
非常建议 PLC 新手和工程师同仁,先直接套用整套框架结构,快速跑通设备全流程。在程序稳定落地后,再根据自己的设备工艺、产线需求,针对性微调改造,适配专属项目场景。真正的代码标准化,从来不局限于固定逻辑,核心价值只有一个:极致的可维护性与可交接性。哪怕时隔半年、一年,换任意一位工程师接手项目,不用翻阅资料、不用反复询问,打开程序就能看懂架构、快速定位修改点位,极大降低沟通成本和运维风险。
你的项目里,有哪些自用多年、堪称封神的通用代码模板?欢迎评论区分享交流,互相学习、共同精进!
(文章来源:吉茄豪豪)
『本文版权归原作者所有,如有侵权,请联系删除。』

扫码添加免费领取资料 😊 免费资料领取
资料介绍:西门子+三菱案例例程

HISTORY / 往期推荐 别忘了点赞+在看哦!
夜雨聆风

