做项目调试那会儿最怕客户问的不是程序能不能跑而是报警记录上的时间对不上。西门子S7-200 SMART和MCGS触摸屏在这类小中控项目里是标配组合但两台设备各自带一块实时时钟跑着跑着就分道扬镳。今天把这套MCGS与200SMART时间同步的做法完整捋一遍从方案选型到PLC时钟指令再到MCGS组态脚本和现场排错给正在被时间戳折磨的朋友一份能直接照抄的作业。1. 先搞明白时间戳是谁打的问题根源在“各记各的账”1.1 触摸屏和PLC各有各的时钟很多朋友第一次遇到时间对不上第一反应是“屏的时钟坏了”或者“PLC时钟不准”其实两边都正常只是压根没同步过。S7-200 SMART CPU内部有一个实时时钟RTC靠内部超级电容或电池维持MCGS触摸屏也有自己的一套系统时钟由触摸屏主板的时钟芯片维持。两块时钟芯片上电后各走各的没有任何机制保证它们一定一致。关键是不同记录用到的时间戳来源不一样。MCGS上显示的历史曲线、报警记录、配方记录时间戳用的是触摸屏自己的系统时间而PLC程序里那些带时间戳的故障字、数据块、FIFO记录用的是PLC的RTC时间。如果两个时钟差十分钟你查报警时就会看到“PLC明明在8点跳的闸屏上记录却写着7点50”排查起来直接晕头转向。要是这设备还接了MES或者SCADA时间戳对不上就不是麻烦的问题而是数据直接没法用的问题。1.2 时钟漂移比想象中快石英晶振实时时钟的精度没有大家想的那么高在工业现场温度变化大、振动多、电源质量参差不齐的环境里一台设备一个月漂移几十秒到几分钟都很正常。我在现场实测过几套系统MCGS屏和PLC放了两个月没管差距最多能到三分钟左右。还有一类情况更隐蔽设备断电时间长了CPU的超级电容或者电池电量耗尽RTC会回到出厂默认时间比如2000年1月1日。重新上电后PLC程序该跑还跑但时间戳全是错的。如果现场没有校时习惯这个错误时间会被一直带下去直到有人发现报警记录全是乱码。下表可以快速判断某个记录到底该信谁记录类型时间戳来源MCGS报警记录、事件记录触摸屏系统时钟MCGS历史曲线、配方、数据转存触摸屏系统时钟PLC程序内部带时间戳的故障字、FIFOPLC的RTC上位机/SCADA采集的数据上位机本机时钟或PLC返回的时钟所以做时间同步之前先想清楚你要对齐的是哪一类记录如果只是屏上显示的时间不对那就校屏如果PLC数据要传给上位机那PLC时钟也得准。大多数项目的底线是两个时钟差距保持在几秒以内这样无论哪边打时间戳误差都可接受。2. 同步方向怎么定谁当时间源更合理2.1 三种常见方案对比方向上有三种常见做法第一种PLC当时间源。PLC程序里用TODR把RTC读出来放到V区MCGS读V区再把自己的系统时间设置成PLC的值。这种方案的好处是时间源只有一个所有屏、所有上位机都以PLC为准程序逻辑统一。第二种触摸屏当时间源。操作工在屏上校好时间MCGS把系统时间写到V区PLC用TODW指令把V区数据写入自己的RTC。好处是现场校时最直观——值班人员直接改屏上的系统时间就行不需要打开编程软件。坏处是如果屏本身时间乱掉了写进PLC会把PLC也带偏。第三种外部队时比如NTP或者PTP。适合有上层管理网络、设备数量多的大系统。但对一台MCGS加一台200SMART的小项目来说引入NTP服务器、交换机、网络配置复杂度明显过剩而且现场很多设备根本不在管理网里断网后照样对不上。三种方案的核心差异可以这样看对比项PLC做时间源触摸屏做时间源外部队时时间准确性来源PLC RTC程序可查可改触摸屏系统时钟网络时间服务器多台HMI是否一致是都跟PLC走需要各屏分别处理是都跟NTP走对接MES/SCADA方便时间源单一较麻烦时间源在屏上最方便实现复杂度低~中中高适用场景单屏或多屏的单机设备只有一台屏、现场手动校时为主大型网络化系统2.2 我的选型建议绝大多数单屏加单PLC的项目我推荐PLC做时间源。理由很简单PLC程序里本身就要记录故障、批次数据这些数据的时间戳必须由PLC时钟保证让PLC当时间源是顺势而为。另外PLC的RTC在断电后保持能力通常比触摸屏强可靠性更高。触摸屏当时间源也有它的适用场景比如只有一台屏操作工需要随时手动改时间比如换班对时改完之后一键写进PLC。这种情况下一定要在屏的界面上把“写入PLC”做成一个明确按钮而不是每次改完系统时间就自动写——否则操作工只是想把屏时间调准看一眼PLC时钟就被带跑了。如果现场有多台MCGS那就别用触摸屏当时间源老老实实让所有屏都去读PLC每台屏开机同步一次保证大家看到的时间完全一致。这也是我后面第7节会展开说的场景。3. 200SMART侧实现TODR/TODW和BCD格式是绕不开的3.1 时钟缓冲区结构S7-200 SMART读时钟和写时钟各有一条指令TODRRead Real-time Clock和TODWSet Real-time Clock。它们的共同点是都得通过一个8字节的缓冲区来传递数据这个缓冲区你自己指定起始地址比如VB1000。8字节缓冲区的含义和格式如下缓冲区偏移含义范围存储格式VB1000年0~99对应2000~2099BCDVB1001月1~12BCDVB1002日1~31BCDVB1003时0~23BCDVB1004分0~59BCDVB1005秒0~59BCDVB1006星期1~7BCDVB1007保留0-注意这里的“BCD”是最大的坑。BCD格式下一个字节的高四位表示十位低四位表示个位。比如2023年的“23”在缓冲区里是十六进制0x23也就是十进制35。如果你直接把35当成年份去用后面全乱套。S7-200 SMART的TODR和TODW读写缓冲区都是BCD格式这一点在系统手册里写得很清楚但现场照着手册做的人真不多。3.2 TODR读时钟 BCD转十进制的程序PLC读时钟这侧我的习惯是每扫描周期都执行一次TODR把结果转成十进制后放到VW1100开始的地址区MCGS只读这些已经转好的十进制值不在触摸屏脚本里做BCD运算清晰又省事。下面是STEP 7-MicroWIN SMART里的STL写法逻辑和梯形图完全对应// 网络1每个扫描周期读PLC实时时钟到VB1000~VB1007 LD SM0.0 TODR VB1000 // 网络2年BCD转十进制再加2000变成完整年份 LD SM0.0 MOVB VB1000, AC0 BCDI AC0 MOVW AC0, VW1100 I 2000, VW1100 // 网络3月 LD SM0.0 MOVB VB1001, AC0 BCDI AC0 MOVW AC0, VW1102 // 网络4日 LD SM0.0 MOVB VB1002, AC0 BCDI AC0 MOVW AC0, VW1104 // 网络5时 LD SM0.0 MOVB VB1003, AC0 BCDI AC0 MOVW AC0, VW1106 // 网络6分 LD SM0.0 MOVB VB1004, AC0 BCDI AC0 MOVW AC0, VW1108 // 网络7秒 LD SM0.0 MOVB VB1005, AC0 BCDI AC0 MOVW AC0, VW1110这里几个细节说明一下。MOVB VB1000, AC0是把字节移到累加器AC0的低字节同时把高字节清零这样后面BCDI AC0才会把0x0023正确转成23而不是被高字节里的垃圾数据干扰。I 2000, VW1100作用是把00~99的年转换成2000~2099的完整年份MCGS那边拿到2023、2024这种四位年份直接就能用。3.3 TODW写时钟 十进制转BCD的程序触摸屏当时间源时PLC要执行TODW把MCGS写入的V区十进制数据转成BCD再写进RTC缓冲区最后写回PLC时钟。程序的关键是你不能每个扫描周期都执行TODW否则触摸屏那边还没来得及更新数据PLC时钟就被旧值反复覆盖了。正确做法是加一个触发位上升沿执行一次写完就复位。这里我用M0.0做“同步请求”由MCGS置位M0.1做“同步完成”标志PLC侧维护。// 网络8M0.0上升沿触发执行一次TODW完成后复位请求、置位完成标志 LD M0.0 EU // 年完整年份减2000再转BCD MOVW VW1200, AC0 -I 2000, AC0 IBCD AC0 MOVB AC0, VB1000 // 月 MOVW VW1202, AC0 IBCD AC0 MOVB AC0, VB1001 // 日 MOVW VW1204, AC0 IBCD AC0 MOVB AC0, VB1002 // 时 MOVW VW1206, AC0 IBCD AC0 MOVB AC0, VB1003 // 分 MOVW VW1208, AC0 IBCD AC0 MOVB AC0, VB1004 // 秒 MOVW VW1210, AC0 IBCD AC0 MOVB AC0, VB1005 // 星期字节填0PLC会自动根据日期推算 MOVB 0, VB1006 // 写入PLC实时时钟 TODW VB1000 // 完成标志置位请求位复位 S M0.1, 1 R M0.0, 1这组程序里VW1200到VW1210和MCGS的数据对象一一对应VW1200是完整年份VW1202是月VW1204是日VW1206是时VW1208是分VW1210是秒。写入前PLC侧先减2000是因为时钟缓冲区的年只有0~99存不了2023这么大的数。3.4 为什么非要在PLC里转BCD有些朋友可能会问BCD转换放MCGS脚本里做不行吗行但我不推荐。第一MCGS脚本里做BCD转换公式就是(原始值/16)*10 (原始值%16)逻辑本身不复杂但每个时间字段都要写一遍脚本会变得啰嗦而且很容易把地址对应错。第二PLC侧程序是一次性的写完调试完就不动了但MCGS工程后期常被人改来改去脚本越简单越稳。第三如果这台PLC以后还要被别的上位机读时间VW1100这些十进制值可以继续复用不用重新发明一遍。还有一点由于TODR读出来的BCD值最大也只有0x59秒这一项永远不会出现负数或者超过255的情况所以你存到VW里的十进制值一定是正数MCGS那边用“16位无符号数”来定义通道就够了。4. MCGS组态侧驱动、变量、脚本一条龙4.1 设备窗口添加S7-200 SMART网口驱动MCGS这侧先从设备窗口入手。进入MCGS组态环境的“设备窗口”双击打开设备组合在设备工具箱里找到“S7-200 SMART TCP”驱动如果你的MCGS版本里名字是“西门子 S7-200 TCP”也一样就是对应200SMART网口通信的驱动拖到设备窗口中。双击驱动打开属性需要配置几个东西远程IP地址填S7-200 SMART CPU的IP比如192.168.0.10本地IP地址填触摸屏自己的IP比如192.168.0.20远程端口默认102一般不用动通信周期默认100ms或者1000ms都行时间同步用1秒周期足够。网口通信最大的好处是不用管PPI电缆、波特率、站号这些串口烦心事只要IP在同一网段、网线物理通了基本都能连上。如果设备之间没有交换机触摸屏和CPU可以用网线直连但记得两端IP都要设固定地址不要开DHCP。4.2 实时数据库对象和设备通道对应关系在MCGS里数据对象是全局的设备通道要和数据对象绑定。先到“实时数据库”里把这些对象建好PLC年、PLC月、PLC日、PLC时、PLC分、PLC秒类型都是数值型。如果你要做触摸屏写PLC的方案再建触年、触月、触日、触时、触分、触秒、同步触发、同步完成这些对象。回到设备窗口在S7-200 SMART驱动下面添加设备通道通道地址要和PLC程序里的V区对应。PLC做时间源时通道如下设备通道地址方向关联数据对象数据类型VW1100只读PLC年16位无符号数VW1102只读PLC月16位无符号数VW1104只读PLC日16位无符号数VW1106只读PLC时16位无符号数VW1108只读PLC分16位无符号数VW1110只读PLC秒16位无符号数触摸屏写PLC做时间源时还要加这些通道设备通道地址方向关联数据对象数据类型VW1200读写触年16位无符号数VW1202读写触月16位无符号数VW1204读写触日16位无符号数VW1206读写触时16位无符号数VW1208读写触分16位无符号数VW1210读写触秒16位无符号数M0.0读写同步触发位M0.1只读同步完成位通道地址格式直接填VW1100、M0.0这样千万别填成DB1.DBW0那种那是S7-1200/1500的写法200SMART驱动不认识。4.3 循环脚本里同步PLC做时间源PLC做时间源的同步脚本放在“运行策略”里的“循环策略”中。新建一个循环策略循环周期设60秒脚本内容就两行!SetDate(int(PLC年), int(PLC月), int(PLC日)) !SetTime(int(PLC时), int(PLC分), int(PLC秒))int()这个函数必须有。MCGS的数据对象默认按浮点数处理PLC年读进来虽然是2023但类型可能是2023.0时间设置函数要求整数参数不转换的话某些版本会直接报错或者静默不执行。这里有个容易忽略的点循环策略的循环周期是从策略开始执行之后算的如果你在工程里还挂了别的循环策略注意让时间同步策略的执行时间不要太密集。60秒一次对RTC来说绰绰有余一天也就同步1440次完全没有任何负担。4.4 按钮脚本里把触摸屏时间写进PLC触摸屏做时间源触摸屏做时间源时建议在画面上放一个“时间写入PLC”按钮按钮的“抬起”事件里写脚本。先建一组中间数据对象年、月、日、时、分、秒脚本逻辑如下!GetDate(年, 月, 日) !GetTime(时, 分, 秒) 触年 int(年) 触月 int(月) 触日 int(日) 触时 int(时) 触分 int(分) 触秒 int(秒) 同步触发 1!GetDate会把触摸屏当前系统日期取出来放到年、月、日这三个变量里!GetTime同理取出时、分、秒。把值转存到触年~触秒这些和VW1200关联的对象后置位同步触发M0.0PLC那边上升沿一到就会执行TODW并把M0.0复位、M0.1置位。同步完成后可以在按钮后面加一个状态显示关联同步完成对象显示“已同步”。脚本里也可以等一小段时间再去读同步完成标志避免操作工手太快按钮还没写完就切换画面。4.5 版本差异函数名以组态帮助为准MCGS不同版本的系统函数命名有点乱我上面写的!SetDate、!SetTime、!GetDate、!GetTime是嵌入版里最常见的叫法但有些版本里会写成!SetSystemDate、!SetSystemTime。接手别人的工程时先按F1打开组态帮助在“系统函数”里搜一下“时间”“日期”确认当前版本里到底叫什么再写脚本省得程序写完了才发现函数名不存在。5. 同步时机和通信状态判断别把错误数据当宝5.1 为什么不能无脑定时同步刚接触时间同步的人最容易犯的错就是循环脚本里什么都不判断每60秒直接执行!SetDate和!SetTime。通信正常时这没问题但一旦网线松动、PLC停机、IP被改MCGS读到的是最后一次通信成功时缓存的旧值甚至可能是0。这个时候脚本照样执行等于用一个假时间把本来还准的触摸屏时钟给覆盖了越同步越乱。我在现场遇到过这种情况操作工说屏的时间每天都会跳回同一个错误值查了半天发现是PLC连接断开后MCGS设备对象里保持的是上次的值循环脚本照样往里写。所以同步之前一定要做通信正常性判断。5.2 加一道“允许同步”的门槛最直接的办法是看驱动的通信状态。MCGS的S7-200 SMART驱动一般会提供一个通信状态通道不同版本名字不一样有的叫“通讯状态”有的叫“通道状态”值等于0表示通信正常。你可以在实时数据库里建一个“通信正常”对象关联这个通道然后脚本改成IF 通信正常 0 THEN !SetDate(int(PLC年), int(PLC月), int(PLC日)) !SetTime(int(PLC时), int(PLC分), int(PLC秒)) ENDIF如果你的驱动没有暴露通信状态通道也可以用更土但可靠的办法让PLC用SM0.51秒脉冲给一个VW地址做自加比如VW1300每秒加1溢出就自动回绕不需要处理。MCGS建一个对象“心跳”关联VW1300再建一个脚本变量“上次心跳”脚本判断两次读的值不一样就认为通信在线IF 心跳 上次心跳 THEN 上次心跳 心跳 !SetDate(int(PLC年), int(PLC月), int(PLC日)) !SetTime(int(PLC时), int(PLC分), int(PLC秒)) ENDIF这种心跳方式是真正“通信在线才动作”的逻辑比单纯判断值大小更可靠。VW1300回绕的时候心跳值从65535跳回0和上次读的值肯定不一样所以溢出不需要专门处理。5.3 一套可行的同步节奏我的做法是首次上电必须同步之后每天固定时间同步一次再留一个手动同步按钮给运维。首次同步放在循环策略里用一个“开机已同步”标志控制。标志初始为0只有当通信正常且标志为0时才执行同步成功后把标志置1。这样避免了MCGS“启动策略”里脚本执行时通信还没建立、读到的全是0的问题。每日固定时间同步可以在循环脚本里加个时间判断比如凌晨3点IF 通信正常 0 THEN IF 时 3 AND 分 0 AND 秒 0 THEN !SetDate(int(PLC年), int(PLC月), int(PLC日)) !SetTime(int(PLC时), int(PLC分), int(PLC秒)) ENDIF ENDIF注意这里的“时”“分”“秒”是触摸屏系统时间不是PLC时间。凌晨同步的好处是现场一般没有人在操作改系统时间对正在运行的画面、配方、报表影响最小。6. 现场排错复盘这几个坑我替各位踩过了6.1 BCD没转换年份变成35第一次做这个功能时我在PLC里只写了TODR没做BCD转换MCGS直接把VB1000的原始值拿来用。结果2000的“00”读出来是0还好2023的“23”读出来是35月份“12”读出来是18设出来的系统时间彻底没法看。排查过程很快打开MCGS的设备调试窗口看到PLC年35PLC月18马上意识到是BCD的问题。加完转换程序后数值瞬间正常。这个坑是新手必踩这里提前说破各位少走一次弯路。6.2 TODW每个周期执行PLC时钟被旧值反复覆盖还有一次是帮朋友调设备他的PLC程序里把TODW放在了SM0.0常通条件下每个扫描周期都在执行。现象是触摸屏上改了时间点写入PLC时钟确实变了但下一秒又被VW1200里的旧值覆盖回去了等于永远改不过去。这就是我前面强调上升沿触发的原因。TODW的执行必须严格受限要么用M0.0上升沿要么用第一次扫描标志SM0.1做一个写完就断开的逻辑总之不能常通。当然如果VW1200里的值本身会随触摸屏实时刷新那常通也没事但那样PLC时钟会跟着触摸屏的每一秒刷新而不断重写没有实际意义还增加通信负荷。6.3 设备调试窗口看到的通道值不动MCGS里排查通信问题最趁手的工具就是设备调试窗口。在组态环境的设备窗口里双击驱动打开调试页面你能看到每个通道的实时值。如果VW1100的值始终显示0或者不动先别怀疑脚本看看这个窗口。通道值不动的常见原因有三个IP没配对、通道地址格式填错、数据对象类型不匹配。IP问题用电脑ping一下CPU就能确认。地址格式问题常见于把VW1100填成了VW110.0或者1100这类格式驱动直接不识别。数据类型不匹配则表现为值能变化但都是乱码比如把VW通道定义成了32位浮点。我习惯先把设备调试窗口打通确认VW1100到VW1110都有正确数值在刷新再去写循环脚本。这样如果最后时间还是不对问题一定在脚本不用两头猜。6.4 断电后时间回到出厂值有一台设备停机检修了两周重新送电后MCGS屏显示的时间是对的屏自己走的但PLC传到屏上的时间变成了2000年1月1日。原因就是S7-200 SMART的RTC靠超级电容维持断电时间超过保持时间后时钟丢失回到出厂默认。这种问题的处理没有捷径只能靠上电同步。我后来在循环策略里加了“开机已同步”标志每次设备恢复送电、通信建立后的第一分钟就把PLC时间拉回来。这里有个细节如果PLC时钟已经回到2000年那么开机同步会把触摸屏时间也带到2000年去等于两个一起错。所以遇到长期断电的设备上电后先用编程软件MicroWIN SMART的时钟设置功能把PLC时间调准再让自动同步去跟进顺序不能反。6.5 星期字节的坑S7-200 SMART时钟缓冲区里VB1006是星期1表示周日到7表示周六。很多时候我们根本不显示星期但这个字节会影响TODW能否正确写入。有朋友遇到过TODW执行后时间没变查来查去发现是星期字节里填了个无意义的数。我的做法是写时钟时直接把VB1006清零让PLC根据日期自动推算星期。实测这个方式在各种固件版本的200SMART上都正常比自己在PLC里算星期几可靠得多。6.6 函数名写错导致脚本不执行MCGS脚本有个特点函数名写错不会弹出编译错误而是运行时不执行很难发现。有一次我把!SetDate写成了!SetDay脚本编译通过但时间就是不改变。排查这类问题可以借助MCGS的调试输出函数在脚本里临时加一行!Debug(sync)然后在运行环境里看调试输出。更简单的办法是建一个运行计数器循环策略里每次执行加1画面上显示这个计数器如果数值增长说明循环策略在跑问题在函数名或参数上如果计数器不动那要先检查策略本身有没有被启用。7. 多屏系统、首次校时和日常维护心得7.1 多台MCGS怎么保持统一有些设备一台PLC带两台甚至三台MCGS屏分布在机台两侧。这种布局下如果每台屏都自己走时钟一个月后两屏显示的时间差个几十秒很正常操作工两边一对比就会投诉。我的方案是所有屏全部按PLC做时间源每台屏各自的循环策略都去读同一个VW1100到VW1110同步节奏也一致。这样不管哪台屏打开看到的都是PLC的同一份时间天然一致不需要屏和屏之间互相通信。要注意的是多台屏同时读PLC时PLC的程序不要做任何复杂的地址互斥读时钟是纯读操作不存在冲突。7.2 首次校时和长期维护最后聊一下日常维护。既然PLC做时间源那PLC自身的时钟谁来校准答案是初始阶段靠编程软件后期靠人工抽查。设备出厂前用MicroWIN SMART连接PLC在设置里把时钟校准一次精确到秒。之后只要PLC内部超级电容状态正常一天漂移量很小加上每日一次自动同步系统能一直保持基本准确。触摸屏这边的维护重点在操作工习惯。很多现场操作工会手动改MC屏的时间改完也不告诉别人。如果你们用的是触摸屏做时间源一定要在画面上加一个明显的“时间写入PLC”按钮让“改屏时间”和“同步PLC”变成两个明确动作避免误操作。我在实际项目中习惯在触摸屏主画面放两个时间显示一个直接读触摸屏系统时间一个读PLC时间两个都常驻显示。这样做的好处是一眼就能看出偏差哪天两者差超过一分钟说明同步链路哪一环出问题了趁早处理不要等到报警记录乱套了再回头找。时间同步这种功能平时存在感很低但它一旦失效排查成本远比当初做这个功能的成本高得多。