☰
PLC标准化编程八步法:S7-1200/1500程序架构与S88状态模型实战
2026/10/15 10:17:16 网站建设 项目流程

简介:这份PDF资料聚焦PLC标准化编程方法与设计,面向工业自动化领域的电气工程师、PLC程序员及希望提升程序架构能力的技术人员,尤其适合使用西门子S7-1200与S7-1500系列、希望摆脱面向过程编程、建立可复制程序体系的从业者。资源为单个PDF文件,压缩包约1.98MB,内容围绕程序结构规划、变量命名规则、设备对象分解与状态模型构建展开,并给出中央空调系统的八步法实例。资料系统梳理了OB、FB、FC、DB、UDT等程序元素,详解驼峰与帕斯卡命名规则,以及MCM、MIM、MIS、MID等现场设备命名模式,同时引入S88标准分解设备对象,帮助读者理解控制模块、单元、设备与模块的状态模型。已有345人学习,适合需要提升程序严谨性、可维护性与团队协作效率的工程师参考,也可作为标准化编程培训与项目复盘的辅助材料。

1. 从“每次从零开始”到八步法:PLC标准化编程到底在解决什么

干了几年自动化的人多半有过这种体验:接手一个老项目,打开程序一看,变量名是M100.0、DB1.DBD0,功能块里塞满了置位复位,注释比代码还少。想改一个逻辑,得先把整个程序通读一遍,生怕碰坏了哪根“暗线”。更崩溃的是,下一个项目来了,明明设备差不多,却因为程序架构不一样,又得从头搭一遍。这不是技术能力问题,是编程方法的问题。

这套《PLC标准化编程方法与设计》资料,核心就是冲着这个痛点去的。它面向 S7-1200 和 S7-1500 平台,把标准化拆成三个层面:程序架构怎么分层、变量怎么命名、设备对象怎么分解。资料里给了一套“八步法”,从程序架构设计一路走到 IO 点映射,中间穿插 S88 标准的状态模型和驼峰/帕斯卡命名规则。适合两类人:一是手里有项目但程序越写越乱、想建立自己模板库的工程师;二是团队里需要统一编程规范、让几个人写的代码能互相看懂的负责人。它不教你怎么写梯形图,它教的是怎么让写出来的程序别人能接得住。

2. 程序架构分层:OB、FB、FC 到底该怎么摆

2.1 为什么“一个 OB1 走天下”迟早翻车

很多从 200 SMART 或者更早平台转过来的工程师,习惯把所有逻辑塞进 OB1,最多拆几个 FC 出来。项目小的时候没问题,几十个 IO 点,逻辑一目了然。但到了 S7-1500 这种面向中大型项目的平台,IO 点动辄几百上千,还涉及多个设备单元、多种控制模式,再这么写就是给自己挖坑。

翻车的典型场景是这样的:调试阶段发现某个电机的手动逻辑有问题,你打开 OB1 往下翻,翻了三十个网络还没找到那段逻辑,因为中间夹杂着报警、联锁、模拟量处理。好不容易找到了,改完下载,结果影响了另一个设备的自动流程——因为两个设备的逻辑共用了一个临时变量。这种“玄学故障”追起来极其痛苦。

标准化的程序架构要解决的就是这个问题。资料里给出的架构分层思路是:OB 负责调度,FB 负责设备级逻辑封装,FC 负责纯计算或数据处理,DB 负责数据存储,UDT 负责数据结构定义。每一层职责明确,互不越界。

具体到 S7-1200/1500 的 TIA Portal 环境里,常见的做法是:

  • OB1(主循环):只做块调用,不写具体逻辑。里面按顺序调用初始化子程序、IO 映射子程序、设备单元子程序、报警子程序、数据交换子程序。
  • FB(功能块):每个设备类型一个 FB,比如电机 FB、变频器 FB、阀门 FB。FB 内部封装这个设备的所有逻辑——手动、自动、故障处理、状态输出。通过背景 DB 实现多实例调用。
  • FC(功能):用于不需要记忆状态的纯逻辑,比如模拟量标定、单位换算、数据打包。
  • DB(数据块):分为设备背景 DB 和全局数据 DB。设备背景 DB 由 FB 调用时自动生成,全局 DB 存放配方、参数、报警文本等。

