1. 项目背景与整体思路
搞自动化这么多年,跟触摸屏和PLC打交道的场合太多了。以前在现场最常碰到的画面,就是触摸屏上固定显示一排按钮、一个I/O域,点几下换一屏,再点几下又换一屏。操作工还好,但我们做调试和运维的人看着是真着急。尤其是碰上设备要监控的IO点位特别多,输入输出几十上百个点,要是还在触摸屏上一个个拖变量、一个个摆放控件,组态工作量能让人怀疑人生。
这个项目要解决的问题,其实就是标题里说的那件事:用西门子触摸屏做IO变量的动态显示。什么叫动态显示?通俗点说,就是屏幕上的控件不是跟某一个IO点死死绑定,而是可以通过切换、选择、翻页的方式来复用。比如画面里有10组设备状态,每一组的输入输出点结构其实都是类似的,那我只要做一组控件,用变量来动态切换它显示的对象,就能替代做10组控件的工作量。这在多工位设备、多轴系统、批量生产线监控里非常实用。
我这次以西门子S7-1200 PLC搭配西门子MTP1000触摸屏为例来拆解整套方案。MTP1000属于西门子新一代精简系列HMI,组态环境是WinCC Unified,很多从老款精简屏转过来的朋友一开始有点发怵,界面和变量机制跟以前的WinCC flexible差别挺大。但只要摸清楚DB块、FC块在PLC侧怎么规划,触摸屏侧怎么关联变量,动态显示这个功能无非就是一层窗户纸。
整个项目的核心路径是:在PLC里建全局DB块,把IO输入输出点的位状态和模拟量数值统一放到DB块的某个区域里,然后写一个FC块,把外设IO映像区或者其他来源的数据周期性地搬运到DB块里,最后触摸屏上建立变量时直接指向DB块的地址,再通过“可见性”或者“变量选择”的方式来做动态显示。这样一来,触摸屏只管读DB块,不直接面对最新输入输出区,既安全又灵活。同时,如果以后设备点位变更,只需要改PLC侧DB块的映射关系,触摸屏组态基本不用动,维护成本能降一个数量级。
这篇文章不是纯理论科普,也不是简单的说明书搬运,而是基于我在调试现场实际踩坑之后整理出来的方案。不管你是刚入门想搞懂PLC和触摸屏联动的新手,还是已经在用西门子设备想优化监控画面的工程师,这套思路和步骤都有参考价值。
2. 为什么一定要用DB块和FC块,而不是直接监控I/O区
2.1 直接监控I/Q区会踩哪些坑
很多人第一次做触摸屏IO监控时,习惯直接在HMI变量表里新建变量,地址填“I0.0”“Q0.1”或者“IW64”这样的外设地址。这样做在点数少的时候确实最快,几步就能让几个信号在屏上动起来。但我得提醒一句,这种方案在S7-1200/1500平台上有几个很现实的问题。
第一个问题是触摸屏的通讯压力。HMI变量如果直接采集外设输入输出映像区,那么HMI会不断地与PLC交换这些地址的数据。当监控的点数很多,比如数字量几百点、模拟量几十路,通讯报文会变得很长,屏幕翻页和刷新速度都会被拖累。尤其是在老款支持以太网但带宽有限的精简屏上,这种现象更明显,画面卡顿、反应迟滞,操作工体验很差。
第二个问题是地址规划混乱。用直接地址监控,HMI画面上的变量和PLC程序里的地址是散乱对应的。今天改了一个输入点,明天换了一个输出通道,触摸屏变量表要跟着改半天,而且很容易漏改。等设备运行几个月之后,再回去审查画面和PLC程序的对应关系,那就是一场灾难。
第三个问题是Q区直接访问的风险。某些情况下,触摸屏侧设置了“允许写入”,操作工直接点画面上的控件写Q点,万一误操作或者画面切换瞬间误触发,后果可能是设备意外动作。这在安全要求高的场合是绝对不能接受的。通过DB块间接转发,触摸屏读写的是数据块里的镜像区域,程序侧可以在FC块里做安全的逻辑判断,比如使能条件、互锁检查、时序限制,才能真正做到可控。
2.2 DB块和FC块的职责划分
这套方案里的关键设计思想,就是分离“数据采集”和“数据展示”两个环节。PLC侧由FC块负责从信号源头采集数据,写入DB块;触摸屏侧只跟DB块打交道,所有画面的变量都指向DB块里的对应字段。
DB块在S7-1200/1500里就是一个数据仓库,你可以把它理解成一个表格,里面定义了各种类型的字段,比如字节、字、双字、整数、实数、布尔量。西门子PLC的DB块分为全局DB和背景DB。做IO监控,我们用全局DB,因为它可以跨OB、FC、FB被任意读取和修改。在这里,DB块扮演的是“数据中转站”的角色,它把IO状态、模拟量数值、系统标志位等信息集中存储在固定偏移的地址上,方便触摸屏统一寻址。
FC块,也就是函数,是一种没有背景数据块、不保存内部静态状态的程序组织单元。我的习惯是用FC块写纯组合逻辑或者转换逻辑。在这个方案里,FC块负责把最新输入输出映像区(外设I/O)的原始数据经过筛选、位整合、字节组合、范围变换之后,集中搬运到DB块中。之所以用FC而不是直接用传送指令,是因为FC块可以定义输入输出参数,可以被反复调用,逻辑清晰,也方便以后增加处理环节,比如滤波、报警判断、统计等。
2.3 动态显示的底层逻辑
所谓动态显示,在触摸屏上实现的手段其实不止一种。常见的有控件可见性控制、画面窗口切换、文本列表状态切换、IO域数值关联等。但无论哪种手段,核心逻辑都是:画面上的一个对象,根据某个变量或者表达式的值,切换到不同的显示结果。
以电机状态监控为例,一个电机的完整状态至少包含三个信息:运行信号、故障信号、当前电流值。如果画面里要监控20台电机,传统做法就是放20组指示灯和显示框。但采用动态显示方案后,我们可以只做一组指示灯和显示框,通过一个“设备序号”变量来告诉画面现在要显示第几台电机的状态,数据源指向DB块中对应电机编号的结构数组元素。
这样就引出了DB块结构设计的一个核心经验:如果动态显示的对象是“一组结构相同的数据”,那么在DB块里就应该将这些数据设计成结构体数组,而不能平铺设计。结构体数组配合触摸屏的索引寻址,可以实现一键切换监控对象,这是整个方案性价比最高的部分。
3. PLC侧实现,从0到1搭建DB块与FC块
3.1 定义DB块的数据结构
我先带大家把DB块的数据结构定义清楚。在TIA Portal里,新增全局DB,就可以在“数据类型”列中定义字段。第一个最关键的检查点是:“优化的块访问”属性。对这个应用场景,我强烈建议关闭优化块访问。因为西门子HMI对非优化DB块的地址偏移可以直接计算,变量访问更直观。尤其是MTP1000这类WinCC Unified组态的屏,虽然官方说支持符号寻址,但在跨软件版本调试时,非优化访问的兼容性更好,踩坑概率低。
我们假设要监控8台设备,每台设备状态包含两个数字量输入信号(运行反馈、故障信号)和一个模拟量输入(电流)。那么DB块结构可以这样设计:
DATA_BLOCK "DB_IO_Monitor" { S7_Optimized_Access := 'FALSE' } VERSION : 0.1 STRUCT DeviceCount : Int; // 设备总数,用于HMI循环显示 CurrentIndex : Int; // 当前选中设备编号,HMI可写 Device : Array[0..7] of Struct Running : Bool; // 运行状态位 Fault : Bool; // 故障状态位 Current : Real; // 电流实际值,单位A TimeStamp : DInt; // 故障发生时间戳 End_Struct; RawInput : Array[0..15] of Word; // 原始输入字,用于调试查看 RawOutput : Array[0..15] of Word; // 原始输出字,用于调试查看 END_STRUCT这里有几个设计细节我说明一下。Device数组用了Array[0..7] of Struct这样的结构体数组。为什么不用8个独立的变量?因为动态显示的核心就是索引。触摸屏上只要用Device[CurrentIndex].Running这种方式关联变量,然后修改CurrentIndex,画面显示内容就能跟着切换。CurrentIndex这个变量我把注释就写在HMI侧可写,这样操作工就能在触摸屏上用一个“上一台/下一台”的按钮去改变它,画面上的IO状态同步切换。
至于RawInput和RawOutput数组,是我后来调试时加上的。因为现场排查问题时,我们经常需要回看原始的输入输出字内容,确认到底是采集环节出了问题还是映射环节出了问题。有了这些原始数据留底,仪表盘级别的对照排查就能很快定位问题。
3.2 编写FC块,高效完成数据映射
完成DB块定义之后,下一步就是写FC块,把IO映像区搬进DB块。这里我推荐用SCL语言来写,因为SCL处理数组循环和位操作非常灵活。你可能会问,LAD不也能传送数据吗?能,但一个一个地拖传送指令,点位一多就累了,而且后续修改很不方便。SCL一次循环就搞定。
FC块接口定义如下:
FUNCTION "FC_IO_Map" : Void { S7_Optimized_Access := 'FALSE' } VERSION : 0.1 VAR_INPUT bEnable : Bool; // 使能刷新 END_VAR VAR_TEMP i : Int; // 循环变量 diIndex : DInt; // 设备编号索引 END_VAR这段接口定义里,我只留了一个输入参数bEnable,用于控制刷新动作是否执行。如果这个使能位为0,FC块不会刷新DB块数据,这样在调试时可以冻结住HMI上的显示数据,方便观察某一个时刻的设备状态。
接下来是FC块主体代码。以数字量采集为例,我们先把IO槽位上连续的输入字节整体搬运到DB块的RawInput数组里,这个操作其实只是一条MOVE_BLK指令的事。然后再逐位分解到设备状态结构体里。代码如下:
IF #bEnable THEN // 批量搬运原始输入输出数据 #i := 0; WHILE #i < 16 DO "DB_IO_Monitor".RawInput[#i] := PEW64; // 连续读入16个字到DB #i := #i + 1; END_WHILE; END_IF;这段指令其实需要按PLC实际硬件地址调整。如果输入模块从地址64开始,那么PEW64就是第一个输入字。注意,S7-1200/1500的外设访问要用PEW(按字)或PED(按双字)指令,不是直接用IW。这个区别很多朋友调试时卡过。用IW只能读过程映像区的刷新值,而PEW是直接读取外设实际值,对实时性要求高的场景更准确。
接下来是位分解和模拟量处理部分。我们假设设备0的运行反馈信号接在数字量输入模块的bit0,设备0的故障信号接在bit1,设备1的运行反馈在bit2,故障在bit3,依此类推。那么从RawInput[0]里提取各个设备状态位的代码如下:
FOR #i := 0 TO 7 DO "DB_IO_Monitor".Device[#i].Running := NOT_CAST( "DB_IO_Monitor".RawInput[0], #i * 2 ); "DB_IO_Monitor".Device[#i].Fault := NOT_CAST( "DB_IO_Monitor".RawInput[0], #i * 2 + 1 ); END_FOR;这里借用了位测试的思路,用“与”运算再加移位来实现。SCL里没有直接的“取位”函数,通常用MOVE加掩码实现。更简单的方式是先把字赋给临时变量,然后用SHR右移再AND1来取最低位。完整写法如下:
FOR #i := 0 TO 7 DO "DB_IO_Monitor".Device[#i].Running := (SHR(IN := "DB_IO_Monitor".RawInput[0], N := (#i * 2)) AND 16#1) = 1; "DB_IO_Monitor".Device[#i].Fault := (SHR(IN := "DB_IO_Monitor".RawInput[0], N := (#i * 2 + 1)) AND 16#1) = 1; END_FOR;模拟量处理同理。如果模拟量模块地址从IW80开始,4模拟量通道对应设备0到设备3的电流,那么可以这样映射:
FOR #i := 0 TO 3 DO "DB_IO_Monitor".Device[#i].Current := INT_TO_REAL( "DB_IO_Monitor".RawInput[4 + #i] ) * 0.1; END_FOR;这里的0.1是根据模拟量模块的量程和传感器变送比例算出来的线性系数。如果用的是4~20mA模拟量板卡,信号范围对应工程量0~10A,那换算系数就是满量程除以数字量满刻度,计算方式我在文章后面会展开。要注意的是,这里的RawInput[4]对应的是第5个字,因为前面4个字被数字量占用了。地址偏移别搞混,这是新手比较容易懵的地方。
3.3 在OB1中调用FC块并设置扫描周期
FC块写完之后,必须在OB1或者其他组织块里调用它,程序才会真正执行。调用方式在TIA Portal里很简单,从右侧指令树拖入FC_IO_Map就好。调用时把输入参数bEnable接成一个常开节点或者一个运行标志位。
关于刷新周期,我有几条经验分享。第一,如果只是做状态显示,没有动作控制需求,那么每个扫描周期刷新完全没有问题。S7-1200的循环周期通常在几毫秒到十几毫秒,完全足够视觉层面上的刷新。第二,如果画面里包含其他复杂运算或者通讯任务,为了给PLC减轻负担,可以在FC调用前面加上一个周期触发器,比如用“Clock_1Hz”系统时钟位,让FC每秒只执行一次。这样IO数据虽然每秒刷新一次,但对触摸屏监控来说已经够用了。第三,涉及快速联锁动作的监控,比如分闸信号、安全急停信号,不建议在这种周期性批量刷新里做关键判定,这些信号必须走硬接线逻辑或者快速OB,不能依赖HMI刷新,这是安全底线。
这里还要提一个细节:如果PLC程序周期太短,而FC块执行的搬运指令比较多,会对扫描周期有一定影响。所以在FC块内部,我建议把整个数据映射逻辑做得精简高效,尽量减少不必要的中断保护语句和重复循环。你可以在FC块开头写一个时间戳记录,调试时观察单次调用的CPU运行时间是否在允许范围内。
4. MTP1000触摸屏侧组态与动态显示配置
4.1 新建项目并建立PLC连接
MTP1000是西门子新一代精简系列HMI,组态软件是WinCC Unified Comfort。首次打开软件新建项目时,会提示选择设备类型。这里要特别注意,MTP1000系列和老的TP900、KTP900虽然在名字上很接近,但组态软件完全不同。老款精简屏用TIA Portal里的WinCC Comfort,MTP系列必须用WinCC Unified。如果你拿着TP900的工程文件想直接下到MTP1000,大概率是打不开或者提示设备不匹配,很多从老设备升级上来的客户都卡在这一步。
建立PLC连接时,先在项目树里添加S7-1200PLC,然后创建HMI连接。连接协议选择“S7-1200/1500”或者“SIMATIC S7-1500”,IP地址填写PLC的IP,机架号和槽号保持默认即可。MTP1000和S7-1200通常直接接在同一台交换机上,网络配置只要在同一个网段就行。这里有个值得注意的地方:WinCC Unified项目默认会把连接参数中的“访问点”设置为S7-ONLINE,如果现场使用了虚拟网卡或者软路由,这个访问点可能会选错,导致HMI和PLC一直建立不上连接。
4.2 创建变量,关联DB块地址
连接建立好后,在HMI变量表中新建变量。这里就是之前强调“关闭DB块优化访问”的意义所在。如果DB块是优化访问模式,变量地址显示的是一个符号名,WinCC Unified解析起来相对繁琐;如果是非优化访问模式,你直接可以填写绝对地址,比如%DB1.DBX0.0这样的格式。
数字量变量关联方式如下:新建一个变量叫“设备0运行状态”,数据类型选Bool,地址填DB_IO_Monitor.Device[0].Running。注意,TIA Portal的符号寻址用点号,绝对寻址才是%DB1.DBX0.0。在WinCC Unified里,我们可以直接使用全局DB的符号名,前提是PLC侧已经编译且符号信息正确上传。
为了做动态显示,我们需要一个关键变量“当前设备编号”,数据类型选Int,地址关联到DB_IO_Monitor.CurrentIndex。画面上的按钮通过改变这个变量的值,来切换显示对象。比如“下一台”按钮的点击事件,写一条脚本逻辑,让CurrentIndex在当前值基础上加1,超过设备总数时回0。这样一组控件就能监控所有设备。
4.3 用可见性属性实现IO动态显示
MTP1000的WinCC Unified画面编辑器中,几乎每个对象都有一项“可见性”(Visibility)属性。我们利用这个属性,让画面上的指示灯、IO域只在特定条件下显示。举个例子:画面上放置一个“运行指示”圆形灯,在它的“可见性”属性里填写一个布尔表达式,比如"设备0运行状态" == true或者直接引用符号名。
但这就是常规的单点显示,离“动态”还有点距离。动态的精髓在于复用。我们画一组控件,把它们都绑定到“当前设备”的变量上。比如一个IO域,它的“过程值”属性绑定到表达式"DB_IO_Monitor".Device["DB_IO_Monitor".CurrentIndex].Current,当操作工切换CurrentIndex时,这个IO域自动显示新设备的电流值。这里可能有人会担心,数组下标能用变量吗?在WinCC Unified里,答案是肯定的。它支持带变量下标的符号寻址,这就为动态监控打开了极大的空间。
实际项目里,我通常还会配合“画面窗口”来实现整块动态区域。做法是把一组设备状态监控控件做成一个子画面,子画面里所有控件都带CurrentIndex索引。在主画面中放一个画面窗口控件,把“画面名称”属性设置为这个子画面,然后把这个子画面的两个关键变量连接准备好。切换按钮改变CurrentIndex时,整块监控区域就像“换了一台设备”一样整体刷新,视觉效果非常直观。
这种设计还有一个隐性红利:触摸屏的变量连接数大幅减少。如果8台设备都用独立控件,至少需要8组×3个变量共24个连接。用动态方案之后,本质上只要一组控件加一个索引变量,变量连接数量下降一个量级。对应到WinCC Unified里,HMI与PLC的通讯负载也会显著降低,画面翻页和刷新也就更快了。
4.4 让IO监控画面更好用的几个组态细节
在MTP1000上做IO监控画面,有几个操作细节我建议你在组态时一并处理掉。
第一个是画面刷新策略。WinCC Unified的默认画面循环周期是100毫秒左右,你可以根据需求调整。如果只是状态灯和数值显示,100毫秒足够。如果是一些快速脉冲信号,建议在PLC侧做累计或锁存,否则人眼根本看不出闪动,反而容易误判信号状态。更合理的设计是:对需要捕捉的脉冲信号,在PLC里用SR触发器锁存,触摸屏上显示锁存状态,操作工确认后再复位。
第二个是报警和颜色变化。MTP1000支持对象颜色随变量值变化。比如设备故障信号为真时,指示灯变红并闪烁;电流值超过上限时,IO域背景色变黄。这些都可以在“动画”属性里配置,不用写额外脚本,直接绑定变量条件就行。
第三个是操作权限。HMI不光是显示,还可能涉及设备启停操作。MTP1000用户管理里有权限等级设置。我建议把“切换设备编号”的按钮设为操作员级别可操作,把“写入设备参数”的按钮设为工程师/管理员级别。这样避免现场操作工误改参数,同时也满足一般设备安全审核要求。
第四个是屏幕按钮的自锁和互锁。如果画面里既有“上一台”又有“下一台”,建议在两台边界时禁用按钮。WinCC Unified里可以在按钮的“使能”属性里绑定表达式,判断当前设备编号是否已经超出边界,超出则按钮置灰。这样操作工不会产生“怎么按了没反应”的困惑。
5. 昆仑通态触摸屏如何导入西门子DB块数据
5.1 为什么要跨界导入
很多调试场景里,现场不止有西门子触摸屏。有时候设备供应商标配的是西门子MTP1000,但因为项目周期太紧或者备件库存不足,甲方会临时把触摸屏换成其他品牌。昆仑通态(MCGS)是国产组态软件里用得很多的一款,客户经常会问:MCGS能不能直接读西门子S7-1200的DB块数据?
答案是肯定的。MCGS支持通过以太网和西门子S7协议直接访问S7-1200/1500,前提是DB块关闭优化访问。这里又回到了之前强调的重点,如果你的DB块开的是优化访问,那MCGS的驱动解析会比较麻烦,因为优化的块访问地址是动态重排的,外部设备无法预先计算变量的物理偏移。这是跨品牌通讯的第一大坑,不少工程师在MCGS里翻来覆去找不到DB1里的变量,就卡在这里。
5.2 在昆仑通态中手工映射DB块地址
手工映射方式适合点位不是特别多的场合。在MCGS的设备组态里,添加一个“西门子S7-1200 TCP”驱动,然后设置PLC的IP地址和端口号,通常S7-1200以太网通讯端口是102。然后逐个添加采集变量,比如要读取DB_IO_Monitor.Device[0].Running这个位,在变量地址栏里填DB1.DBX0.0,数据类型选位。
如果要读取电流值,地址就是DB1.DBD8这类绝对偏移。偏移地址如何计算?只要把DB块关闭优化访问,并且记录好每个字段的偏移量。通常在TIA Portal里单击DB块,在“偏移量”列就能看到每个字段的字节偏移地址。结构体数组的每个元素占据若干字节,按顺序累加即可。我通常会在Excel里做一个地址偏移表,把DB块所有字段的偏移量都列出来,这样在MCGS里配置时直接查表,省去心算错误。
这种方式的优点是直接、明了、不依赖中间转换;缺点是当点位很多时,手动在MCGS里逐个建变量实在太累。所以这个方法比较适合小型项目或者临时调试用的演示工程。
5.3 通过CSV批量导入提高组态效率
MCGS支持变量表批量导入导出,这是大批量点位时最推荐的方式。先在MCGS里新建一个临时工程,通过“设备组态”里的变量导出功能,导出一份CSV模板,里面有通道名称、数据类型、读写属性、采集周期、连接设备等列。我们在Excel里按照之前整理好的地址偏移表,手工或者用公式批量生成每一行变量记录,然后保存为CSV,再在MCGS里导入即可。
CSV里有一列“通道地址”,格式是DB1.DBW100这样的绝对地址。注意西门子数据格式和昆仑通态的差异:S7-1200的字节顺序默认是大端模式,而MCGS某些数据类型在解析时可能需要调整“大小端”。我在实际项目里就遇到过一个典型问题:MCGS读到的模拟量电流值数值差很多,仔细排查发现是高低字节反了,在变量属性里勾选“字节顺序调整”后数值就正常了。这是跨品牌通讯里最典型的坑,没有之一。
另外一个坑是变量导入后,采集周期默认值往往不合理。MCGS默认采集周期是1000毫秒,如果点位多且屏上又有历史曲线,建议把不需要快速刷新的变量的采集周期调大到2秒或5秒,减轻PLC和屏的通讯负担。对于需要快速响应的启动停止按钮,采集周期设为100毫秒就能满足响应需求。
5.4 MCGS读取失败时的参数自检清单
如果MCGS里配置好了变量,但运行监控始终读到0或者提示通讯失败,先别急着怀疑PLC侧,按下面的顺序排查一遍,大概率能解决问题。
第一,确认PLC的DB块确实是“非优化访问”且已编译下载。查看DB块属性里的“优化的块访问”复选框是否关闭。如果之前在优化模式下建的DB块,后来取消了优化访问,必须先重新编译再下载,否则实际的物理地址和离线文件不一致,外部设备读到的可能就是错乱的数据。
第二,确认PLC的OPEN Communication权限。S7-1200的CPU属性里,“防护与安全”中有“允许从远程对象进行PUT/GET通信访问”的选项,如果这个选项没勾,第三方设备是读不到DB块数据的。一般默认是允许的,但有些品牌项目里会为安全考虑关掉它。如果MCGS读不到数据,优先检查这里。
第三,确认MCGS变量的数据类型长度。S7-1200的Bool变量只占用1位,读取时通道地址必须精确到DBX0.0这种位地址,不能写成DBB0。而整数(Int)要占2个字节,地址必须偶对齐,比如DBW2。如果对齐错误,MCGS读回来的值要么是0要么是乱码。
第四,确认大小端设置。西门子PLC遵循大端字节序,MCGS默认可能是小端。在MCGS变量属性里找到字节顺序设置,改为“大端”模式,通常能立即解决数值翻倍或者完全不对的问题。这个排查步骤看起来简单,但每次都能拦住不少人。
第五,也是很多人容易忽略的,就是触摸屏和PLC的以太网连接要稳定。建议在生产调试阶段就固定IP,不要用DHCP自动获取。MCGS的驱动连接超时通常默认几秒,如果网络质量差,会出现变量周期性的跳0和恢复,看起来像数据不稳定,实际是通讯丢包。
6. 常见问题与排查技巧实录
6.1 MTP1000下载程序时提示设备不匹配怎么办
这个问题在水友群里出现的频率非常高。我也是从TP900切到MTP1000之后才真正理解这里的坑。MTP1000使用了WinCC Unified运行时,而不是传统的Comfort运行时。所以,之前用TIA Portal WinCC Comfort做的老工程,无法直接下载到MTP1000。解决办法有两个:一是用工程迁移工具把老的WinCC Comfort工程转移到WinCC Unified,但要注意,迁移后部分对象、脚本可能需要手工调整,不是完全一键完成;二是直接在WinCC Unified中重新建工程,如果画面数量不多,手工重建反而比重构更稳妥。我个人建议第二种,因为第一次迁移工程时踩过不少脚本兼容性的坑,手工重建的工程量并不大,而且可控性好。
6.2 触摸屏显示数值一直为0,通讯显示正常
这个现象在调试现场特别常见,原因大概率不是通讯断了,而是“读到了地址但数据本身是0”。排查顺序如下:首先在PLC侧监控DB块的地址内容,确认DB块里确实有数据。其次在触摸屏侧打开“诊断”页面看变量状态,如果变量状态为“值有效”,说明通讯正常,问题在地址映射;如果变量状态是“无效”或“超出范围”,检查地址格式。然后确认HMI变量数据类型和DB块字段类型是否一致,比如PLC用了Real型,HMI变量却建成了Int,读出来的肯定不对。最后检查有无大小端设置问题。我把这几个检查点做成了一张速查表,用得上的可以截图保存。
| 现象 | 排查步骤 | 常见根因 |
|---|---|---|
| 变量一直是0 | 先看PLC侧DB值,再看HMI变量状态 | 地址偏移写错或数据类型不匹配 |
| 数值显示翻倍/乱码 | 检查字节序设置 | 大小端不一致 |
| 通讯状态正常但无值 | 查看PLC属性远程通讯是否允许 | PUT/GET未开启 |
| 变量偶尔变成0 | 检查网络丢包和采集周期 | 通讯超时或传输模式异常 |
| 地址找不到 | 确认DB优化访问属性 | 优化访问未关闭 |
6.3 动态切换按钮没反应,或切换后数值延迟很大
切换按钮没反应,要么是变量写不进去,要么是写进去了但画面引用方式不对。检查CurrentIndex变量是否被误设成了只读属性;再检查按钮是否因为权限等级不够而被禁用了。切换后数值延迟大,通常是触摸屏的采集周期太长或者通讯报文太大。把不必要的历史数据采集频率降下来,或者缩小画面窗口刷新范围,一般就能改善。
另一个比较容易忽略的问题是数组下标的边界。如果在触摸屏的表达式里直接写了Device[CurrentIndex],而操作工快速连点“下一台”按钮,CurrentIndex可能瞬间超过数组上限,导致表达式无效。所以我在PLC侧FC块里专门写了边界钳制的逻辑,确保CurrentIndex永远在0到7之间。这个逻辑只有几行:
IF "DB_IO_Monitor".CurrentIndex > 7 THEN "DB_IO_Monitor".CurrentIndex := 7; END_IF; IF "DB_IO_Monitor".CurrentIndex < 0 THEN "DB_IO_Monitor".CurrentIndex := 0; END_IF;不要小看这两行。触摸屏脚本触发变量变更时,有时候会连续写入几个中间值,如果没有边界限制,画面表达式就可能因为越界而在短时间内失效,导致画面闪烁或控件直接隐藏。等到值回到合法范围,画面才恢复正常。这种问题在调试现场用时很难查,但只要在PLC侧做个合法范围保护,就能从根上规避。
6.4 画面闪烁和刷新跟不上
画面闪烁,尤其是状态指示灯那种忽亮忽灭,很多时候其实是信号本身在快速通断,而不是显示问题。比如一个接近开关在工件经过时输出几十毫秒的脉冲,如果触摸屏采集周期是100毫秒,很容易漏掉脉冲或者看到一个不稳定的半亮状态。这种情况下,不要试图靠调快采集周期来解决,正确的做法是在PLC侧把脉冲信号做锁存或者累计。比如增加一个“运行次数”计数器,或者用SR触发器做一个“曾经有信号”的保持位,触摸屏上显示保持位,操作工确认后复位。这样既不会闪烁,又能捕捉到短暂信号,而且还能为后续的产量统计留数据基础。
如果确认信号本身是稳定的,画面还是闪,那就需要检查HMI的循环周期和画面窗口的刷新机制。WinCC Unified里可以将某些不频繁变化的对象放到一个独立的静态画面中,避免整屏频繁刷新。还有一点是要注意画面窗口的“刷新”属性,如果设置成了循环刷新,即使子画面内容没变也会持续发送请求,浪费通讯资源。把这些细节逐一排查完,闪烁问题基本都能解决。
6.5 关于DB块大小和地址对齐的避坑心得
我在实际项目里被地址对齐坑过一次,那次监控40多路模拟量,为了省DB空间,我把两个Int连续存放,结果触摸屏读回的数据有一部分总是错位。后来才想起来西门子PLC对多字节数据类型是有对齐要求的。S7-1200/1500里,INT类型的数据在DB块中默认按2字节对齐,REAL类型按4字节对齐,如果你强制紧凑排列,虽然离线能编译,但跨设备访问时地址解析就会混乱。
建议在DB块结构里预留对齐占位,或者在结构体末尾加一个Reserved字节数组做填充。这样虽然多占几个字节,但换来的是一劳永逸的稳定地址。做IO监控的DB块一般不会大到让人在意这点空间,稳定可靠才是第一位的。
6.6 从MTP1000跨界到其他HMI时的通用经验
最后讲一个通用性的经验。动态显示这个设计思路,不仅适用于西门子MTP1000,也适用于昆仑通态、威纶通、Proface等主流触摸屏。无论什么品牌,底层逻辑都是一样的:PLC侧用DB块集中管理IO状态,用FC块或FB块统一映射数据,HMI侧通过索引变量实现画面控件的动态切换。区别只在于地址表达方式和组态软件的操作习惯。
如果你准备在其他品牌的屏上复刻这套方案,建议先确认三件事:第一,该屏是否支持“符号寻址”或“绝对寻址”的方式访问PLC数据块;第二,该屏是否支持“变量下标”或“表达式引用”来作为控件数据源,如果不支持,那就只能通过脚本动态修改变量地址,稍微绕一点;第三,该屏的数据类型和字节序处理是否能配置,这一条决定了模拟量值是否正确。把这三件事搞清楚,跨品牌迁移这套方案其实只是时间问题,不需要重新设计。
回到西门子生态里,MTP1000的优势在于和S7-1200/1500的原生整合,变量符号直接导入,通讯稳定,脚本功能也不弱。所以我最终的结论也简单:如果你的设备全流程都在西门子体系里,直接用DB块加FC块配合MTP1000是最省心的路线;如果现场需要兼容其他品牌的触摸屏,那你更需要把DB块的地址规划做得足够规范,只有规范了,跨平台才不吃力。这套方法我用下来,最大的感受就是:前期的数据结构设计多花半小时,后期调试和维护能省下好几天,这笔账怎么算都划算。