三菱PLC ST语言编程实战:从基础语法到CRC16校验实现
2026/7/29 7:04:01 网站建设 项目流程

1. 从梯形图到结构化文本:为什么我们需要ST语言?

如果你在三菱PLC的圈子里待过一段时间,从早期的FX系列玩到现在的iQ-R、iQ-F,手里用的编程软件从GX Developer换成了GX Works2或GX Works3,那你大概率经历过一个编程思维的转变。最开始,我们习惯用梯形图(LD),因为它直观,像电路图,继电器怎么吸合、线圈怎么得电,一目了然。处理简单的起保停、顺序控制,梯形图游刃有余。但当你开始接触更复杂的项目,比如需要处理大量数据运算、配方管理、复杂的流程控制,或者需要编写一个可复用的功能块时,你就会发现,用梯形图画起来会变得异常臃肿和低效。画几百个甚至上千个梯级,找一根线的去向都像在迷宫里寻宝。

这时候,ST语言(Structured Text,结构化文本)的价值就凸显出来了。它本质上是一种高级的、类似于Pascal或C的文本编程语言,被引入到IEC 61131-3标准中,成为了PLC编程的五大语言之一。在GX Works2中,ST语言不再是一个陌生的选项,而是处理复杂逻辑和算法的利器。我最初接触ST,是因为一个简单的需求:客户需要根据几个传感器的模拟量输入,实时计算一个产品的质量系数,这个计算公式涉及乘方、开方、三角函数和一堆条件判断。如果用梯形图实现,我需要调用一堆函数块,用中间变量倒来倒去,逻辑支离破碎。而用ST,我只需要十几行清晰明了的代码,像写数学公式一样直接表达出来,可读性和维护性瞬间提升了好几个档次。

所以,ST语言的核心价值,在于它填补了传统梯形图在复杂数据处理、算法实现和结构化编程方面的短板。它让PLC程序员能够以更接近计算机软件开发的思维来组织逻辑,特别适合数学运算、字符串处理、数组操作、循环和条件分支复杂的场景。对于从计算机或嵌入式背景转过来的工程师,ST语言更是几乎没有学习门槛,能让他们快速上手PLC逻辑开发。接下来,我们就深入GX Works2,看看如何开启你的ST编程之旅。

2. GX Works2中的ST编程环境搭建与核心语法要素

在GX Works2中,ST语言并非孤立存在,它可以和梯形图、顺序功能图(SFC)、功能块图(FBD)等语言混合编程,这是IEC 61131-3标准的强大之处。你可以在一个程序段(POU,程序组织单元)里使用ST,在另一个程序段里使用梯形图,它们通过全局变量或接口变量进行数据交互。

2.1 创建你的第一个ST程序段

打开GX Works2,创建一个新工程,选择对应的PLC型号(例如FX5U)。在工程导航树的“程序”下,右键点击“程序本体”,选择“新建数据”。在弹窗中,数据类型选择“程序语言”,然后你就能看到ST的选项了。给它起个名字,比如“MainLogic_ST”,点击确定,一个空白的ST编辑器窗口就会打开。

这个编辑器和我们常用的代码编辑器很像,有语法高亮、自动缩进和基本的错误提示。这里有一个非常重要的概念:在ST中,所有的语句都以分号;结束,这和C语言类似,是很多初学者容易忘记的地方。

2.2 ST语言的核心语法构件

ST语言的语法并不复杂,它由以下几个核心构件组成:

1. 变量与数据类型:ST是强类型语言,所有变量必须先声明后使用。在GX Works2的ST编辑器中,你通常会在程序开头或专门的“局部变量声明区”进行声明。三菱PLC的数据类型非常丰富:

  • 基本类型BOOL(位,如X0, M0),INT/DINT(16位/32位整数),REAL(浮点数),STRING(字符串)。
  • 衍生类型ARRAY(数组),如ARRAY[1..10] OF INT表示10个整数的数组。STRUCT(结构体),可以将不同类型的数据打包。
  • 直接地址:你也可以直接使用PLC的软元件地址,如D100,M100,但在结构化编程中,更推荐使用有意义的变量名,然后通过软件设置关联到实际地址。

声明示例:

VAR bStartButton AT %MX0: BOOL; // 将bStartButton变量关联到输入X0 iCounter: INT; rTemperature: REAL; arrData: ARRAY[1..5] OF DINT; END_VAR

2. 赋值语句:这是最常用的语句,使用:=运算符。

iCounter := 100; rTemperature := rTemperature + 1.5; bMotorRunning := TRUE; // BOOL类型赋值

3. 条件判断(IF...ELSIF...ELSE...END_IF):和大多数语言一样,用于分支逻辑。

IF bStartButton AND NOT bFault THEN bMotorRunning := TRUE; iCounter := 0; ELSIF bStopButton THEN bMotorRunning := FALSE; ELSE // 保持原状态 END_IF;

4. 循环语句:

  • FOR循环:用于已知次数的循环。
    FOR i := 1 TO 10 BY 1 DO arrData[i] := i * 2; END_FOR;
  • WHILE循环:用于条件满足时的循环。
    WHILE iCounter < 100 DO iCounter := iCounter + 1; // 注意:必须有能改变循环条件的语句,否则是死循环 END_WHILE;

5. 函数与功能块调用:ST可以方便地调用系统内置函数和用户自定义的功能块(FB)。

  • 函数:有返回值,如数学函数SIN(rAngle),SQRT(rValue),类型转换函数INT_TO_REAL(iValue)
    rResult := SIN(rAngle) * 100.0;
  • 功能块:具有内部状态,每次调用可能产生不同输出,如定时器TON、计数器CTU。在ST中调用功能块,需要先实例化(声明一个该FB的变量),然后通过实例名调用。
    VAR tonDelay: TON; // 声明一个接通延时定时器实例 END_VAR tonDelay(IN:=bStart, PT:=T#5S); // 调用,设置参数 bTimeOut := tonDelay.Q; // 获取输出

注意:GX Works2的ST语言是IEC 61131-3标准的一个子集,并有三菱自己的扩展。在编写复杂运算时,务必在软件帮助中查询特定函数或运算符的兼容性,避免使用标准中定义但GX Works2未实现的语法。

3. 实战:用ST语言实现一个复杂的CRC16校验功能

网络热词中提到了“三菱st语言crc16计算”,这确实是一个ST语言大显身手的典型场景。CRC(循环冗余校验)在通信中广泛应用,例如Modbus RTU协议。用梯形图实现CRC计算需要大量的位操作和循环,逻辑极其繁琐。而用ST语言,我们可以清晰地用算法逻辑来实现。

假设我们需要为一段数据(存储在数组arrTxData中)计算Modbus RTU标准的CRC16校验码(多项式0xA001)。下面我们一步步用ST语言实现。

3.1 算法理解与变量声明

首先,我们需要明白CRC16计算的核心是一个对数据每个字节进行位操作的循环过程。我们声明必要的变量:

VAR // 假设要计算CRC的数据包,共6个字节 arrTxData: ARRAY[1..6] OF BYTE := [16#01, 16#03, 16#00, 16#00, 16#00, 16#01]; uiCRCValue: WORD := 16#FFFF; // CRC初始值 iDataIndex: INT; // 数据索引 iBitIndex: INT; // 位索引 bBit: BOOL; // 临时位变量 END_VAR

3.2 ST语言实现CRC16计算逻辑

我们将计算过程封装在一个循环中。注意,ST语言中对于字节和位的操作非常直接。

// CRC16计算主循环 FOR iDataIndex := 1 TO 6 DO // 遍历数据数组的每个字节 uiCRCValue := uiCRCValue XOR WORD(arrTxData[iDataIndex]); // 字节与CRC低字节异或 FOR iBitIndex := 1 TO 8 DO // 对每个字节的8位进行处理 bBit := BOOL(uiCRCValue.0); // 取出CRC最低位 (LSB) uiCRCValue := SHR(uiCRCValue, 1); // CRC右移一位 IF bBit THEN uiCRCValue := uiCRCValue XOR 16#A001; // 如果移出位为1,则与多项式异或 END_IF; END_FOR; END_FOR; // 最终,uiCRCValue中存储的就是CRC16校验码 // 注意:Modbus RTU协议要求先发送低字节,再发送高字节 wCalculatedCRC := uiCRCValue; // 假设wCalculatedCRC是一个WORD型变量用于存储结果