这样分层的直接好处是:改电机逻辑只动电机 FB,不影响其他设备;新增一台电机只增加一个背景 DB 和一次调用,不用复制粘贴代码。

2.2 八步法里的架构设计:先画图纸再砌墙

资料里提到的“八步法”,第一步就是程序架构设计。这一步不是上来就打开 TIA Portal 建项目,而是先在纸上或者文档里把子程序划分清楚。八步法的完整流程是:

  1. 程序架构设计
  2. 创建 PLC 变量表
  3. 创建 PLC 数据类型(UDT)
  4. 创建电机功能块的程序模型
  5. 创建 S88 状态功能块的程序模型
  6. 调用电机功能块的程序
  7. 编写设备单元的控制程序
  8. 编写 IO 点映射程序

注意这个顺序:先定义数据结构和接口,再写功能块内部逻辑,最后做 IO 映射。很多人的习惯是反过来的——先写逻辑,用到什么变量再定义什么变量,最后 IO 映射也是散落在各个网络里。这种“边写边想”的方式在项目后期会带来大量的返工。

第一步架构设计要确定的内容包括:这个项目有几个设备单元、每个单元包含哪些设备模块、每个设备模块需要哪些功能块、功能块之间的调用关系是什么。以资料里提到的中央空调系统为例,设备单元可能包括冷冻机组、冷却塔、水泵、阀门等,每个设备模块对应一个 FB,单元层再写一个 FB 或者 FC 来协调这些设备模块的动作顺序。

提示:架构设计阶段不要纠结具体的变量地址,先把块的结构和调用关系定下来。地址分配是第六步以后的事。

2.3 用 UDT 把设备接口标准化

UDT(用户自定义数据类型)是标准化编程里被低估的工具。它的作用是把一组相关的变量打包成一个数据类型,在 DB 里声明的时候直接使用这个类型,而不是一个一个变量去定义。

以电机为例,一个电机通常需要这些变量:启动命令、停止命令、运行反馈、故障反馈、手动/自动模式、运行状态、故障代码。如果不做 UDT,每个电机都要在 DB 里定义这七八个变量,十个电机就是七八十个变量,命名还容易乱。用 UDT 之后,定义一个UDT_Motor,里面包含这些成员,然后在 DB 里声明Motor1 : UDT_Motor,结构清晰,复制也方便。

// UDT_Motor 定义示例(在 TIA Portal 的 PLC 数据类型中创建) TYPE "UDT_Motor" VERSION : 0.1 STRUCT CmdRun : Bool; // 启动命令 CmdStop : Bool; // 停止命令 CmdReset : Bool; // 故障复位 ModeAuto : Bool; // 自动模式 FbRunning : Bool; // 运行反馈 FbFault : Bool; // 故障反馈 FbRemote : Bool; // 远程/就地反馈 State : Int; // 状态字(对应 S88 状态模型) FaultCode : Word; // 故障代码 END_STRUCT; END_TYPE

这段 SCL 代码定义了一个电机的基础数据结构。CmdRun、CmdStop、CmdReset是来自 HMI 或者上位机的命令位;ModeAuto区分手动和自动;FbRunning、FbFault、FbRemote是来自现场设备的反馈信号;State是一个整数,用来表示电机当前处于 S88 状态模型中的哪个状态;FaultCode用于传递具体的故障信息。

参数说明:State用 Int 而不是 Bool,是因为 S88 状态模型有多个状态(空闲、启动中、运行、停止中、故障等),用整数可以一次性表达。FaultCode用 Word 可以编码 16 种故障,如果不够可以改成 DWord 或者 Array of Word。

定义好 UDT 之后,在全局 DB 里这样使用:

