1. 先搞清楚“适合”到底在问什么
“哪种语言最适合 PLC 编程”这个问题,在技术社区里几乎每个月都会被翻出来讨论一轮。但如果你仔细看那些争论,会发现大家其实在回答不同的问题。有人问的是“入门学哪个最快”,有人问的是“做复杂逻辑哪个最不容易翻车”,还有人问的是“招聘市场上哪个最值钱”。这三个问题的答案完全不一样。
我在产线上摸爬滚打这些年,接触过西门子、三菱、欧姆龙、汇川、AB 这几个主流品牌,也用过梯形图、ST、FBD、SCL、C 语言写 PLC 程序。我的结论是:不存在一种“最好”的语言,只存在“在特定场景下最不容易出问题”的语言。PLC 编程语言的选择,本质上是在可维护性、开发效率、执行确定性、团队技能栈这四个维度之间做权衡。
这篇文章我会把 PLC 编程语言的选型逻辑彻底拆开,从 IEC 61131-3 标准讲起,对比梯形图、结构化文本、功能块图、顺序功能图、指令表这五种标准语言,再补充 C 语言和厂商私有语言的实际使用场景。每个结论我都会给出具体的工程案例和参数依据,不是拍脑袋说的。如果你正在纠结学哪个、用哪个,或者团队要统一编程规范,这篇内容可以直接拿去参考。
2. IEC 61131-3 标准下的五种语言到底怎么选
2.1 梯形图:电气工程师的母语,但不是万能药
梯形图(LAD)是 PLC 编程里使用率最高的语言,没有之一。它的语法直接脱胎于继电器控制电路,常开触点、常闭触点、线圈、定时器、计数器这些元素,对于有电气背景的人来说几乎零学习成本。你给一个干了十年电气维护的老师傅看梯形图,他可能没写过 PLC 程序,但能看懂逻辑走向。
梯形图最大的优势在于调试直观。在博途或者 GX Works 里在线监控时,能流是否导通、哪个触点没闭合、哪个线圈没输出,一眼就能看出来。这在现场排查故障时非常关键。我遇到过很多次夜班抢修,设备突然停机,操作工说不清现象,这时候打开梯形图监控,顺着能流走一遍,五分钟定位问题。换成 ST 语言,你得逐行看变量值,效率差很多。
但梯形图有明确的适用边界。当逻辑涉及大量数据运算、数组操作、循环处理、字符串处理时,梯形图会变得极其臃肿。我见过一个项目用梯形图写配方管理,200 多个配方参数,每个参数用 MOV 指令搬来搬去,程序写了三千多步,后来加一个配方要改十几处地方,维护成本高得离谱。这种场景就应该用 ST 或者 SCL。
注意:梯形图适合布尔逻辑、互锁、顺序控制、简单定时计数。涉及浮点运算、指针、结构体、循环迭代时,强行用梯形图是在给自己挖坑。
2.2 结构化文本:复杂算法的唯一正解
结构化文本(ST)的语法接近 Pascal 和 C,支持 IF-THEN-ELSIF、CASE、FOR、WHILE、数组、结构体、自定义函数块。在西门子体系里叫 SCL,在 CODESYS 体系里就叫 ST,在三菱体系里叫 ST,在欧姆龙体系里叫 ST。名字不同,核心语法大同小异。
ST 的真正价值在处理批量数据和复杂算法时体现得淋漓尽致。举个例子,一台 PLC 通过 Modbus 控制 32 台变频器,每台变频器要读写频率给定、实际频率、电流、电压、故障码、运行状态等十几个寄存器。如果用梯形图,32 台乘以十几个参数,就是几百个 MOVE 和比较指令,程序长度爆炸。用 ST 写一个 FOR 循环,配合数组和结构体,几十行代码就能搞定,而且增加一台变频器只需要改一个常量。
// 西门子 SCL 示例:批量读取变频器数据 FOR i := 1 TO 32 DO // 调用 Modbus 读取功能块 ModbusRead( SlaveAddr := i, StartAddr := 16#2000, Quantity := 10, DataPtr := ADR(VFD_Data[i]) ); // 故障判断 IF VFD_Data[i].FaultCode <> 0 THEN VFD_Fault[i] := TRUE; TotalFaultCount := TotalFaultCount + 1; END_IF; END_FOR;这段代码如果用梯形图实现,至少需要几百个网络段。而且 ST 的文本特性意味着它可以做版本管理、代码审查、差异对比,这在团队协作中非常重要。梯形图的差异对比几乎没法看,ST 的 Git diff 清清楚楚。
ST 的缺点也很明显:在线调试不如梯形图直观。你只能看变量值,看不到“能流”。而且 ST 对编程基础有一定要求,没写过代码的电气工程师上手会吃力。我的建议是,团队里至少要有一个人精通 ST,负责写复杂功能块,其他人用梯形图调用这些功能块。
2.3 功能块图与顺序功能图:特定场景的利器
功能块图(FBD)在过程控制领域用得比较多,比如 PID 回路、模拟量处理、信号滤波。它的图形化表达方式对于连续量控制很友好,一个 PID 功能块拖出来,输入输出引脚连上线就行。但在离散制造领域,FBD 的使用率远低于梯形图。
顺序功能图(SFC)是描述状态机的最佳工具。设备有几个状态、每个状态的转移条件是什么、转移时要执行什么动作,SFC 用图形化的方式表达得非常清晰。我做过一个装配线项目,设备有手动、自动、回零、急停、故障复位五个主状态,每个主状态下又有若干子状态。用 SFC 画出来,逻辑一目了然,客户看了都说清楚。如果用梯形图写状态机,需要大量 SET/RESET 指令和比较指令,容易出错。
但 SFC 在实际项目中的使用率并不高,主要原因是很多 PLC 品牌的 SFC 编辑器体验一般,而且 SFC 和梯形图、ST 的混合编程需要额外注意执行顺序。我的经验是,主状态机用 SFC 或者 ST 的 CASE 语句写,子逻辑用梯形图或 ST 写,这样兼顾清晰度和灵活性。
2.4 指令表:正在被淘汰的语言
指令表(IL)是类似汇编的文本语言,西门子的 STL 就是典型代表。在老一代 S7-300/400 项目中,STL 用得很多,因为那时候 SCL 还不成熟,STL 能实现一些梯形图做不到的功能,比如间接寻址、循环、指针操作。
但现在新项目基本不用 IL 了。博途里 STL 已经不再更新,西门子官方推荐用 SCL 替代。三菱的 IL 也在逐步退出。IL 的可读性太差,维护成本太高,除非你在维护老设备,否则没必要学。
2.5 五种语言的选型对照表
| 语言 | 适用场景 | 优势 | 劣势 | 学习曲线 |
|---|---|---|---|---|
| 梯形图 LAD | 布尔逻辑、互锁、顺序控制 | 直观、调试方便、电气人员易上手 | 复杂逻辑臃肿、数据处理弱 | 低 |
| 结构化文本 ST | 算法、数据处理、批量操作 | 简洁、可复用、易版本管理 | 调试不直观、需要编程基础 | 中 |
| 功能块图 FBD | 过程控制、模拟量处理 | 图形化、信号流清晰 | 离散逻辑表达弱 | 低 |
| 顺序功能图 SFC | 状态机、流程控制 | 状态转移清晰 | 编辑器体验参差、混合编程需注意 | 中 |
| 指令表 IL | 老设备维护、特殊寻址 | 灵活、底层控制 | 可读性差、逐步淘汰 | 高 |
3. 不同品牌生态下的语言选择差异
3.1 西门子体系:SCL 越来越重要
西门子的编程生态里,梯形图和 SCL 是主力。博途平台下,SCL 的编辑器体验已经做得相当好,语法高亮、自动补全、在线监控都支持。S7-1200/1500 的项目里,我建议逻辑控制用梯形图,数据处理和复杂算法用 SCL,两者混合编程。
西门子还有一个 STL(指令表),但在 S7-1500 里已经不建议使用了。博途里查看 PLC 资源使用情况时,你会发现 SCL 编译后的代码效率并不比 STL 差多少,但可读性天差地别。
有个细节值得注意:西门子的 SCL 在 OB 块、FB 块、FC 块里的写法略有差异。OB 块里可以直接写程序,FB 块需要定义静态变量,FC 块没有记忆功能。这些概念新手容易混淆,我后面会专门讲。
3.2 三菱体系:梯形图为主,ST 逐步普及
三菱的 GX Works2 和 GX Works3 里,梯形图是绝对主力。三菱的梯形图编辑器做得非常成熟,指令输入快捷,监控方便。FX 系列和 Q 系列的老项目几乎全是梯形图。
但三菱也在推 ST 语言,GX Works3 里的 ST 编辑器已经可用了。我做过一个 FX5U 的项目,涉及伺服电机控制,用梯形图写定位指令没问题,但涉及多轴插补和参数计算时,ST 明显更顺手。三菱的 ST 语法和西门子 SCL 有差异,比如三菱用:=赋值,条件判断用IF...THEN...END_IF,但循环语句的写法不太一样,跨品牌迁移时需要查手册。
3.3 欧姆龙与汇川:CODESYS 生态的崛起
欧姆龙的 NJ/NX 系列和汇川的 AM/AC 系列都基于 CODESYS 平台。CODESYS 是一个独立的 PLC 编程环境,支持 IEC 61131-3 全部五种语言,而且对 ST 的支持非常好。在 CODESYS 里,你可以用 ST 写功能块,用梯形图调用,用 SFC 写流程,混合编程非常灵活。
汇川 PLC 的 CODESYS 版本里,ST 语言的使用率很高,尤其是涉及运动控制的项目。汇川的伺服驱动和 PLC 配合时,用 ST 写凸轮同步、电子齿轮、插补算法,比梯形图方便太多。而且 CODESYS 支持面向对象编程,可以定义接口、继承、多态,这在复杂项目里能大幅提升代码复用率。
3.4 AB 体系:梯形图传统深厚,ST 逐步引入
罗克韦尔的 Studio 5000 里,梯形图是绝对主流。AB 的梯形图编辑器功能强大,AOI(Add-On Instruction)机制让代码复用变得容易。但 AB 的 ST 语言支持相对较晚,语法也和西门子、CODESYS 有差异。
AB 项目里,我建议主逻辑用梯形图,复杂计算用 ST。AB 的 ST 在数组处理和循环方面表现不错,但调试体验不如梯形图。另外 AB 的 AOP 安装和固件版本匹配是个坑,后面会讲。
4. 从实际项目看语言选型的决策逻辑
4.1 案例一:一台 PLC 控制 32 台变频器的 Modbus 通讯
这个场景在热词里出现了,我正好做过类似的项目。一台西门子 S7-1500 通过 Modbus RTU 控制 32 台变频器,读写频率给定、实际频率、电流、电压、故障码。
如果用梯形图写,每台变频器的读写需要独立的 Modbus 功能块调用,32 台就是 32 个调用,加上数据处理和故障判断,程序长度至少几千步。而且增加或减少变频器时,要手动复制粘贴大量代码,容易出错。
我用 SCL 写了一个循环,配合数组和结构体,核心代码不到 100 行。变频器数量定义为一个常量,改一个数字就能适配不同规模的项目。故障判断用 FOR 循环遍历,统计故障数量,触发报警。
// 定义变频器数据结构 TYPE VFD_Type STRUCT FreqSet : REAL; // 频率给定 FreqActual : REAL; // 实际频率 Current : REAL; // 电流 Voltage : REAL; // 电压 FaultCode : INT; // 故障码 Status : WORD; // 状态字 END_STRUCT; END_TYPE // 定义数组 VFD_Data : ARRAY[1..32] OF VFD_Type;这个项目的经验是:通讯类、批量类、数据类逻辑,ST 是唯一合理的选择。梯形图在这种场景下不是不能用,而是用了之后维护成本会高到让你怀疑人生。
4.2 案例二:星-角降压启动的梯形图程序
星-角降压启动是电气控制的经典电路,用 PLC 实现时,梯形图是最自然的选择。主回路有主接触器、星接触器、角接触器,控制逻辑是启动时星接触器吸合,延时后星接触器断开、角接触器吸合。
这个逻辑用梯形图写,大概十几个网络段,包括启动按钮、停止按钮、定时器、互锁、输出线圈。逻辑清晰,调试方便,任何电气人员都能看懂。
// 星-角降压启动梯形图逻辑(伪代码表示) Network 1: 启动保持 I0.0 (启动) ---| |--- I0.1 (停止) ---|/|--- Q0.0 (主接触器) ---( ) Q0.0 ---| |---| Network 2: 星接触器 Q0.0 ---| |--- T37 ---|/|--- Q0.1 (星接触器) ---( ) Network 3: 角接触器 Q0.0 ---| |--- T37 ---| |--- Q0.2 (角接触器) ---( ) Network 4: 定时器 Q0.0 ---| |--- TON T37, 5s这个场景如果用 ST 写,反而没有梯形图直观。电气人员看梯形图能直接对应到电路图,看 ST 代码需要脑补逻辑关系。所以简单逻辑控制,梯形图仍然是首选。
4.3 案例三:PLC 状态机写法
设备状态机是另一个典型场景。一台设备有手动、自动、回零、急停、故障复位五个状态,每个状态下有不同的动作和转移条件。
用梯形图写状态机,通常用 SET/RESET 指令或者 MOV 指令给状态变量赋值,然后每个状态下用比较指令判断。程序能跑,但状态多了之后,梯形图会变得很乱,转移条件分散在各个网络段里,容易漏掉互锁。
用 ST 的 CASE 语句写状态机,结构非常清晰:
CASE MachineState OF 0: // 空闲状态 IF StartButton THEN MachineState := 10; // 转到回零 END_IF; 10: // 回零状态 IF HomeSensor THEN MachineState := 20; // 转到自动 ELSIF Fault THEN MachineState := 90; // 转到故障 END_IF; 20: // 自动运行 IF StopButton THEN MachineState := 0; ELSIF Fault THEN MachineState := 90; END_IF; 90: // 故障处理 IF ResetButton AND NOT Fault THEN MachineState := 0; END_IF; END_CASE;这种写法状态转移一目了然,增加状态只需要加一个 CASE 分支。我现在的项目里,主状态机一律用 ST 的 CASE 写,子逻辑用梯形图或 ST 写,这是我认为最合理的混合编程方式。
4.4 案例四:伺服电机控制与运动算法
伺服控制涉及位置计算、速度计算、加减速曲线、电子齿轮比、凸轮同步等。这些计算用梯形图写会非常痛苦,因为涉及大量浮点运算和三角函数。
三菱 JE-A 伺服带 5:1 减速器,带 5M20 同步轮,线速度 0.8 米每秒,需要计算电机转速。这个计算过程涉及减速比、同步轮周长、线速度到转速的转换,用 ST 写几行代码就搞定:
// 计算电机转速 SyncWheelCircumference := 3.14159 * 20 / 1000; // 同步轮周长,单位米 LineSpeed := 0.8; // 线速度,单位米每秒 ReducerRatio := 5.0; // 减速比 MotorSpeed := (LineSpeed / SyncWheelCircumference) * 60 * ReducerRatio; // 电机转速,单位 RPM如果用梯形图,需要多个 MUL、DIV、MOV 指令,而且浮点数处理在梯形图里很别扭。所以运动控制类项目,ST 是更好的选择。
5. 新手入门与团队协作的语言策略
5.1 新手应该先学哪个
如果你刚接触 PLC 编程,我的建议是先学梯形图,再学 ST。原因很简单:梯形图是 PLC 编程的基础语言,绝大多数现有项目都是梯形图写的,你去看别人的程序、维护老设备、和电气人员沟通,都需要梯形图。而且梯形图的逻辑思维是 PLC 编程的基础,理解了能流、互锁、定时器、计数器这些概念,再学 ST 会容易很多。
学完梯形图之后,尽快学 ST。ST 是处理复杂逻辑的必备技能,而且随着 CODESYS 生态的普及,ST 的使用率会越来越高。我见过很多只懂梯形图的工程师,遇到数据处理和算法就卡住了,只能到处找现成的功能块,效率很低。
5.2 团队编程规范怎么定
团队协作时,语言选择需要统一规范。我的建议是:
- 主逻辑用梯形图:互锁、顺序控制、简单定时计数,梯形图最直观,调试最方便。
- 复杂算法用 ST:数据处理、通讯、运动控制、状态机,ST 更简洁。
- 功能块封装用 ST:把常用功能封装成 FB 块,用 ST 写内部逻辑,用梯形图调用。
- 统一命名规范:变量命名、功能块命名、注释格式要统一,否则混合编程会乱。
有个经验:不要强制所有人用同一种语言。有人擅长梯形图,有人擅长 ST,强制统一反而降低效率。关键是接口要清晰,功能块要封装好,调用方式要统一。
5.3 跨品牌迁移的语言注意事项
不同品牌的 ST 语法有差异,跨品牌迁移时需要注意:
| 品牌 | ST 语法特点 | 注意事项 |
|---|---|---|
| 西门子 SCL | 接近 Pascal,用:=赋值 | FB 块需要定义静态变量,FC 块无记忆 |
| 三菱 ST | 接近 C,条件判断用THEN | 循环语句写法与西门子不同 |
| CODESYS ST | 标准 IEC 语法,支持 OOP | 功能块调用方式与西门子不同 |
| AB ST | 接近 C,数组下标从 0 开始 | 与西门子数组下标从 1 开始不同 |
跨品牌迁移时,不要直接复制粘贴代码,要逐行检查语法差异。尤其是数组下标、数据类型、功能块调用方式,这些地方最容易出问题。
6. 常见问题与排查技巧实录
6.1 梯形图转 ST 时最容易踩的坑
坑一:数组下标不一致。西门子数组下标从 1 开始,AB 和 CODESYS 从 0 开始。迁移时如果不注意,会数组越界或者数据错位。
坑二:数据类型不匹配。梯形图里 INT 和 DINT 经常混用,ST 里类型检查更严格,INT 和 DINT 直接运算会报错,需要显式转换。
坑三:定时器用法不同。梯形图的 TON 定时器在 ST 里需要实例化调用,不能像梯形图那样直接拖出来用。
坑四:边沿检测。梯形图的上升沿触点|P|在 ST 里需要用 R_TRIG 功能块或者手动写边沿检测逻辑。
6.2 ST 程序调试不直观怎么办
ST 调试确实不如梯形图直观,但有几个技巧可以弥补:
- 善用在线监控和变量表:把关键变量加到监控表里,实时看值变化。
- 分段调试:把复杂逻辑拆成多个功能块,逐个调试。
- 加调试变量:在关键位置加临时变量,记录中间结果。
- 用断点和单步:博途和 CODESYS 都支持断点和单步调试,虽然 PLC 的断点会影响扫描周期,但调试阶段可以用。
6.3 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| ST 编译报错“类型不匹配” | INT 和 DINT 混用 | 检查变量声明和运算表达式 | 用 INT_TO_DINT 等转换函数 |
| 数组越界 | 下标从 0 开始 vs 从 1 开始 | 检查数组声明和循环边界 | 统一下标起始值 |
| 定时器不工作 | 未实例化或未调用 | 检查定时器 FB 是否被调用 | 在循环中调用定时器 FB |
| 边沿检测失效 | 未使用 R_TRIG/F_TRIG | 检查边沿检测逻辑 | 用 R_TRIG 功能块或手动实现 |
| 程序扫描周期变长 | ST 循环次数过多 | 查看 PLC 资源使用情况 | 优化循环,减少不必要的计算 |
| Modbus 通讯超时 | 从站地址冲突或波特率不匹配 | 检查从站地址和通讯参数 | 统一波特率,检查接线 |
6.4 独家避坑技巧
技巧一:ST 里慎用 WHILE 循环。WHILE 循环如果条件控制不当,会导致扫描周期无限长,PLC 看门狗超时。能用 FOR 循环就用 FOR,循环次数可控。
技巧二:浮点数比较不要用等号。浮点数运算有精度误差,IF RealVar = 0.0 THEN可能永远不成立。要用ABS(RealVar) < 0.001这种方式。
技巧三:ST 功能块要加超时保护。通讯类功能块如果对端无响应,可能一直等待。加一个超时计数器,超时后强制退出,避免程序卡死。
技巧四:梯形图和 ST 混合编程时注意执行顺序。OB 块里先调用哪个功能块、后调用哪个,会影响逻辑结果。我的习惯是先读输入,再算逻辑,最后写输出,这样扫描周期内数据一致。
技巧五:变量命名加前缀。输入用I_,输出用Q_,中间变量用M_,定时器用T_,功能块实例用FB_。这样在 ST 代码里一眼就能看出变量类型,减少错误。
7. 关于 AI 生成 PLC 代码的一些观察
最近热词里有“AI PLC 代码生成”,我也试过一些工具。目前的水平是:简单逻辑能生成,复杂逻辑需要大量人工修正。比如让 AI 生成一个星-角降压启动的梯形图,它能给出基本框架,但互锁逻辑和定时器参数需要人工调整。让 AI 生成 Modbus 通讯的 ST 代码,它能给出结构,但寄存器地址、数据类型、字节序这些细节需要根据实际设备手册修改。
我的建议是:把 AI 当成代码助手,不要当成代码作者。用它生成框架和模板,然后人工填充细节和验证逻辑。PLC 程序涉及设备安全,未经充分测试的代码绝对不能上产线。
8. 回到最初的问题
哪种语言最适合 PLC 编程?我的答案是:梯形图是基础,ST 是进阶,两者混合使用是当前最优解。简单逻辑用梯形图,复杂逻辑用 ST,状态机用 ST 的 CASE 或 SFC,运动控制用 ST,通讯和数据处理用 ST。不要迷信某一种语言,也不要排斥某一种语言,根据场景选择最合适的工具。
如果你刚开始学,先把梯形图练熟,再学 ST。如果你已经在做项目,试着把重复性的、数据密集型的逻辑用 ST 重写,你会发现代码量大幅减少,维护效率明显提升。如果你在带团队,制定好混合编程规范,让每个人用自己擅长的语言,但接口要统一。
我在实际项目中的体会是,语言只是工具,真正决定程序质量的是逻辑清晰度、可维护性和容错能力。一个用梯形图写的结构清晰的程序,比一个用 ST 写的乱七八糟的程序好得多。反过来也一样。所以与其纠结学哪个语言,不如先把编程思维和工程规范练好。