代码解读与实操心得:

  1. 类型转换WORD(arrTxData[iDataIndex])是将BYTE类型显式转换为WORD类型以便进行异或运算。在ST中,注意数据类型匹配,避免隐式转换带来的意外。
  2. 位访问uiCRCValue.0是直接访问uiCRCValue这个WORD变量的第0位(最低位)。这是三菱ST语言的一个便捷特性。其他品牌的PLC可能需要通过位与(AND)和移位操作来实现。
  3. 移位函数SHR是逻辑右移函数。这里每次右移一位。
  4. 多项式16#A001是Modbus CRC16的多项式0xA001的十六进制表示。这是CRC16-Modbus的标准值。

踩坑提醒:我最初实现时犯过一个错误,在内层位循环结束后,没有正确地进行下一次字节的异或。务必确认你的数据遍历逻辑和位处理逻辑是严格嵌套的。另一个常见问题是字节顺序。计算出的CRC值在放入通信帧时,需要按照协议要求调整高低字节顺序(Modbus RTU是先低后高)。上述代码计算出的uiCRCValue,其低8位是uiCRCValue.1(或通过BYTE(uiCRCValue)获取),高8位是BYTE(SHR(uiCRCValue, 8))。如果顺序弄反,通信对方会校验失败。

3.3 将CRC功能封装为功能块(FB)

一个更工程化的做法是将上述逻辑封装成一个可重用的功能块(FB),比如FB_CRC16_Modbus。这样,在程序中任何需要计算CRC的地方,只需要实例化并调用这个FB即可,输入数据数组和长度,输出CRC值,代码整洁且易于维护。在GX Works2中创建ST语言的功能块非常方便,这体现了ST语言在模块化设计上的优势。

4. ST语言中的高级功能与混合编程技巧

掌握了基础语法和实战案例后,我们可以探索ST语言更强大的能力,以及如何与其他语言协同工作。

4.1 使用CASE语句处理多路分支

当有多个确定的值需要判断时,CASE语句比一连串的IF...ELSIF更清晰。

CASE iMode OF 1: rSetSpeed := 10.0; bPump1 := TRUE; 2: rSetSpeed := 20.0; bPump1 := TRUE; bPump2 := TRUE; 3: rSetSpeed := 50.0; // ...其他操作 ELSE // 默认情况,处理非法值 bFault := TRUE; END_CASE;

4.2 结构体(STRUCT)组织复杂数据

对于一台设备的多组参数,使用结构体管理比分散的变量要高效得多。

TYPE ST_Recipe : STRUCT rTemperature_SET: REAL; rPressure_SET: REAL; iTime_SET: INT; bEnable: BOOL; END_STRUCT END_TYPE VAR stCurrentRecipe: ST_Recipe; stBackupRecipe: ST_Recipe; END_VAR // 使用 stCurrentRecipe.rTemperature_SET := 150.5; IF stBackupRecipe.bEnable THEN stCurrentRecipe := stBackupRecipe; // 整体复制 END_IF;

4.3 ST与梯形图(LD)的混合编程与交互

这是GX Works2的精髓。你可以在一个FB或程序里,部分逻辑用ST写(比如复杂的计算),部分用梯形图画(比如简单的联锁和启停)。它们通过变量无缝交互。

场景:一个PID温度控制回路。PID算法本身用ST语言实现,因为它涉及浮点运算和条件判断。而设备的启动、停止、报警复位等安全联锁逻辑,用梯形图实现更直观。

操作

  1. 在同一个POU内,你可以插入多个“段”(Section)。为一段选择“结构化文本(ST)”,为另一段选择“梯形图(LD)”。
  2. 在ST段中,你声明并计算一个实型变量rPID_Output
  3. 在梯形图段中,你可以直接用一个线圈或比较指令来使用这个rPID_Output变量,控制一个模拟量输出模块或作为其他逻辑的输入。

交互的关键全局变量FB的输入输出变量。确保在ST中修改的变量,在梯形图中能够正确访问。在GX Works2的变量声明表中,可以清晰地管理这些变量的作用域(局部、全局)。

4.4 利用EXP等数学函数进行工程计算

热词中提到了“exp在st语言”,EXP是指数函数(e^x)。在ST中调用它非常简单,用于需要指数计算的模型,如某些化学反应速率、生长模型等。