// 在全局 DB 中声明电机实例 DATA_BLOCK "DB_Motors" { S7_Optimized_Access := 'TRUE' } VERSION : 0.1 VAR Motor1 : "UDT_Motor"; // 1号电机 Motor2 : "UDT_Motor"; // 2号电机 Motor3 : "UDT_Motor"; // 3号电机 END_VAR

这样每个电机的数据结构完全一致,FB 的接口可以直接用UDT_Motor作为 InOut 参数,调用的时候把对应的 DB 变量传进去就行。新增电机只需要在 DB 里加一行声明,不用改 FB 的代码。

3. 变量命名与 S88 状态模型:让程序自己说话

3.1 驼峰与帕斯卡:什么时候用哪个

命名规则这件事,看起来是小事,实际上是标准化里最容易产生分歧的地方。每个人都有自己的习惯,有人喜欢下划线,有人喜欢全小写,有人喜欢加前缀。项目里几个人各写各的,最后合到一起就是灾难。

资料里明确了两套命名规则,分别对应不同的对象:

驼峰命名(camelCase):第一个字母小写,后续单词首字母大写,不用分隔符。适用于变量、PLC 变量、PLC 数据类型和结构的成员。比如motorAuto、valveOpenFb、tempSetpoint。

帕斯卡命名(PascalCase):第一个字母大写,每个单词首字母都大写。适用于程序块、数据块、工艺对象、库、PLC 变量表、监控表、PLC 数据类型本身的名称。比如MotorControl、ValveControl、DB_Motors、UDT_Motor。

为什么这么分?因为在实际编程中,变量和块名出现在不同的上下文里。变量出现在代码逻辑中,驼峰命名让变量和关键字、指令区分得更明显;块名出现在调用和引用中,帕斯卡命名让块名更醒目。TIA Portal 本身对大小写不敏感,但人眼敏感,统一的命名规则能减少阅读时的认知负担。

注意:帕斯卡命名里允许少量下划线,比如DB_Motors这种,目的是区分数据块的类型前缀。但不要滥用,Motor_Control_FB_01这种就过度了。

3.2 现场设备命名:Equipment Type + Extension + Meaning

除了编程层面的命名规则,资料里还给出了现场设备的命名模式:设备类型 + 扩展 + 含义。比如:

命名含义说明
MCMMotor Command Run电机运行命令
MIMMotor Indication Running电机运行反馈
MISMotor Isolator Switch电机隔离开关反馈
MIDMotor Indication Defect电机热保护故障反馈

这种命名方式的好处是,看到变量名就知道它属于哪个设备、是什么类型的信号。MCM 一定是电机的命令,MIM 一定是电机的反馈,不会混淆。在 IO 点映射的时候,这种命名方式也能直接对应到硬件地址。

实际项目中,我一般会在这个基础上再加一层单元前缀。比如中央空调项目里,冷冻水泵的启动命令可以命名为CHWP01_MCM,其中CHWP01是设备编号,MCM是信号类型。这样在变量表里排序的时候,同一设备的信号自然聚在一起。

3.3 S88 状态模型:设备行为的形式化描述

S88 标准是批量控制领域的设备模型标准,但它的思路可以推广到一般的 PLC 编程。核心思想是把设备分解为层次结构:过程单元(Process Cell)→ 设备单元(Unit)→ 设备模块(Equipment Module)→ 控制模块(Control Module)。

对应到 PLC 程序里:

  • 控制模块:最小的控制单位,比如一个阀门、一个电机。对应一个 FB。
  • 设备模块:完成一个具体功能的设备组合,比如一个加料模块(包含阀门和泵)。对应一个 FB,内部调用多个控制模块 FB。
  • 设备单元:完成一个完整工艺步骤的单元,比如混合单元。对应一个 FB 或者 FC,协调多个设备模块。
  • 过程单元:整个生产线或工艺段。

状态模型是 S88 的另一个核心。每个设备模块都有自己的状态机,常见状态包括:空闲(Idle)、启动中(Starting)、运行(Running)、停止中(Stopping)、故障(Fault)、复位中(Resetting)。状态之间的转换由命令和条件触发。

