1. 为什么“注释代码”这件小事值得单独拿出来讲
在STEP 7(TIA Portal)里写程序,注释代码这件事看起来简单到不值一提——不就是加两个斜杠或者括号吗?但真正在项目里摸爬滚打过几年的人都知道,注释代码的方式、时机和粒度,直接决定了你后期调试和交接的效率。尤其是在LAD、FBD、STL和SCL这四种语言混用的项目里,注释的写法完全不一样,稍不注意就会踩坑。
我自己带过好几个用TIA Portal V16做产线改造的项目,PLC程序里既有梯形图写的安全逻辑,也有SCL写的配方管理和数据处理,还有从老设备移植过来的STL代码。每次调试阶段需要临时屏蔽某段逻辑时,团队里总有人因为注释方式不对导致编译报错,或者更隐蔽的——注释掉了但实际还在执行。这些问题在手册里往往一笔带过,但在实际工程中会浪费大量时间。
这篇文章就是把这些年积累的注释技巧和踩过的坑整理出来。不管你是刚接触TIA Portal的新手,还是用了多年STEP 7但一直只用一种语言的老手,下面这些内容都能帮你少走弯路。我会按语言类型逐一拆解注释方法,重点讲清楚每种语言注释的底层逻辑、操作步骤、以及什么场景下该用哪种注释方式。特别是SCL语言,它的注释规则和LAD/FBD/STL差异最大,也是热搜里“sht30的scl接哪里”这类问题频繁出现的地方——很多人把传感器SCL引脚和编程语言SCL搞混,后面我也会顺带把这个概念理清楚。
2. 四种编程语言的注释机制到底差在哪
2.1 LAD和FBD:图形化语言的注释逻辑
LAD(梯形图)和FBD(功能块图)在TIA Portal里属于图形化编程语言,它们的注释方式和文本语言有本质区别。图形化语言里没有“注释掉一行代码”这种概念,因为程序本身是网络(Network)组成的图形结构。
在LAD/FBD中注释代码,实际上有两种理解:
第一种是给网络添加注释文本。这个操作很简单,选中网络后右键选择“属性”,或者直接在网络标题栏双击,就能输入注释内容。这种注释不会影响程序执行,纯粹是给读程序的人看的。我习惯在每个功能块的开头网络写清楚这段逻辑的用途、作者和修改日期,后期维护时能省很多沟通成本。
第二种是临时禁用某个网络或某段逻辑。在LAD/FBD里,你不能像文本语言那样把一段代码“括起来”注释掉。常见的做法是:
- 选中需要禁用的网络,右键选择“禁用网络”(Disable Network)。这个操作会让该网络在编译时被跳过,但不会删除。需要恢复时再右键“启用网络”即可。
- 如果只想禁用网络中的某一个分支或触点,可以选中该元素后按Delete删除,但这样会丢失逻辑。更稳妥的方式是在该分支上串联一个永远为假的条件,比如一个未使用的M位且保持为0,这样逻辑上等效于屏蔽。
- 对于FBD中的某个输入引脚,可以临时断开连接线,但同样建议先记录原始连接关系。
注意:禁用网络这个操作在编译时会生成警告信息,但不会导致编译失败。如果你在团队协作中看到大量被禁用的网络,建议在提交前统一清理,否则后期很容易忘记哪些是故意禁用的、哪些是遗留的调试代码。
2.2 STL:语句表语言的注释方式
STL(语句表)是TIA Portal中比较接近底层汇编的文本语言,它的注释规则和SCL有相似之处,但细节不同。
在STL中,单行注释使用双斜杠//。比如:
// 这是一个单行注释 A "StartButton" // 读取启动按钮状态 JC START // 如果为1则跳转到START标签STL不支持块注释(即不能像C语言那样用/* */括起多行)。如果你需要注释掉一整段STL代码,只能逐行加//,或者使用编辑器提供的“注释选中行”功能。在TIA Portal的STL编辑器里,选中多行后按Ctrl + K可以批量添加注释符号,按Ctrl + Shift + K可以取消注释。这个快捷键在LAD/FBD的文本注释框里也能用,但在图形网络中无效。
STL里还有一个特殊之处:跳转标签和注释的关系。如果你注释掉了一行包含跳转目标的代码,但跳转指令还在,编译会报错。比如:
JC OVER // 跳转到OVER标签 // OVER: // 如果这行被注释掉,上面的跳转就会找不到目标这种情况下,要么把跳转指令也注释掉,要么保留标签行不注释。我个人的习惯是,在STL里做临时屏蔽时,优先注释掉跳转指令本身,而不是目标标签。
2.3 SCL:结构化控制语言的注释规则
SCL(Structured Control Language)是TIA Portal中类似Pascal的高级语言,它的注释规则和C语言系比较接近,支持两种注释方式:
- 单行注释:使用双斜杠
//,从该符号到行尾的内容都会被忽略。 - 块注释:使用
(*和*)括起来,可以跨多行。注意,SCL不支持/* */这种C风格注释,只能用(* *)。
举个例子:
// 这是单行注释 (* 这是块注释 可以跨多行 适合临时屏蔽大段代码 *) IF "StartButton" THEN "Motor" := TRUE; // 启动电机 (* "Alarm" := TRUE; // 这行被块注释屏蔽了 "Indicator" := FALSE; *) END_IF;这里有个容易踩的坑:块注释不能嵌套。也就是说,你不能在一个(* *)里面再写一个(* *),编译器会认为第一个*)就结束了注释,后面的内容会被当作代码解析,大概率报错。如果你需要注释掉一段已经包含块注释的代码,只能改用逐行//的方式。
另外,SCL的块注释在TIA Portal的某些版本里对中文支持不太好。如果你在(* *)里写了中文,偶尔会出现编译警告或乱码。我的经验是,块注释里尽量用英文或拼音,单行注释//对中文的支持更稳定。
2.4 四种语言注释方式对比速查
| 语言 | 单行注释 | 块注释 | 批量注释快捷键 | 临时禁用网络/逻辑 |
|---|---|---|---|---|
| LAD | 不支持 | 不支持 | 无 | 右键禁用网络 |
| FBD | 不支持 | 不支持 | 无 | 右键禁用网络 |
| STL | // | 不支持 | Ctrl + K | 逐行注释或跳转屏蔽 |
| SCL | // | (* *) | Ctrl + K | 块注释或逐行注释 |
这张表建议截图保存,在项目现场调试时能快速查阅。特别是LAD/FBD和文本语言混用的时候,很多人会习惯性地在LAD里找//,结果发现根本没有输入注释的地方。
3. 在TIA Portal里实际操作:从选中到注释的完整流程
3.1 LAD/FBD中禁用网络的具体步骤
假设你有一段LAD程序,其中某个网络负责控制一台电机的启停,现在调试阶段需要临时屏蔽这段逻辑。操作步骤如下:
- 在项目树中打开对应的FC或FB块,切换到LAD视图。
- 在程序编辑区找到目标网络,单击网络左侧的灰色边框区域,选中整个网络。选中后网络边框会变成蓝色。
- 右键点击选中的网络,在弹出的上下文菜单中选择“禁用网络”。如果你用的是TIA Portal V16,这个选项可能在“编译”子菜单下,不同版本位置略有差异。
- 禁用后,网络标题栏会出现一个灰色的“已禁用”标记,网络内的逻辑颜色会变暗。
- 需要恢复时,重复上述步骤,选择“启用网络”。
这里有个细节:禁用网络后,该网络内的所有逻辑都不会被编译和执行,但网络内的变量声明和符号引用仍然会被检查。也就是说,如果你禁用了一个网络,但该网络里用到了一个已经被删除的变量,编译时仍然会报错。这一点和文本语言的注释不同——注释掉的内容完全不会被编译器看到。
实操心得:在多人协作的项目里,我建议在禁用网络的同时,在网络标题里写上禁用原因和预计恢复时间。比如“2024-03-15 临时屏蔽,等待传感器到货后恢复”。这样即使你休假了,同事也能判断这个网络该不该动。
3.2 STL中批量注释与取消注释
STL编辑器的批量注释功能比LAD/FBD方便得多。具体操作:
- 用鼠标拖选需要注释的多行代码,或者按住Shift键点击首尾行。
- 按
Ctrl + K,选中的每一行开头都会加上//。 - 如果要取消注释,选中已注释的行,按
Ctrl + Shift + K,编辑器会自动移除行首的//。
这个快捷键在TIA Portal的SCL编辑器里同样适用。但要注意,如果选中的行里已经包含单行注释,再按Ctrl + K会变成双重注释,取消时需要按两次Ctrl + Shift + K才能完全恢复。我见过有同事在调试时反复注释和取消,最后代码里残留了一堆////,虽然不影响编译,但看起来非常乱。
对于STL里的跳转标签,批量注释时要特别小心。如果标签行被注释掉了,但跳转指令还在,编译会直接报错“未找到跳转目标”。正确的做法是:
- 先注释跳转指令行。
- 再注释标签行。
- 恢复时顺序相反。
3.3 SCL中块注释的边界处理
SCL的块注释(* *)在处理大段代码时非常方便,但边界情况需要留意。比如下面这段代码:
(* 这是一个块注释 IF "Condition" THEN "Output" := TRUE; END_IF; *)如果这段注释出现在一个IF语句内部,而注释的结束位置恰好在一个语句中间,就可能出问题。比如:
IF "Start" THEN (* "Motor" := TRUE; "Valve" := TRUE; *) "Pump" := TRUE; END_IF;这段代码是合法的,因为块注释完整地包含了两个赋值语句。但如果你这样写:
IF "Start" THEN (* "Motor" := TRUE; *) "Valve" := TRUE; (* "Pump" := TRUE; END_IF;这里第二个块注释没有闭合,编译器会把后面的END_IF也当作注释内容,导致IF语句缺少结束标记,编译报错。所以使用块注释时,一定要确保(*和*)成对出现,并且不要跨越语句结构的边界。
我的个人习惯是:临时屏蔽少量代码用//逐行注释,屏蔽大段代码用(* *),但块注释的范围不会跨越IF...END_IF、FOR...END_FOR这类结构语句的边界。如果确实需要屏蔽整个结构,我会把结构语句也一起注释掉。
3.4 跨语言项目的注释策略
在实际项目里,一个FC块可能同时包含LAD网络和SCL程序段,或者一个FB块里既有STL写的底层逻辑,又有SCL写的数据处理。这种混合编程的情况下,注释策略需要统一规划。
我的做法是:
- 在块头部用SCL或STL的注释方式写一个总说明,包括块的功能、作者、版本、修改记录。这个说明放在块的最前面,不参与逻辑执行。
- 每个网络或程序段开头写简短注释,说明该段逻辑的用途。LAD/FBD用网络标题,STL/SCL用
//。 - 临时调试注释统一用
//,避免块注释嵌套问题。调试完成后及时清理,不要留在最终版本里。 - 对于需要长期保留但暂时不用的代码,用块注释
(* *)包起来,并在注释开头写明“备用逻辑,勿删”。
这样做的原因是,混合编程时最容易出现的问题是:LAD网络被禁用了,但SCL里对应的变量还在被引用;或者STL里的跳转标签被注释了,但SCL里还有跳转到该标签的指令。统一的注释策略能减少这类跨语言引用错误。
4. 那些手册里不会写的注释避坑指南
4.1 注释掉代码不等于代码不执行
这是新手最容易犯的错误。在LAD/FBD里,禁用网络确实会让该网络不执行。但在STL和SCL里,注释掉代码只是让编译器忽略这些文本,如果被注释的代码里有对变量的赋值,这些赋值不会发生。听起来是废话,但实际项目中经常出现这样的情况:
// "Motor" := TRUE; // 这行被注释了 "Motor" := FALSE; // 这行还在执行结果就是电机永远不会启动。调试时如果发现某个输出不对,第一件事就是检查是不是有注释掉的赋值语句影响了逻辑。
更隐蔽的是注释掉条件判断但保留了执行语句:
// IF "Enable" THEN "Output" := TRUE; // END_IF;这种情况下,"Output" := TRUE;会无条件执行,因为IF和END_IF都被注释掉了。如果"Enable"本来是用来做安全联锁的,这就可能导致严重的安全问题。
注意:在安全相关程序(如F-CPU中的安全逻辑)里,绝对不要用注释的方式来临时屏蔽逻辑。安全程序有专门的禁用和旁路机制,必须按照安全手册操作。
4.2 SCL块注释里的中文和特殊字符
前面提到过,SCL的块注释(* *)对中文的支持在某些TIA Portal版本里不够稳定。我实测过V15、V16、V17三个版本,V16对中文块注释的兼容性最差,偶尔会出现编译后注释内容乱码,或者编译器把中文当成非法字符报错。
规避方法很简单:块注释里只写英文、数字和常用符号,中文注释一律用//单行注释。如果确实需要在块注释里写中文,可以在中文前后加空格,或者把块注释拆成多个单行注释。
另外,SCL里不支持/* */这种C风格注释。如果你从其他PLC平台(比如某些日系PLC)移植代码过来,习惯性地写了/* */,TIA Portal会直接报语法错误。这一点在移植项目时要特别注意。
4.3 注释与编译优化的关系
TIA Portal在编译时会自动优化代码,删除永远不会执行的逻辑。但注释掉的内容不参与编译,所以不会被优化。这意味着:
- 如果你注释掉了一大段代码,编译后的块大小不会减小,因为注释内容仍然保存在源文件中。
- 如果你删除了代码而不是注释,编译后的块会变小,下载到PLC的存储占用也会减少。
- 对于存储空间紧张的PLC(比如一些紧凑型CPU),长期保留大量注释代码可能导致块无法下载。
我的建议是:调试阶段的临时注释可以保留,但在项目最终交付前,把确认不再使用的注释代码彻底删除,只保留必要的说明性注释。这样既能减小块体积,也能避免后期维护时被大段注释干扰。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| SCL编译报错“未预期的符号” | 块注释未闭合或嵌套 | 检查(* *)是否成对,避免嵌套 |
| STL跳转报错“未找到标签” | 标签行被注释但跳转指令还在 | 同时注释跳转指令和标签行 |
| LAD网络禁用后编译警告 | 禁用的网络内有未使用的变量 | 清理变量或恢复网络 |
| SCL中文注释乱码 | 块注释中的中文编码问题 | 改用//单行注释 |
| 注释后逻辑仍执行 | 注释范围不完整 | 检查IF/END_IF等结构是否被完整注释 |
| 批量注释后代码混乱 | 重复注释导致//// | 用Ctrl+Shift+K逐次取消 |
这张表里的问题,我在不同项目里至少都遇到过一次。特别是“注释后逻辑仍执行”这一条,曾经在一个输送线控制项目里导致电机意外启动,排查了半天才发现是IF条件被注释了但赋值语句还在。
5. 从注释技巧延伸到SCL的常见概念混淆
5.1 编程语言SCL和硬件引脚SCL是两回事
热搜词里出现“sht30的scl接哪里”,这个问题和编程语言SCL完全无关。SHT30是一款温湿度传感器,它的SCL引脚是I2C通信的时钟线(Serial Clock Line),需要接到PLC的I2C主站时钟引脚上。而编程语言SCL是Structured Control Language的缩写,两者只是字母巧合。
在TIA Portal项目里,如果你用SCL语言写I2C通信程序来读取SHT30的数据,那么SCL语言里会涉及对SCL引脚的读写操作。但“SCL接哪里”问的是硬件接线,答案取决于你用的PLC型号和I2C模块。比如用Arduino或树莓派接SHT30,SCL通常接GPIO的I2C时钟脚;用西门子PLC接SHT30,可能需要通过CM模块或第三方网关。
这个混淆在初学者里非常普遍。我见过有人在论坛上问“SCL语言怎么接SHT30”,结果被误导去改程序里的SCL代码,实际上他需要的是硬件接线图。所以这里特别澄清一下:编程语言的SCL和硬件引脚的SCL没有任何关系,遇到问题时要先分清是软件还是硬件层面。
5.2 TIA Portal V16在注释功能上的改进
TIA Portal V16相比V15在编辑器体验上有不少改进,注释相关的包括:
- SCL编辑器的语法高亮更准确,注释内容会显示为绿色,不容易和代码混淆。
- 批量注释快捷键
Ctrl + K在更多编辑器里生效,包括STL和SCL。 - 禁用网络的右键菜单更直观,V16里直接显示“禁用/启用网络”,V15里藏在子菜单里。
- 块注释的自动补全功能:输入
(*后编辑器会自动提示补全*),减少未闭合错误。
如果你还在用V15或更早版本,升级到V16后这些细节能明显提升编码效率。但要注意,V16的项目文件不能直接在V15里打开,团队协作时要统一版本。
5.3 FBD注释的特殊性
FBD(功能块图)和LAD虽然都是图形化语言,但FBD的注释更麻烦一些。因为FBD的连线是逻辑流,禁用某个功能块或断开某条连线都会影响整个网络的逻辑。
在FBD里临时屏蔽逻辑,我通常用两种方法:
- 方法一:在需要屏蔽的输入引脚上接一个常数0或FALSE。比如一个AND门的某个输入需要临时屏蔽,就把它接0,这样AND门输出恒为0,等效于屏蔽了该分支。
- 方法二:选中整个网络后禁用网络,和LAD的操作一样。
方法一的优点是只影响单个分支,不影响网络内其他逻辑;缺点是如果忘记恢复,后期排查时容易忽略。方法二更彻底,但会影响整个网络。根据调试粒度选择合适的方法。
6. 我个人的注释习惯和项目实践
6.1 注释的粒度控制
在项目里,我遵循“三层注释”原则:
- 块级注释:每个FC/FB/OB块头部写清楚功能、作者、创建日期、修改记录。用SCL的
//或STL的//写在块最前面。 - 网络/程序段级注释:每个LAD网络标题或SCL程序段开头写一句话说明用途。比如“电机启动条件判断”或“配方数据读取”。
- 行级注释:只在逻辑复杂或容易误解的地方写行注释。比如一个复杂的数学运算,或者一个不常见的指令组合。
不建议每行都写注释,那样反而干扰阅读。注释的价值在于解释“为什么这么做”,而不是“这行在做什么”——后者应该由代码本身表达清楚。
6.2 调试注释的清理流程
调试阶段会产生大量临时注释和禁用网络。我的清理流程是:
- 调试完成后,先全局搜索
//和(*,逐个确认是否还需要保留。 - 对于禁用的网络,逐个启用并确认逻辑正确,或者彻底删除。
- 对于注释掉的代码,如果确认不再使用,直接删除而不是保留注释。
- 最后编译整个项目,确保没有警告和错误。
这个流程看起来繁琐,但能避免很多后期问题。我见过一个项目因为调试时的禁用网络没恢复,导致正式运行时某段安全逻辑失效,幸好被操作员及时发现。
6.3 团队协作中的注释规范
如果是多人协作的项目,建议在项目开始前就约定注释规范:
- 统一用
//做单行注释,块注释只在必要时使用。 - 禁用网络必须写明原因和预计恢复时间。
- 注释里的日期格式统一为
YYYY-MM-DD。 - 修改他人代码时,保留原注释并追加修改说明,不要直接覆盖。
这些规范看起来是小事,但在项目交接和后期维护时能节省大量沟通成本。特别是当项目周期超过半年时,你自己都会忘记当初为什么注释掉某段代码。
6.4 一个真实的调试案例
去年做一个包装线改造项目,PLC程序里有一段SCL写的配方管理逻辑。调试时发现某个配方参数总是被覆盖,排查了半天才发现是之前同事在调试时注释掉了一行赋值语句,但注释符号//只加在了行首,而行尾还有一个分号没注释掉,导致编译器把分号当成了空语句,逻辑上虽然不执行赋值,但变量声明还在,最终影响了后续的计算。
正确的做法应该是把整行都注释掉,包括分号:
// "RecipeParam" := 100;而不是:
// "RecipeParam" := 100;;这个案例说明,注释代码时要注意语法完整性。虽然注释内容不参与编译,但如果注释不彻底,残留的符号可能被编译器解析成其他含义。
7. 关于注释,最后再分享几个实用技巧
7.1 用注释做代码书签
在大型项目里,我习惯用特定格式的注释做书签,方便快速定位。比如:
// TODO: 需要优化这段逻辑的性能 // FIXME: 这里的边界条件处理有问题 // NOTE: 这个参数需要根据现场情况调整TIA Portal的任务列表(Task List)可以自动识别这些关键词,在“视图”菜单里打开“任务列表”,就能看到所有标记了TODO/FIXME/NOTE的注释位置。这个功能在调试阶段非常实用,相当于给代码加了一个待办事项清单。
7.2 注释里的变量引用要小心
如果你在注释里写了变量名,比如:
// "MotorSpeed" 需要限制在1500以内当这个变量被重命名或删除时,注释里的变量名不会自动更新。时间长了,注释和实际代码就会不一致。我的做法是,注释里尽量用自然语言描述,而不是直接写变量名。如果必须写变量名,就在变量重命名后全局搜索注释内容,手动更新。
7.3 导出注释做文档
TIA Portal支持将块导出为SCL源文件或XML文件。导出的SCL源文件里会包含所有注释内容。如果你需要给客户或同事提供程序说明文档,可以把关键块导出为SCL,然后用文本编辑器整理注释,形成一份可读性更强的文档。这比截图LAD网络要方便得多,也更容易维护。
7.4 注释的版本管理
如果项目用Git或SVN做版本管理,注释的修改也会被记录。我建议在提交代码时,把注释的修改和代码的修改分开提交,这样版本历史更清晰。比如先提交“添加功能注释”,再提交“修改逻辑实现”。虽然多了一步操作,但后期回溯问题时能快速定位是注释变了还是代码变了。
7.5 不要过度依赖注释
最后说一个观点:注释是辅助,不是替代。好的代码应该尽量做到自解释——变量命名清晰、逻辑结构简单、函数职责单一。注释应该用来解释“为什么”,而不是“是什么”。如果你发现一段代码需要大量注释才能看懂,那可能是代码本身需要重构,而不是加更多注释。
我在实际项目里的体会是,注释写得好的程序,往往逻辑也写得清晰;注释乱七八糟的程序,逻辑通常也好不到哪去。所以,把注释当成代码质量的一部分来对待,而不是事后补的额外工作。这样坚持下来,你会发现调试和维护的效率会有明显提升。