VAR rGrowthRate: REAL; rTime: REAL := 2.0; rCoefficient: REAL := 0.5; END_VAR // 计算例如:生长速率 = e^(系数 * 时间) rGrowthRate := EXP(rCoefficient * rTime);

除了EXP,GX Works2的ST语言库通常还包含LN(自然对数)、LOG(常用对数)、SINCOSTAN等全套数学函数,使得实现复杂的控制算法成为可能。

5. 学习路径与工程实践中的注意事项

对于想系统学习三菱PLC ST语言的朋友,光靠官方手册可能有些枯燥。结合我的经验,给出以下建议:

5.1 学习资源与推荐路径

  1. 官方文档是基石:三菱电机官网提供的GX Works2操作手册、编程手册(特别是结构化文本篇)是必须精读的。里面详细规定了语法、函数库和软件操作。
  2. 实践项目驱动:不要只看不练。从一个小目标开始,比如把之前用梯形图写的一个繁琐的报警处理程序,用ST语言重写。体会两者在逻辑表达上的差异。
  3. 参考热词提及的书籍:虽然无法推荐具体书籍,但可以告诉你筛选方法。寻找书名中包含“IEC 61131-3”、“结构化文本(ST)”、“PLC高级编程”等关键词的书籍。优先选择那些有大量实际案例和代码片段,并且注明适用于多品牌PLC(如西门子SCL、倍福ST、三菱ST)的教材,因为ST语言的核心语法是相通的,这类书籍通常讲解得更透彻。
  4. 利用网络社区和案例:积极参与相关的技术论坛,查看别人分享的ST语言代码片段,特别是针对特定功能(如PID、通信协议解析、数据队列管理)的实现。理解别人的思路比复制代码更重要。

5.2 工程应用中的关键陷阱与调试技巧

陷阱1:扫描周期与执行顺序ST语言编写的程序段,其执行顺序由它在POU中的位置决定(通常从上到下)。你需要非常清楚PLC的扫描周期:输入采样 -> 程序执行 -> 输出刷新。在ST中,如果一个变量在同一扫描周期内被多次赋值,只有最后一次赋值生效。这与梯形图的“电流”流动概念不同,需要从“顺序执行”的软件思维去理解。

调试技巧:善用GX Works2的在线监视断点调试功能。在ST编辑器中,你可以设置断点,让PLC运行到指定行暂停,然后查看此时所有变量的值,这对于排查复杂的逻辑错误和算法错误至关重要。

陷阱2:变量初始化与保持性在ST中声明的局部变量,默认每个扫描周期都会重新初始化(除非你声明为RETAIN类型或使用VAR_GLOBAL RETAIN)。如果你需要一个在PLC断电再上电后能保持值的变量(比如累计产量),必须将其设置为保持型变量,并确认PLC的硬件支持(电池或非易失性存储器)。

VAR RETAIN iTotalCount: DINT := 0; // 保持型变量,初始值为0 END_VAR

陷阱3:数组越界与类型溢出这是ST编程中最常见的运行时错误之一。访问数组时,索引值必须在声明范围内。进行数学运算时,要注意数据类型的范围(如INT的范围是-32768~32767)。一个超出范围的赋值可能导致不可预知的行为。

防御性编程:在访问数组前,增加索引有效性检查。对于可能溢出的计算,考虑使用范围更大的数据类型(如用DINT代替INT),或者在计算前进行限幅判断。

陷阱4:ST与LD混编时的变量竞争当ST段和梯形图段同时读写同一个变量时,如果逻辑设计不当,可能会产生“竞争条件”。由于PLC是顺序扫描,后执行的段会覆盖先执行段的结果。因此,在混合编程时,最好明确数据的流向,避免双向读写同一个变量。通常,让ST段负责“计算”,将结果写入一组变量;让梯形图段负责“控制”,读取这组变量并产生最终输出。

从我个人的项目经验来看,ST语言的学习曲线初期可能比梯形图陡峭,但一旦掌握,它会极大地提升你处理复杂控制任务的效率和代码质量。它迫使你以更结构化的方式思考问题,这本身就是一种宝贵的技能提升。在GX Works2这个平台上,大胆地将ST语言用起来,从一个小功能块开始,你会发现PLC编程的世界原来可以如此不同。

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

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

立即咨询