资料里提到的“自动化编程的经典总结”——“每个控制单元,在每种控制模式下、每种状态下、在什么条件下、做什么”——其实就是状态模型的通俗表达。把这四个问题回答清楚,设备的逻辑就完整了。

在 SCL 里实现状态模型,通常用 CASE 语句:

// 电机 FB 内部的状态机片段 CASE #state OF 0: // 空闲状态 IF #CmdRun AND #ModeAuto THEN #state := 10; // 转到启动中 END_IF; 10: // 启动中 #outputRun := TRUE; IF #FbRunning THEN #state := 20; // 转到运行 ELSIF #startTimeout.Q THEN #state := 100; // 转到故障 #FaultCode := 16#0001; // 启动超时 END_IF; 20: // 运行状态 IF #CmdStop OR NOT #ModeAuto THEN #state := 30; // 转到停止中 END_IF; IF #FbFault THEN #state := 100; #FaultCode := 16#0002; // 运行故障 END_IF; 30: // 停止中 #outputRun := FALSE; IF NOT #FbRunning THEN #state := 0; // 回到空闲 END_IF; 100: // 故障状态 #outputRun := FALSE; IF #CmdReset AND NOT #FbFault THEN #state := 0; // 复位后回到空闲 END_IF; END_CASE;

这段代码展示了一个简化的电机状态机。#state是状态变量,#CmdRun、#CmdStop、#CmdReset是命令输入,#FbRunning、#FbFault是反馈输入,#outputRun是输出到现场的控制信号。

参数说明:状态编码用 0、10、20、30、100 而不是 0、1、2、3、4,是为了留出扩展空间。比如以后要加“暂停”状态,可以用 25;要加“维护”状态,可以用 90。#startTimeout是一个定时器实例,用于检测启动超时。#FaultCode用十六进制赋值,方便在 HMI 上显示和排查。

这种状态机的写法比一堆置位复位指令要清晰得多。调试的时候,直接监控#state的值就知道设备在哪个状态,不用去猜逻辑走到哪了。

4. 避坑与排查:标准化落地时最容易翻车的五个地方

4.1 现象:FB 改了接口,所有调用处报错

原因:FB 的 InOut 参数用了具体的 DB 变量类型,而不是 UDT。比如电机 FB 的接口定义成Motor1 : Struct,里面手动展开了所有变量。后来要加一个变量,改了 FB 接口,所有调用这个 FB 的地方都得重新连线。

解决:FB 的接口参数一律用 UDT 类型。Motor : "UDT_Motor"作为 InOut 参数,调用的时候传"DB_Motors".Motor1。这样 FB 内部改逻辑不影响接口,接口改成员也只改 UDT 定义,所有调用处自动更新。

4.2 现象:IO 映射程序散落在各个 FB 里,查一个点要翻半天

原因:写 FB 的时候顺手把 IO 地址写进去了,比如#outputRun := %Q0.0。多个 FB 都这么干,最后 IO 地址和逻辑混在一起,想查某个输出点被谁写了,得一个一个 FB 搜。

解决:八步法的最后一步是“编写 IO 点映射程序”,这一步单独做一个 FC 或者 FB,专门负责把过程映像区的 IO 地址映射到 DB 变量。FB 内部只操作 DB 变量,不直接碰 IO 地址。这样查 IO 点只需要看映射程序,逻辑和硬件解耦。

// IO 映射 FC 示例 // 输入映射 "DB_Motors".Motor1.FbRunning := "I_Motor1_Running"; // %I0.0 "DB_Motors".Motor1.FbFault := "I_Motor1_Fault"; // %I0.1 // 输出映射 "Q_Motor1_Run" := "DB_Motors".Motor1.CmdRun; // %Q0.0

4.3 现象:多个设备共用定时器或计数器,互相干扰

原因:在 FB 里用了全局定时器(比如 T1、T2),多个背景 DB 调用同一个 FB 时,定时器是共享的。电机 1 的启动超时定时器还没走完,电机 2 的启动又把它复位了。

解决:FB 里用 IEC 定时器(TON、TOF、TP)的实例,声明在 FB 的 Static 变量里。每个背景 DB 有自己独立的定时器实例,互不干扰。不要在 FB 里用T1、T2这种全局定时器。

