简介:面向工业自动化与SCADA开发者的西门子WinCC用户归档专题案例,聚焦生产数据存储与检索场景,系统讲解动作(Actions)与标准模块之间的协同机制,帮助解决历史数据管理、报表生成与故障排查中的实际难题。压缩包内共290个文件,大小36.21MB,以250个rpl脚本文件为主体,辅以mdf/ldf数据库文件、pdl画面文件、dum备份、cfg配置文件等,覆盖归档触发逻辑、数据筛选转换、压缩存储与调用显示等完整环节。已有1150人参与学习,内容包含示例项目文件、脚本代码、配置文件及分步实践指南,可直接对照案例项目进行配置与调试。通过学习可掌握用户归档的触发条件设置、标准模块复用方式、归档间隔与保留期限等策略设计,并能理解动作与模块配合提高项目效率的关键思路,适合需要深化WinCC数据管理能力的自动化工程师与项目集成人员使用。
1. wincc 用户归档案例:事件型数据不该塞进过程值归档
班组长让你把每天的设备点检记录存下来,要求能按操作员查、按时间段导出来。第一反应是拉一个变量归档,结果发现点检是事件型数据——一天百来条,查的时候还要跟过程值混在一起,这不是变量归档该干的活。WinCC 用户归档就是为这种场景设计的:它把数据按记录存成一张张结构化表,字段你自己定,运行时可以手动录入、脚本写入、按条件检索,还能绑定表格控件直接展示。这篇文章用一个设备点检归档案例,把建表、画面绑定、脚本读写和踩坑整条路走一遍。适合做批次追溯、操作日志、报表底表的工程师,也适合刚接触用户归档、想把概念落到现场的人。
2. 用户归档和变量归档的选型边界:先定数据模型,再动手建表
2.1 一张表看清用户归档与变量归档的分工
很多人把用户归档和变量归档当成同一种东西的两种叫法,实际上两者分工完全不同。变量归档解决的是“过程值怎么存下来、怎么压缩、怎么画趋势”,用户归档解决的是“业务记录怎么结构化、怎么按条件查、怎么改”。下面这张对比表是我每次给现场同事培训时必放的。
| 对比维度 | 变量归档 | 用户归档 |
|---|---|---|
| 存储对象 | 模拟量、开关量的过程值快照 | 操作日志、点检记录、批次信息等结构化记录 |
| 触发方式 | 周期采集或变化采集,系统自动写 | 手动录入、脚本写入、事件触发 |
| 数据量 | 高频、大,按秒甚至毫秒积累 | 低频、小,一天几十到几千条 |
| 查询方式 | 按时间轴查询,适合画趋势曲线 | 按任意字段组合条件查询,支持增删改 |
| 编辑能力 | 运行时只读,不能改历史值 | 可插入、可修改、可删除(受权限控制) |
| 典型场景 | 温度曲线、压力趋势、能耗分析 | 点检表、交接班记录、生产追溯、质检结果 |
关键结论是:拿用户归档存模拟量趋势是常见误用。有人觉得用户归档也能存数值,就把一个温度测点每分钟写一条用户归档,结果一个月下来数据库膨胀、查询卡顿,而趋势控件还不直接读这张表,最后还得回到变量归档。反过来,拿变量归档存点检记录也别扭——你没法按操作员名字过滤,也没法在运行界面里补一条漏记的数据。选型时先问一句:这条数据是要“画曲线”还是要“查记录”,答案直接决定用哪套机制。
2.2 点检记录的数据模型:字段命名、类型和长度怎么定
用户归档的本质是数据库表,字段设计直接决定后面查询顺不顺。以设备点检为例,一条完整记录至少包含:点检时间、设备编号、点检人、设备状态、关键温度值、备注。对应到用户归档字段,我一般这样设计:
| 字段名 | 数据类型 | 长度/精度 | 说明 |
|---|---|---|---|
| RecordTime | 日期/时间 | 固定 | 点检时间,排序和过滤的主键字段 |
| DeviceID | 文本 | 8 | 设备编号,如 P-101 |
| OperatorName | 文本 | 16 | 点检人姓名,按 4 个汉字加余量设计 |
| Status | 整型 | 固定 | 设备状态码,1 正常、0 异常 |
| TempValue | 浮点数 | 保留两位 | 关键温度值 |
| Remark | 文本 | 50 | 备注,注意给足长度 |
字段命名这里有一条血泪经验:尽量用英文,不要用中文。中文不是不能用,但你在脚本里拼 SQL 时每次都要加引号,跨项目迁移时还会遇到编码问题,排查起来非常痛苦。另外避开 SQL 保留字,比如 Name、Status 这种在很多数据库语境里容易出问题,稳妥做法是统一加前缀,比如 F_RecordTime、F_DeviceID。类型和长度在项目运行后修改受限,尤其是文本字段,长度一开始就按最坏情况给。备注只给 20 个字符,现场多打几个字就截断,等发现时历史数据已经写坏了,没有后悔药。
2.3 在项目管理器里创建一个能跑的归档:三个关键步骤
创建用户归档的位置在项目管理器左侧树里的“用户归档”节点。我用的版本是 TIA WinCC V15.1,老版 WinCC 7.x 位置也类似,逻辑不变。
第一步:右键“用户归档”,选择“新建归档”,归档名填 EquipmentInsp。归档名就是后面脚本连接时的关键标识,建议只允许字母和数字,不要带空格。第二步:在新建归档对话框的字段选项卡里,按上一节的字段表逐条添加,每添加一个字段就设置数据类型和长度。这里有三个属性容易忽略:允许为空、索引、锁定。RecordTime 建议勾选索引,按时间过滤会快很多;允许为空按业务需求设置,点检记录的设备和时间建议必填。第三步:编译项目。编译不是走个形式,它会校验字段定义和页面引用,编译通过后这个归档才算在运行库里真正创建出来。
运行系统启动后,这个归档会对应项目数据库里的一张实际表。单用户项目默认数据库实例是 .\WinCC,归档名就是表名。你可以用 SQL Server Management Studio 连上去看一眼表结构,这一步能帮你建立“用户归档=表”的直觉,后面脚本写错了也知道去哪查。建好表之后先别急着写脚本,下一章先走画面绑定这条路,把手工录入跑通。
3. 画面绑定用户归档控件:从拖入控件到完成第一条真实记录
3.1 用户归档控件的功能区:表格、工具栏和过滤条各自管什么
用户归档控件在 WinCC 画面编辑器里叫 WinCC UserArchive Control,拖到画面上之后,第一眼会看到一大块表格区域。这个控件默认分成三块:顶部是工具栏,中间是数据表格,底部是状态栏。工具栏里提供的是运行时操作按钮——新建记录、删除记录、保存、撤销、过滤,这些按钮能否点,取决于你在属性里给了哪些权限,而不是全部默认可用。表格区域显示的就是用户归档里的实际记录,一行一条,列名对应你建的字段。底部还有一个小过滤条,运行时可以直接输入条件过滤表格内容,不用写脚本,适合给操作员用。
很多人第一次用这个控件,运行起来发现表格是空的,第一反应是归档没建对。其实大概率是表里本来就没数据,或者在属性里没绑定归档名。控件本身只是个容器,它不会自动找到你的归档,必须显式指定。这个“没绑定”的问题,是我见过最多的新手翻车点。
3.2 控件属性里必须改的四个参数:归档名、编辑权限、删除权限和排序
选中控件,右键打开属性对话框,重点看四个地方。
| 参数 | 位置 | 建议值 | 说明 |
|---|---|---|---|
| 用户归档名 | 属性页“用户归档” | EquipmentInsp | 不选的话控件运行起来白板一块 |
| 允许插入记录 | 属性页“运行时行为” | 是 | 控制运行时能否新增行 |
| 允许删除记录 | 属性页“运行时行为” | 是 | 控制运行时能否删除行 |
| 默认排序字段 | 属性页“表格” | RecordTime 降序 | 保证最新记录显示在最上面 |
前两个是基础,第三个是安全边界。如果这个画面只给班长看、不让他改数据,就把插入和删除都关掉,只留查看能力。默认排序字段容易被忽略,不设的话按数据库物理顺序显示,新插入的记录跑到表格最后面,现场操作员会以为数据丢了。排序字段选 RecordTime 并按降序,最上面永远是最新记录,贴近日常检查习惯。
另外注意一点:控件的过滤功能依赖查询界面,运行时过滤只影响显示,不会改数据库原始数据。这点可以在交接班时明确告诉操作员——误过滤不是误删除,不用担心。
3.3 手动增删改查验证:填一条、存一条、再到数据库里核对一条
控件配置完成并编译运行后,按下面这套步骤做第一次真实录入验证。
第一步:启动运行系统,打开绑定控件的画面,点击工具栏上的“新建记录”按钮,表格底部会出现一条空行。第二步:依次填入 RecordTime、DeviceID、OperatorName、Status、TempValue 和 Remark。日期时间字段可以直接点单元格弹出选择器,文本字段直接输入。第三步:点击保存按钮,确认没有报错弹窗。第四步:切换到 SQL Server Management Studio,连接到 .\WinCC,展开表目录,找到 EquipmentInsp 表,执行最简单的查询,确认刚填的记录已经落到数据库里。
这里有两个必踩的细节。第一,保存按钮灰着点不动,大概率是“允许插入记录”没打开,或者当前记录里有必填字段为空。第二,往数值字段里输入“abc”这类非数字内容,控件会拒绝并把光标停在原单元格,这不是故障,是类型校验在起作用。类型校验按你建字段时选的类型走,所以建表时不要把温度字段误建成文本型,否则后面排序和趋势都会出问题。
4. 用脚本读写用户归档:VBS 写记录,C 脚本查记录
4.1 为什么建议脚本直连项目库而不是操作控件
控件适合人工录入和查看,但现场很多场景需要自动化:PLC 报某个信号后自动写一条点检记录,交班时按工号批量查记录,定时统计当班异常次数。这些靠手工点控件做不了。常见做法是用脚本直连项目数据库,对用户归档对应的表执行 SQL。这样做的优势是不依赖画面是否打开——后台全局脚本也能写;劣势是你要自己管理连接字符串和错误处理,比调用控件接口更“裸”。
我一般混用两种语言:VBS 写业务逻辑,读起来直白,适合保存、批量插入这类低频操作;C 脚本适合放在按钮事件里做查询回显,性能比 VBS 稳。下面两段代码分别是“按信号写一条记录”和“查询最新记录回显到画面”,可以直接抄到自己的项目里改字段名。
4.2 VBS 写入:PLC 信号触发一条点检记录
在画面某对象的 VBS 事件里写如下代码。常见触发方式是脚本触发器定时调用,或者关联一个 PLC 变量,变量变化时执行写入。
Dim conn, sql Set conn = CreateObject("ADODB.Connection") conn.ConnectionString = "Provider=SQLOLEDB.1;Data Source=.\WinCC;Initial Catalog=EquipmentInsp" conn.Open sql = "INSERT INTO EquipmentInsp " & _ "(RecordTime, DeviceID, OperatorName, Status, TempValue, Remark) " & _ "VALUES (" & _ "'" & Now & "', " & _ "'P-101', " & _ "'张工', " & _ "1, " & _ "36.5, " & _ "'例行点检无异常')" conn.Execute sql conn.Close Set conn = Nothing这段代码的逻辑是:先建立 ADO 连接,连接串里 Data Source 写成 .\WinCC,指代 WinCC 项目运行库;Initial Catalog 写成用户归档名 EquipmentInsp。很多第一次接触的人卡在这里——不知道归档名可以直接作为库名使用。如果连接失败,下一步去 SSMS 里确认数据库实例名和表名,以实际为准,不要死磕代码。SQL 语句里显式列出字段名而不是用位置赋值,是避免字段错位的必要习惯。VALUES 里字符串用单引号包,数字直接写,日期用 Now 函数生成当前时间。备注里如果可能包含单引号,比如“设备’A’异常”,直接拼接会把 SQL 截断,正式项目要么做单引号替换,要么改成 ADO 参数化查询。
这里有个参数值得注意:ConnectionString 里的 Provider 用 SQLOLEDB.1 是最通用的写法。如果你的 WinCC 版本较新,也可以用 MSOLEDBSQL,但现场机器不一定装了新驱动,SQLOLEDB.1 兼容性最好,我至今没遇到跑不起来的机器。
4.3 C 脚本查询最新记录并回显到画面
把下面的 C 脚本放在画面一个查询按钮的 Click 事件里。作用是把 EquipmentInsp 里最新一条记录的 OperatorName 和 TempValue 取出来,写到画面上两个 IO 域的变量里。
#include "apdefap.h" void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { #pragma code("kernel32.dll") #include "winbase.h" #pragma code("msado15.dll") #import "msado15.dll" no_namespace rename("EOF", "adoEOF") #pragma code() _ConnectionPtr pConn; _RecordsetPtr pRs; CoInitialize(NULL); pConn.CreateInstance(__uuidof(Connection)); pConn->Open("Provider=SQLOLEDB.1;Data Source=.\WinCC;Initial Catalog=EquipmentInsp", "sa", "", -1); pRs.CreateInstance(__uuidof(Recordset)); pRs->Open("SELECT TOP 1 OperatorName, TempValue FROM EquipmentInsp ORDER BY RecordTime DESC", _variant_t((IDispatch*)pConn), adOpenForwardOnly, adLockReadOnly, adCmdText); if (!pRs->adoEOF) { SetTagChar("LastOperator", (LPCTSTR)(_bstr_t)pRs->Fields->GetItem("OperatorName")->Value); SetTagDouble("LastTemp", (double)pRs->Fields->GetItem("TempValue")->Value); } pRs->Close(); pConn->Close(); pRs.Release(); pConn.Release(); CoUninitialize(); }这段脚本的核心逻辑是:用 TOP 1 加 ORDER BY RecordTime DESC 取最新一条,避免把整张表拉进内存。adOpenForwardOnly 表示只向前滚动,针对这种只取一条记录的查询最省资源;adLockReadOnly 表示只读打开,防止误写。取到记录后 SetTagChar 和 SetTagDouble 是 WinCC 的 C 脚本 API,把字段值写到内部变量里,画面上的 IO 域直接关联这两个变量就能显示出来。
参数说明里有一个关键点:连接串的用户名和密码我直接写了 sa 和空密码。实际项目中很多 WinCC 运行库是不开 sa 的,更稳妥的方式是用 Windows 集成认证,把 Open 的认证参数改成 SQLOLEDB 支持的安全模式。不管用哪种,密码不要写死在脚本里,项目交付后维护人员翻代码看到明文密码总是隐患。
4.4 把用户归档数据接到历史趋势曲线上:变量中转的脚本思路
有人会问:用户归档里的温度值能不能直接画在 WinCC 的趋势控件里?答案是不能。趋势控件只认变量归档和过程变量,不认用户归档表。常见做法是变量中转:脚本定时把用户归档最新值写到内部变量,趋势控件的数据源指向这个内部变量。比如用定时触发器每秒执行一次SetTagDouble("TrendTemp", (double)最新TempValue),趋势曲线就能跟着更新。
这个思路能解决“给领导看趋势”的需求,但它有一个边界:投放趋势的是实时刷新值,不是完整的归档历史。如果要画某个时间段的历史追溯曲线,脚本要按时间段查用户归档表,再把结果逐点写进数组变量或转存到变量归档里。这属于进阶玩法,我放到最后一章讲验证的时候一并说。
5. 用户归档常见翻车现场:乱码、表锁、找不到许可证的排查顺序
5.1 中文写入控件变成问号:代码页与字段长度
现象:控件和数据库里都能看到记录,但中文字符全部显示成问号,英文和数字正常。原因有两类。第一类是字段长度不够,文本字段按字节存储,中文在部分编码下占两个字节,长度给 10 实际只能存 5 个汉字,超出部分变成乱码。第二类是 WinCC 项目代码页与 SQL 排序规则不一致,SQL 直连写入时字符集转换出问题。解决办法:建表时文本字段长度按最坏情况乘 2;确认项目属性里代码页设置为简体中文(936 或 65001,视版本而定);SQL 直连时在连接串里显式指定语言选项。这个坑最阴险的地方在于,它不是必现的——偶尔一段长备注写进去才翻车,等发现时历史数据已经污染了。
5.2 报表写入时提示表被锁定:连接未关闭与记录锁定
现象:脚本批量插入几十条记录后,后续操作提示“表被锁定”或“无法删除记录”。原因:上一段脚本执行完 SQL 后连接没有关闭,事务一直悬着;或者用户归档组态里勾选了“记录锁定”,运行时控件编辑某条记录会锁住该行。我排查的顺序是:先看脚本里conn.Close是否执行到了——脚本中间报错跳出,连接就漏关了;再看是不是有人正在控件里编辑那条记录。解决:写入和查询代码里用On Error Resume Next配合最后统一关闭连接;组态里的锁定选项如果不是业务必需就关掉;多客户端项目里避免两个画面同时编辑同一条记录。这条属于典型的“自己把自己锁死”,排查本身往往比解决更费时间。
5.3 V15.1 打开用户归档编辑器提示找不到许可证 WinCC Comfort
现象:TIA WinCC V15.1 环境里,打开用户归档相关组态或编译运行时弹窗,提示“找不到许可证 WinCC Comfort”,项目能建、画面能画,就是用户归档用不了。原因:用户归档组态功能属于 Professional 级别能力,如果你创建项目时选的是 Comfort/Advanced 项目类型,授权检查就过不去;还有一种情况是电脑上只装了 Comfort 版本的试用授权,Professional 授权没装或版本号对不上。解决:第一步检查项目类型,新建项目时选择 Professional;第二步打开授权管理器,确认安装了对应 V15.1 的 Professional/Advanced 授权,V15 的授权不能拿来顶替 V15.1;第三步重启授权服务,再重新打开项目。这个坑不是你的脚本问题,是授权边界问题,别浪费时间查代码。
5.4 SQL 直接写入后控件显示对不上:字段顺序与时间格式
现象:脚本用 INSERT 写入数据,数据库里查没问题,但控件表格里某几列的值串位了。原因:INSERT 语句没有显式列出字段名,直接按表结构默认顺序写值 — 一旦建表时调整过字段顺序,脚本里的值就错位了。另一个高频原因是时间格式,WinCC 控件对日期时间字符串的解析严格,写成2024/05/01它能认,写成2024-5-1就可能显示成 1900 年。解决:INSERT 永远显式列出字段名,不要偷懒;时间统一用YYYY-MM-DD HH:MM:SS格式,VBS 里用FormatDateTime(Now, 2)控制格式再拼进 SQL。这条赏罚分明:写规范了没问题,写野了就出怪数据。
5.5 数据量上来后查询越来越慢:索引、分表和清理
现象:归档跑了两三个月,打开控件要等好几秒,脚本查询也越来越慢。原因:RecordTime 字段没建索引,每次查询都全表扫描;或者每天几千条记录全堆在一张表里,没有任何清理策略。解决:建表时给 RecordTime 勾选索引;查询永远加 WHERE 时间范围,不要查全表;控件里默认加载条数限制在能看够用的范围内。更彻底的办法是按月拆归档,每个月一张表,脚本里动态拼表名。用户归档不是数据仓库,别指望它扛几年的数据。定期把旧数据导出到 Excel 或 SQL Server 别的库里,再从用户归档里删掉,这个动作要写进运维手册。
6. 进阶:批量补录、趋势联动和迁移验证的完整核对流程
6.1 用 VBS 把 CSV 批量补录进用户归档
现场经常遇到历史点检记录在纸面上、需要补录的情况。逐条手工点控件太慢,可以用 VBS 脚本读 CSV 文件循环插入。核心逻辑是逐行解析 CSV,拼 INSERT 语句执行。注意 CSV 里的时间文本先做格式标准化,字段顺序和表结构对清楚再跑。批量补录前先在测试归档里跑一遍,确认没有字段错位,再切到正式归档。
Dim fso, ts, line Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile("D:\backfill.csv", 1) Do Until ts.AtEndOfStream line = ts.ReadLine ' 按逗号拆字段,拼 INSERT,注意转义 ' 示例:2024-05-01 08:30:00,P-101,张工,1,36.5,补录 Loop ts.Close这里的转义处理要特别小心。CSV 里如果有包含逗号的备注,简单的 Split 会拆错。常见做法是用分隔符引号处理函数解析,或者要求现场导出的 CSV 不用逗号做分隔符,改用制表符。我倾向后者,因为点检记录备注里很少出现制表符。
6.2 迁移后的验收脚本:条数、字段、时间戳一次对完
用户归档从开发机迁到生产机,或者从旧项目迁到新项目时,组态还能靠导入导出,数据表就要靠备份恢复。迁移完成别急着让现场用,先跑一遍核对脚本:对比源表和目标表的记录条数、字段类型、时间范围。我用得最多的验收 SQL 只有三行:
SELECT COUNT(*) FROM EquipmentInsp; SELECT MIN(RecordTime), MAX(RecordTime) FROM EquipmentInsp; SELECT OperatorName, COUNT(*) FROM EquipmentInsp GROUP BY OperatorName;条数对得上说明数据没丢,时间范围对得上说明归档段完整,按操作员分组能顺带验证字段内容没有整体偏移。这三个查询跑完,心里就有底了。
最后补一个我的教训:最早做用户归档项目时,我图省事把文本字段长度全按 20 设,结果三个月后备注被截断,返工时数据已经坏了。现在我每做一个归档,先写字段字典交底,再动建表,脚本里只用显式字段名,迁移完必跑验收查询。这套流程看着笨,但能拦住绝大多数翻车。希望帮到你。
本文还有配套的精品资源,点击获取