ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Access数据写入WinCC变量的VBS脚本实现与ODBC配置详解

Access数据写入WinCC变量的VBS脚本实现与ODBC配置详解 简介一份面向工业自动化技术人员的PDF手册专门讲解如何利用VBS脚本将Access数据库中的数据写入西门子WinCC变量实现外部数据库与组态软件之间的数据联动适用于考试练习、设备状态采集或生产数据上报等场景。文档以“Wincc_Data”数据库和同名列为例系统展示了从建立数据表含Tag1~Tag5五个字段、配置ODBC数据源到编写完整VBS脚本的整个流程包括声明ADODB对象、构造连接字符串、执行SQL查询、读取结果集并调用HMIRuntime.Tags写入指定变量等关键步骤并配有多段可直接复用的代码片段即使是入门级工程师也能按图索骥完成部署。整个资源包仅含1个PDF文件体积约18KB轻便易存适合作为技术参考或考试复习材料。目前已有342人学习使用对于需要快速打通WinCC与Access数据链路的人员来说是一份简洁而实用的实操指南。1. 从Access数据到WinCC变量为什么这条链路总在现场被反复问起在工厂自动化联调阶段一种很常见的需求是化验室数据库或者班次汇总库里的Access数据要实时或定时变成可供WinCC画面显示、历史趋势曲线脚本取数、报表查询的正式变量。很多人以为WinCC自带数据库驱动打开变量管理就能连上Access实际上WinCC并不直接内置Access接口数据库数据写入WinCC变量的常用做法是先由VBS脚本通过ADO/ODBC把Access表读出来再写入WinCC变量。本文围绕这条链路讲清楚选型、建表、脚本实现和排错。适合正在做WinCC集成、维护老旧上位机系统、以及准备把Access工艺参数迁移到SCADA体系的工程师参考。2. 选型与链路设计为什么优先考虑ODBC加脚本方案2.1 Access在这种场景下的定位轻量、单文件、免服务Access数据库在自动化现场并不少见。一台没有SQL Server环境的普通工控机如果需要保存化验室手工录入的样品结果、小规模配方参数、班次交接记录最省事的方案往往不是装一套数据库服务而是放一个Access文件。它的优势非常具体单文件存储拷走就能备份不需要独立服务进程不占系统资源安装Office或者Access Runtime就能读写SQL查询能力足够支撑中小项目的参数管理。但选型之前必须认清Access的边界。它的写并发能力弱多个客户端同时追加数据时文件锁定策略容易引发“正在被其他用户使用”的报错单文件容量到了2GB上限后性能大幅下降密码保护机制也比较脆弱不能当作安全数据库看待。所以在工业项目里我通常把Access定位成“参数暂存区”或者“离线录入区”从来不建议把它当成历史数据仓库。历史数据应该交给WinCC自带的归档系统归档后的趋势曲线查询速度快得多没必要把历史数据存进Access再绕一圈写回WinCC。和Excel相比Access的优势在结构化和查询能力。Excel对几千行数据还能应付一旦几万行数据叠加公式和格式打开文件都卡Access用一条SQL就能按条件提取字段支持数据类型约束、主键和索引多用户读的体验也比Excel好很多。和SQL Server、MySQL这些需要独立安装、配置服务、管理账户的数据库相比Access在中小项目里的部署成本几乎为零。如果你面对的是一台用了七八年的旧工控机硬件资源有限现场没人愿意维护数据库服务Access往往就是最现实的选择。2.2 接入WinCC的三种路径VBS脚本、C脚本、OPC中间件WinCC读写Access数据库业界主流路径有三种VBS脚本调用ADODB、C脚本调用ADO/ODBC API、通过KEPServerEX这类OPC中间件把数据库包装成外部通讯节点。三者没有绝对优劣关键是匹配项目规模和团队维护能力。方案优点缺点适用场景VBS脚本 ADODB部署简单、调试直观、WinCC原生支持VBS脚本弱类型、性能一般中小项目、周期刷新、单机部署C脚本 ADO/ODBC运行效率高、类型转换可控、适合复杂SQL编译调试周期长现场维护门槛高数据量大、逻辑复杂的项目OPC中间件如KEPServerEX把数据库变成OPC节点WinCC走标准OPC通道需要额外授权和组态对非OPC背景工程师不友好已采用OPC架构、需要集中管理多个数据源工程上我一般优先VBS脚本理由有三个。第一WinCC的全局脚本编辑器原生支持VBS语法接近Excel宏现场工程师能看懂、能改第二ADODB是Windows自带组件Access数据源天然适配不需要额外装运行库第三脚本里可以直接用HMIRuntime.Tags(变量名).Read和.Write读数据库和读写PLC变量在同一个代码体系里排错时思路连贯。数据库增删改查操作在VBS里也就是几条SQL的事。读操作用SELECT写操作用UPDATE追加用INSERT删除用DELETE。唯一需要警惕的是Access的SQL语法和SQL Server有差异比如日期分隔符、通配符、TOP N的写法。实际踩过坑之后我通常会在脚本里把SQL语句拼接成一个字符串变量单独输出到日志这样一旦语法出错能立刻看到Access到底执行的哪条语句。3. 准备数据库与ODBC连接建表、DSN配置和连接字符串3.1 设计一张能直接被脚本消费的Access表如果你打算让脚本周期性从Access读数据写入WinCC变量第一件事不是写代码而是把Access表结构规范起来。最常见的翻车现场是Access表里类型随意文本和数字混在一列脚本读出来以后没法直接写变量只能层层转换一旦某个字段是空值就报类型不匹配。我常用的表结构是这样的CREATE TABLE RCP_Queue ( SeqID AUTOINCREMENT PRIMARY KEY, ParamName TEXT(50) NOT NULL, ParamValue DOUBLE NOT NULL, Processed BIT DEFAULT 0, TryCount INTEGER DEFAULT 0, UpdateTime DATETIME DEFAULT Now() );在Access的查询设计器里直接执行这段DDL就能建表。SeqID是自增主键给每条参数记录一个唯一标识ParamName保存WinCC变量名这样脚本才知道该把值写到哪里ParamValue保存要写入的数值Processed标记这条记录是否已经被脚本处理过防止重复读取TryCount记录失败重试次数UpdateTime记录最后修改时间。ParamName的命名最好和WinCC变量一一对应。比如WinCC变量叫MixerTemp_SP表里ParamName就存MixerTemp_SP。如果表里放的是中文名或者带特殊字符的名字VBS调用HMIRuntime.Tags()时就要处理编码问题非常麻烦。还有一点要注意ParamValue字段别用TEXT类型存储数字。Access的TEXT列在写入数字时不会报错但脚本里判断IsNumeric和CDbl转换会多出一层逻辑而且字段一旦混入单位文本脚本很容易中断。注意Processed和TryCount这两个字段是批量方案的核心。没有Processed脚本会反复读取同一行数据每秒钟往WinCC变量里写相同值既浪费数据库IO又让画面变量不停闪烁。没有TryCount某一行写入失败会卡住整个脚本的后续处理。3.2 配置ODBC数据源32位与64位的实际差别Access的ODBC连接有两种方式一种是先在系统里配置DSN脚本用DSN名连接另一种是无DSN连接直接在连接字符串里写Provider和文件路径。工程上我更推荐无DSN连接原因很简单部署到新电脑时不需要额外创建数据源少一个环境配置环节就少一个出错点。典型的无DSN连接字符串长这样ProviderMicrosoft.ACE.OLEDB.12.0;Data SourceC:\SCADA\param_db.accdb;Persist Security InfoFalse;Provider指定使用Access数据库引擎Data Source直接指向数据库文件Persist Security Info设为False表示不在连接过程中保存密码信息。这个连接字符串可以原样写进VBS脚本不依赖系统DSN。如果你因为某些历史原因必须用DSN最折磨人的问题来了WinCC V7.x系列是按32位进程运行的即使操作系统是64位Windows脚本通过ODBC读数据时调用的也是32位ODBC接口。而控制面板“管理工具”里默认打开的是64位ODBC管理器在里面创建的Access DSN32位的WinCC脚本根本看不到。解决方法是运行框里输入%windir%\SysWOW64\odbcad32.exe这会打开32位ODBC数据源管理器添加Microsoft Access Driver指向.accdb或.mdb文件。每一步操作和64位管理器一样但最终服务对象不同。很多工程师连不上库的第一大原因就是32位/64位DSN混淆明明配了DSN脚本却永远提示找不到数据源。Access数据库引擎版本也要注意。Office 2016以前默认驱动是Microsoft.Jet.OLEDB.4.0只能打开.mdb格式新一点的.accdb格式必须用Microsoft.ACE.OLEDB.12.0或者更高版本。如果你的项目还在用老旧的.mdb文件Jet驱动还能对付如果建库时用了Access 2007以上版本就老实换ACE驱动。3.3 网络路径与共享目录部署的注意事项Access文件如果放在共享目录里给多台WinCC工作站读需要考虑文件锁和网络延迟。Access的默认打开方式是共享模式多客户端可以同时读但写操作会生成.ldb锁文件。脚本如果高频读写锁文件可能残留导致Access提示“文件正被其他用户使用”。工程上我有一个习惯Access文件尽量本地化。数据库生成本地副本由一台采集站专门负责写入其他工作站读自己的副本或者通过同步机制定时复制。如果必须多人共享把Access放在稳定的NAS或者Windows文件服务器上同时把脚本读取周期拉长到5秒以上减少锁冲突概率。网络中断时脚本要能容错不能因为一次网络闪断就把整个WinCC运行系统拖垮。4. 完整脚本实现从Access记录到WinCC变量的三个关键步骤4.1 第一步用ADODB打开连接并读取单条记录先写一个最小可用的脚本。以下代码放在WinCC全局脚本编辑器里用VBS编写周期触发1秒或者5秒都可以。它的目标很纯粹从Access读出最新一条工艺参数写进WinCC变量。 WinCC VBS 全局脚本从 Access 读取单条参数并写入 WinCC 变量 Option Explicit Dim strConn, strSQL Dim oConn, oRS Dim paramValue 连接字符串——无DSN方式直接指向Access文件 strConn ProviderMicrosoft.ACE.OLEDB.12.0; _ Data SourceC:\SCADA\param_db.accdb; _ Persist Security InfoFalse; SQL取设备编号对应的最新一条参数记录 strSQL SELECT TOP 1 ParamValue FROM RCP_Queue _ WHERE DeviceIDPLC01 _ ORDER BY UpdateTime DESC; Set oConn CreateObject(ADODB.Connection) Set oRS CreateObject(ADODB.Recordset) On Error Resume Next oConn.Open strConn If Err.Number 0 Then 连接失败时不做任何写操作保持旧值避免误动作 Err.Clear GoTo CleanUp End If oRS.Open strSQL, oConn, 3, 1 adOpenStatic3, adLockReadOnly1 If Not oRS.EOF Then paramValue oRS(ParamValue).Value 数值型参数必须显式转换后再写入防止字符串与数字类型冲突 If IsNumeric(paramValue) Then HMIRuntime.Tags(MixerTemp_SP).Write CDbl(paramValue) 写一个辅助变量标识数据源正常 HMIRuntime.Tags(MixerTemp_SP_Valid).Write 1 End If End If oRS.Close oConn.Close CleanUp: Set oRS Nothing Set oConn Nothing脚本逻辑分三段建立连接、查询数据、写变量。重点看oRS.Open那行的两个参数3代表adOpenStatic意思是在打开记录集时把所有数据一次性取到内存里适合这种小数据量查询1代表adLockReadOnly只读锁不会对Access表施加写锁不会干扰其他客户端。这两参数是工程上的安全选择。另外注意On Error Resume Next的用法。VBS默认遇到错误会弹出对话框并中断在WinCC后台脚本里这等于直接“漏掉”读写动作开启On Error Resume Next以后错误不会中断脚本统一通过Err.Number判断。每次分支结束后调用Err.Clear避免上一次的错误对象残留在Err里影响下一轮判断。4.2 第二步批量读取多个变量带上处理状态标记实际项目里很少只读一条数据而是一张表里放几十条配方参数每行对应一个WinCC变量。这时候要用循环批量处理同时标记Processed实现“读过就不再读”。下面这段脚本是生产现场我实际套路的一个简化版本 批量脚本把 RCP_Queue 表中未处理的行逐条写入 WinCC 变量 Dim strConn, strSQL, strUpdSQL Dim oConn, oRS Dim paramName, paramVal strConn ProviderMicrosoft.ACE.OLEDB.12.0; _ Data SourceC:\SCADA\param_db.accdb; strSQL SELECT TOP 50 ParamName, ParamValue, SeqID _ FROM RCP_Queue WHERE Processed0 ORDER BY SeqID; Set oConn CreateObject(ADODB.Connection) Set oRS CreateObject(ADODB.Recordset) On Error Resume Next oConn.Open strConn If Err.Number 0 Then Err.Clear GoTo CleanUp End If oRS.Open strSQL, oConn, 3, 1 Do While Not oRS.EOF paramName oRS(ParamName).Value paramVal oRS(ParamValue).Value 写入 WinCC 变量失败时记录错误但继续处理其他行 If IsNumeric(paramVal) Then HMIRuntime.Tags(paramName).Write CDbl(paramVal) End If 写入成功才把 Processed 置 1避免漏写 If Err.Number 0 Then strUpdSQL UPDATE RCP_Queue SET Processed1, _ UpdateTimeNow() WHERE SeqID oRS(SeqID).Value oConn.Execute strUpdSQL Else Err.Clear End If oRS.MoveNext Loop oRS.Close oConn.Close CleanUp: Set oRS Nothing Set oConn Nothing这里有两个工程价值很高的细节Processed字段让脚本不重复读同一行不会一遍遍把相同值写进WinCC变量只有写入成功才更新Processed某一行失败了下次周期还会再试。每周期限取50行防止一次性处理太多行导致脚本长时间占用系统资源。这个数字不是硬性规定取决于变量类型和画面刷新频率一般工艺参数20到50行都算合理。讲到这里必须提醒SQL里的字段名和WinCC变量名保持一致会让脚本显著简化。这张表的设计初衷正是如此ParamName对应WinCC变量管理器里的变量名不需要额外维护一张映射表。如果项目里变量名带前缀比如DB1_MixerTemp_SP只需让Access写入端遵循同样的命名规则就行。4.3 第三步失败重试与脚本退出保护批量脚本依然可能遇到个别变量写入失败比如WinCC变量被人误删、网络瞬断导致外部变量暂时不可写。如果脚本发现错误就直接退出剩余行就不处理了Perror很被动。更稳的做法是引用TryCount和LastTryTime字段让每行数据自己记录失败次数 写失败时累加 TryCount超过3次则强制标记处理完 If Err.Number 0 Then Err.Clear strUpdSQL UPDATE RCP_Queue SET TryCountTryCount1, _ LastTryTimeNow() WHERE SeqID oRS(SeqID).Value oConn.Execute strUpdSQL If oRS(TryCount).Value 3 Then strUpdSQL UPDATE RCP_Queue SET Processed1 WHERE SeqID oRS(SeqID).Value oConn.Execute strUpdSQL End If End If这段逻辑解决的实际问题现场即使出现单条坏数据脚本也不会反复卡在同一行TryCount字段里保留诊断信息事后打开Access就能看到哪一行写不进去、尝试了几次。超过3次就强制标记完成是为了避免脚本永远卡在一行数据上毕竟WinCC写变量的失败原因通常需要人工到服务器端排查脚本死磕没有意义。提示脚本最后一定要释放对象。Set oRS Nothing、Set oConn Nothing这两行看起来简单实际直接决定脚本长时间运行的稳定性。ADODB对象如果一直不释放内存会缓慢增长跑几天之后WinCC运行系统开始卡顿重启项目才好。5. 常见问题排查驱动、变量、类型和性能的五个踩坑记录5.1 现象连接Access报错“未找到提供程序”我去现场支援过好几次脚本写好了但一运行就报“未找到提供程序”或者“无法启动应用程序”数据库文件路径明明是对的拿Access手工打开也正常。这个问题的核心原因就三个字驱动不匹配。最常见的是64位Windows上安装了64位Office脚本以32位进程运行时找不到32位ACE驱动另一种是机器只装了Office但没装完整版Access缺少数据库引擎运行库。解决方法是先确认连接字符串用的驱动名称。如果是.accdb格式用ProviderMicrosoft.ACE.OLEDB.12.0机器上没有这个Provider就去微软官网下载Access Runtime安装如果运维要求不额外装软件可以考虑改用ODBC驱动用32位odbcad32.exe创建DSN后在脚本里配置DSN连接。这里有个矛盾装了64位Office再装32位Access Runtime容易冲突稳妥的办法是统一下载64位Access Runtime但WinCC脚本又是32位进程所以很多现场最终选择的方案是直接去掉Office只装Access Runtime彻底避免办公软件和驱动之间的版本战争。总之让驱动位数和WinCC进程位数保持一致是所有操作的前提。5.2 现象能连上库但WinCC变量只更新一次就不动了数据链路通了一半脚本第一次执行能写入正确值之后无论怎么改Access表里的数据WinCC画面上的变量都不变。我排查这个问题的顺序是先看全局脚本触发器有没有配置周期再看SQL是否始终返回同一行最后看变量有没有被其他画面对象锁定。触发器配置在WinCC全局脚本编辑器右侧的“触发器”栏里没配置周期就只会执行一次这是最常见的初级问题。SQL的问题更隐蔽如果查询语句没有ORDER BY UpdateTime DESCAccess返回行序往往就是主键顺序新增数据排在后面脚本每次拿到的还是第一行旧值。复制粘贴排错法是我的习惯把脚本里的SQL单独复制到Access查询设计器执行一遍看看返回的是不是最新数据这样很快就能判断问题是出在SQL还是出在写入环节。另外还有一种少见情况WinCC变量被画面上的小对象绑定并设置成“强制写入”变量的输入输出域权限设为只读也会让脚本Write看起来失败。这种问题靠变量报文查都查不出来需要逐个打开控件属性确认。5.3 现象脚本运行几小时后内存暴涨甚至崩溃WinCC运行状态看着正常但脚本进程占用的内存持续上升最后整个运行系统卡顿甚至自动退出。这是VBS脚本长期运行的典型病根ADODB的Connection和Recordset对象没有释放或者On Error Resume Next开启后Err对象没有及时Clear。这些对象和错误对象都属于COM资源没有释放时系统无法自动回收一直累积到系统崩溃。解决方法是每段脚本结束时调用oRS.Close、oConn.Close再把两个对象都置为Nothing循环内部每写完一次调用Err.Clear不让错误对象堆叠。还有一条工程纪律一个脚本生命周期内只创建一个Connection对象不要在循环里反复Set oConn CreateObject连接池不会帮你复用Access连接反复创建只会加速资源泄漏。这条听上去基础实际现场一半的脚本稳定性问题都能归到对象释放上。5.4 现象数据量大时读库变慢WinCC画面卡顿Access表里数据超过几千行之后脚本每次执行要一两秒画面刷新出现明显卡顿。根本原因是Access是文件型数据库没有好的索引时全表扫描非常低效再加上脚本在循环里反复开关连接以及SELECT了根本用不到的字段。解决办法有四条第一在SeqID、Processed、UpdateTime上建立索引为WHERE条件铺路第二SQL里只写要用的字段不要SELECT *哪怕一张只有五列表显式写字段也比通配符快第三把读取结果先暂存在VBS数组里再统一写WinCC变量而不是每写一个变量就查一次表第四拉长脚本触发周期大多数工艺参数5秒读一次足够别让WinCC每秒钟都访问数据库。要注意的是Access的连接数有限不要把数据库放在机械硬盘的旧工控机上读取慢往往有几分是磁盘IO瓶颈。有条件的话换成SSD效果立竿见影。5.5 现象写入的WinCC变量被下位机“拉回去”脚本写进去的值没保持多久画面一闪又恢复成PLC那边的旧值看起来就像“写不进去”。这种现象在引用外部变量时经常发生外部变量的最终值由上位机通讯和PLC循环扫描共同决定WinCC侧的Write操作只是一次性写入下一轮通讯刷新到来时变量值就被拉回到PLC输出值了。解决思路不是和PLC硬抢而是先分清变量用途。如果只是给画面显示和报表用写内部变量最省事内部变量不受PLC通讯影响如果确实要写外部变量必须和PLC程序约定写窗口例如某个存储器地址专门供WinCC写入PLC在同一周期读这个地址而不回写相同地址。这类问题的本质是变量规划不清晰动工前把内部变量、外部变量、中间变量分好类脚本逻辑会简单很多。6. 让这套“Access读库写变量”方案长期稳定的四个进阶技巧如果打算把这套方案长期用在产线上我建议在基础脚本之上再补四件事这四件事我后期项目基本固定会用效果很稳。第一件在Access库里建一张Meta表保存参数版本号或者全局LastChanged时间戳。脚本每次执行先读Meta表里的版本号和上一次缓存的值比较没有变化就跳过全部读写操作。这里的工作量很小但能大幅减少数据库IO和变量刷新频率画面上的数值也不会因为反复赋值而闪跳。尤其是配方数据一天只改几次的场景这是从“周期轮询”变成“变更驱动”的最省力办法。第二件使用WinCC内部变量做链路健康监测。脚本每次成功读库除了写工艺参数同时把当前时间写入一个内部变量比如DB_Link_LastOK画面组态里放一个文本块引用这个变量并加上颜色变化逻辑。一旦Access文件被误改、路径被移动、数据库被占用操作员能在画面上立刻看到“链路中断”提示而不是等到数据异常了才开始排查。这个技巧的成本几乎为零回报是省下大量现场沟通时间。第三件定期压缩修复Access数据库。Access文件长时间插入、更新、删除后会产生碎片文件越膨胀查询越慢。我的习惯是每月一次停脚本压缩修复。停脚本可以用Windows计划任务调用WinCC的实例控制命令行手工做也行压缩前一定要确认没有脚本正占用着Access文件否则压缩直接失败。压缩后把数据库文件备份到另一个磁盘出问题时能快速回滚。第四件把验证步骤标准化。每次更改数据库结构或脚本逻辑后先在Access手工UPDATE一行记录把ParamValue改成固定值123.4然后观察WinCC画面变量在下一个周期是否变成123.4最后恢复原值。这个动作前后两分钟但能快速区分“脚本没执行”“读取失败”“写入被覆盖”三种故障比拿着万用表测半天串口实在得多。以上这些技巧做完Access数据库数据写入WinCC变量这套方案才算从“能跑”变成“长期稳定”。我最深的教训是千万别急着写脚本先花半小时把表结构、变量命名、驱动位数、脚本对象释放这些问题设计清楚后面能少熬好几个夜。希望这篇文章能帮你在现场少踩几个坑。本文还有配套的精品资源点击获取
返回列表