4.4 现象:HMI 上显示的状态和实际设备状态对不上

原因:状态变量在多个地方被写入。FB 里写了一次,HMI 脚本里又写了一次,或者另一个 FB 也操作了同一个 DB 变量。最后谁写的生效取决于扫描顺序,结果就是“玄学”。

解决:一个变量只有一个写入者。状态变量由设备 FB 独占写入,HMI 只读不写。HMI 的命令通过独立的命令变量传递给 FB,FB 内部根据命令和反馈更新状态。在变量表里标注每个变量的读写权限,团队里约定好。

4.5 现象:程序下载后设备动作异常,但监控程序看不出问题

原因:优化块访问和非优化块访问混用。S7-1200/1500 默认使用优化块访问,变量的绝对地址不固定。如果某个 DB 被设成了非优化访问,而 FB 里按优化访问的方式引用,或者反过来,就会出现数据错位。

解决:新项目统一使用优化块访问,不要混用。如果必须用非优化访问(比如某些老 HMI 驱动不支持优化访问),在 DB 属性里明确设置,并且在变量表里用绝对地址引用。下载前用 TIA Portal 的“编译”功能检查一致性,不要只做“全部下载”。

5. 从八步法到可复用模板:一个中央空调项目的落地记录

八步法听起来步骤多,但真正跑一遍之后,后面再做类似项目就是改改参数的事。我拿一个中央空调项目走过完整流程,这里把关键节点和可复用的部分拆出来。

第一步架构设计,我确定了六个子程序:IO 映射、初始化、功能块调用、单元控制、报警、数据交换。这个划分方式在大多数过程控制项目里都适用,可以直接作为模板。

第二步创建 PLC 变量表,我按设备编号分组,每组内按信号类型排序。变量表的结构是:设备编号 + 信号类型 + 描述。比如CHWP01_MCM、CHWP01_MIM、CHWP01_MID。这样在变量表里筛选CHWP01就能看到这台泵的所有信号。

第三步创建 UDT,我定义了UDT_Motor、UDT_Valve、UDT_Pump三个基础类型。UDT_Pump继承不了UDT_Motor,但可以把UDT_Motor作为成员嵌进去,再加泵特有的变量比如流量反馈、压差反馈。

第四步创建电机 FB,接口用UDT_Motor作为 InOut,内部实现状态机。这个 FB 写完之后,所有电机都用它,包括冷冻水泵、冷却水泵、冷却塔风机。

第五步创建 S88 状态 FB,这个 FB 不直接控制设备,而是管理设备模块之间的状态协调。比如冷冻机组启动前要先启动冷冻水泵,水泵运行反馈来了之后才允许启动机组。这个逻辑放在状态 FB 里,用状态机的思路写,比用定时器和标志位堆出来的逻辑可靠得多。

第六步调用电机 FB,在功能块调用子程序里,为每台电机生成一个背景 DB,把DB_Motors里对应的变量传进去。这一步在 TIA Portal 里是拖拽操作,但要注意调用顺序——先调用设备 FB,再调用单元控制 FB。

第七步编写单元控制程序,这是项目特有的逻辑,每个项目不一样。但结构是一样的:用状态机描述单元的工作流程,每个状态里调用设备 FB 的命令接口。

第八步 IO 映射,把所有输入输出集中在一个 FC 里。这个 FC 只做赋值,不做逻辑判断。调试的时候如果发现某个点不对,直接在这个 FC 里查。

跑完这八步之后,我把整个项目另存为模板。下一个项目如果是类似的空调系统,直接改 IO 映射和单元控制程序,设备 FB 和 UDT 基本不用动。如果是不同的设备类型,比如换成传送带,只需要新写一个传送带 FB 和对应的 UDT,架构和命名规则照搬。

从那以后我每次开新项目,都强制先走一遍八步法的前四步——架构、变量表、UDT、设备 FB——再开始写具体逻辑。这四步花的时间,在调试阶段能省回来好几倍。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询