ARTICLE DETAIL

资讯详情

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

Access数据库数据写入WinCC变量:VBS脚本+ODBC实战

Access数据库数据写入WinCC变量:VBS脚本+ODBC实战 简介这是一份面向工业自动化与组态软件应用场景的PDF技术资料围绕考试及工程实践需要讲解如何通过VBS脚本将Access数据库表中的数据写入西门子WinCC变量从而实现数据实时监控与处理。文档从建立Wincc_Data数据库及数据表入手逐项说明ODBC数据源Sample的配置方法并给出完整VBS代码涵盖ADODB连接、SQL查询、记录集遍历、HMIRuntime.Tags写入、对象释放等关键环节可用于快速掌握数据库与WinCC变量交互的完整流程。压缩包内仅含1个PDF文件大小约18KB轻量集中便于下载后直接查阅特别适合需要快速补强WinCC数据接口知识的初学者、相关工程师或备考人员。目前已有342人浏览学习内容重点突出既有可直接复用的脚本思路也包含建库、建表、ODBC配置等排错提示对完成类似数采或组态联动任务具有直接参考价值。1. Access 数据进 WinCC一条考试记录如何变成画面里的变量实操考试和技能考核现场经常遇到这种需求考生成绩、题库参数或批次记录存在 Access 数据库里而监控画面用的是 WinCC要把数据库里的某一条记录实时显示出来或者弹窗提示当前考生的分数。Access 数据库数据写入 WinCC 变量最容易走弯路的做法是去折腾 DDE、OPC 或者 C 脚本直连 SQL其实在 WinCC 里用 VBS 脚本配合 ADODB 和 ODBC 是最轻的一条通路。这份资源给的正是这个典型链路建一个名为 Wincc_Data 的 Access 数据库表中放五个 Tag 字段配置一个叫 Sample 的 ODBC 数据源再用十几行 VBS 把 ID50 那条记录的 Tag1 值写入画面变量 U16Tag1。适合已经在用 WinCC 做画面、但数据库交互还不太熟的工程师也适合备考工业自动化相关考试的学员照着敲一遍理解变量写入机制。2. 先打通数据源Access 表结构、ODBC 数据源与连接字符串三个前提2.1 数据表怎么建五个 Tag 字段和一个容易被忽略的 ID 列我在 Access 2016 里建库时步骤很简单新建数据库命名保存为 Wincc_Data.accdb然后在“创建 → 表设计”里加字段。正文里列了五个字段 Tag1、Tag2、Tag3、Tag4、Tag5但看到后面那句select Tag1 from WINCC_DATA where ID 50你就知道这个表里其实还隐含了一个 ID 字段。Access 里最省事的做法是直接加一列“自动编号”主键列名默认就是 ID这样 where 条件才能成立。字段名类型用途ID自动编号主键定位第几条记录Tag1数字 - 整型源数据准备写入 WinCC 变量 U16Tag1Tag2数字 - 整型备用扩展字段Tag3数字 - 整型备用扩展字段Tag4数字 - 整型备用扩展字段Tag5数字 - 整型备用扩展字段这里有一个新手必踩的坑如果只建五个 Tag 字段不建 ID 列SQL 查询一执行就会报“未找到字段 ID”。另外 Tag1 的类型我一般直接选整型不要用文本。原因是 U16Tag1 是 16 位无符号变量范围只有 0~65535文本字段读出来是字符串写入时要经历隐式转换一旦内容带空格或非数字字符写入就会失败。建表时顺手把所有 Tag 字段都设成“数字 - 整型”后面少折腾很久。建完表后建议手动插入 50 条以上测试数据确保 ID50 这条记录真实存在。2.2 ODBC 数据源配置32 位与 64 位选错是白忙ODBC 是微软定义的数据库访问接口标准它的作用是把 Access 数据库的读写能力暴露给外部程序。WinCC 里的 VBS 脚本本身并不能直接打开 Access 文件必须先经过 ODBC 数据源做桥接。常见的翻车点不在脚本而在 ODBC 管理器版本选错。WinCC 7.x 的脚本引擎是 32 位进程而 Windows 10/11 默认打开的 ODBC 管理器是 64 位。你在 64 位管理器里建好数据源 Sample32 位的 WinCC 脚本运行时照样找不到。# 64 位 ODBC 管理器位置 %SystemRoot%\System32\odbcad32.exe # 32 位 ODBC 管理器位置WinCC 必须用这个 %SystemRoot%\SysWOW64\odbcad32.exe正确操作是 WinR 直接运行%SystemRoot%\SysWOW64\odbcad32.exe打开后切到“系统 DSN”页签点添加选择 Microsoft Access Driver (*.mdb, *.accdb)。如果列表里找不到这个驱动说明机器上没装 Microsoft Access Database Engine 可再发行组件去官网下载对应版本装好再回来刷新。数据源名称必须填 Sample不能带空格然后浏览选择刚才的 Wincc_Data.accdb。这里我用系统 DSN 而不是用户 DSN是为了避免 WinCC 以服务或另一个 Windows 账户启动时读不到用户级数据源这条血泪经验后面细说。2.3 连接字符串拆解ProviderMSDASQL 为什么这样写正文里的连接字符串只有一行但每一项都不是摆设参数作用ProviderMSDASQL指定使用微软的 OLE DB Provider for ODBC让 ADODB 能通过 ODBC 访问 AccessDSNSample告诉程序去系统或用户数据源中找名为 Sample 的 ODBC 配置UID;PWD用户名和密码Access 默认不设账户所以留空有人会问能不能不用 DSN直接在连接字符串里写数据库路径可以。部署到别的电脑时免 DSN 连接更省事不用每台机器都重建 ODBC。常见写法是Driver{Microsoft Access Driver (*.mdb, *.accdb)};DbqC:\path\Wincc_Data.accdb;。我一般建议第一次调试先用 DSN 方式因为报错信息更直观等逻辑跑通了再决定要不要改成免 DSN。连接字符串里每个分号都必须保留少一个分号 ADODB 就解析失败这一点在从 PDF 复制代码时特别容易丢。3. VBS 脚本逐段拆解连接、查询与写入 U16Tag1 的完整写法3.1 完整脚本从连接、查询到写入的逐段对照下面这段代码就是正文资源的完整实现我加了中文注释方便对照 声明对象和变量 Dim objConnection Dim objCommand Dim objRecordset Dim strConnectionString Dim strSQL Dim lngValue Dim lngCount 1. ODBC 连接字符串 strConnectionString ProviderMSDASQL;DSNSample;UID;PWD; 2. SQL 查询从 WINCC_DATA 表中取 ID 为 50 的记录 strSQL select Tag1 from WINCC_DATA where ID 50 3. 创建连接对象并打开 Set objConnection CreateObject(ADODB.Connection) objConnection.ConnectionString strConnectionString objConnection.Open 4. 创建命令对象绑定连接并执行查询 Set objCommand CreateObject(ADODB.Command) objCommand.ActiveConnection objConnection objCommand.CommandText strSQL Set objRecordset objCommand.Execute 5. 判断记录集是否有返回字段 lngCount objRecordset.Fields.Count If (lngCount 0) Then objRecordset.MoveFirst 游标移到第一条记录 lngValue objRecordset.Fields(0).Value 取第一个字段的值 HMIRuntime.Tags(U16Tag1).Write lngValue 写入 WinCC 变量 Else HMIRuntime.Trace Selection returned no fields vbNewLine End If 6. 按顺序释放对象和连接 Set objCommand Nothing objConnection.Close Set objRecordset Nothing Set objConnection Nothing逻辑上分三段理解。第一段是连接三件套Connection 负责建立通道Command 负责承载 SQLRecordset 负责接收查询结果。第二段是关键判断lngCount拿到的是字段数量而非记录数量这里用它判断查询是否成功返回数据。第三段是收尾顺序先释放 Command再关闭 Connection最后清空 Recordset 引用顺序不能反否则连接会一直占着数据库文件。参数说明里最值得留意的是Fields(0)它表示取当前记录的第一个字段。查询语句是select Tag1所以下标 0 就是 Tag1。如果 SQL 改成select Tag2, Tag1那Fields(0)就变成 Tag2 了取值会跟着 select 顺序走。另外HMIRuntime.Tags(U16Tag1)这个对象是 WinCC 运行环境的全局入口变量名必须和变量管理里完全一致大小写倒是不敏感但引号里的名字写错一个字母脚本运行时会直接报“未找到标签”。3.2 脚本放在哪里全局脚本动作、画面事件与周期触发同样的脚本放在不同位置行为完全不同。最常见的两种落点一是 WinCC 的 Global Script 动作通过触发器按周期执行适合周期性把数据库最新记录刷到变量上二是画面里按钮的鼠标事件比如考试开始时点一下按钮加载当前考生成绩这种单次触发更适合现场人工操作。我一般这样配周期触发在 Global Script 里新建动作把上面的代码贴进去然后打开动作属性设置触发器选“周期”并在下方填入执行间隔。注意周期不要小于 1 秒否则每次扫描周期都要新建数据库连接Access 单机文件访问扛不住高频读写。更稳的做法是让脚本判断“数据是否变化”再决定要不要写变量比如比较数据库里记录的时间戳和上次读取的时间戳。如果是画面按钮触发脚本写法完全一样只是不需要配置触发器运行到按钮事件时执行一次就结束。这里还有个新手常犯的错误直接点 WinCC 的 VBS 编辑器里“测试运行”按钮弹出窗口里报语法错误就以为脚本有问题。实际上 WinCC 对 VBS 的编译环境和外部的 cscript 有细微差异我在下一章专门讲验证方法时会给一个脱离 WinCC 也能试跑的小技巧。4. 避坑记录ODBC、Recordset 与 WinCC 侧五个高频现场4.1 现象objConnection.Open 报 80004005提示找不到 DSN脚本运行到objConnection.Open直接弹错误对话框错误码是 80004005提示信息通常带“未找到数据源名称并且未指定默认驱动程序”。原因基本就是 ODBC 管理器版本选错了WinCC 的 32 位进程到 64 位 ODBC 注册表里找 Sample自然找不到。还有一种情况是 DSN 建成了用户 DSNWinCC 运行服务用的 Windows 账户和建 DSN 的账户不是同一个。解决方法是先在任务管理器里确认 WinCC 进程位数再用 32 位管理器重建系统 DSN并且数据源名称严格填 Sample前后不要多加空格。如果装了 Access 驱动还是看不到驱动列表检查系统里是否残留多个版本的 Microsoft Access Database Engine把 32 位和 64 位混装也会导致驱动列表异常。4.2 现象SQL 不报错但 lngCount 恒为 0连接没问题脚本执行到 If 判断时走了 Else 分支Trace 打印出 Selection returned no fields。最直接的原因是 ID50 这条记录根本不存在表里只有十几条数据Access 的自动编号未必连续删过记录后 ID 可能从 49 直接跳到 51。另一个常见原因是表名和字段名匹配问题SQL 里写的WINCC_DATA和实际保存的表名不一致Access 对大小写不敏感但对空格和下划线敏感。解决方法是先在 Access 里用“创建 → 查询设计 → SQL 视图”直接运行一遍select Tag1 from WINCC_DATA where ID 50确认能返回一行再回 WinCC 调试。如果 Access 里也查不到就加一条测试记录把 ID50 补齐或者改 SQL 里的条件为where ID 1先验证通路。4.3 现象写入不报错但画面上 U16Tag1 的值纹丝不动这是最迷惑人的一种情况脚本正常执行Trace 里也打印出了读到的值但画面上绑定的 U16Tag1 就是不变或者变成 0、变成负数。原因通常有两个方向。第一HMIRuntime.Tags(U16Tag1).Write是异步写写入动作提交给 WinCC 运行系统后立即返回画面刷新有延迟要等一个周期才能看到。第二写入值超出 U16Tag1 的范围U16 是无符号 16 位整型合法范围 0~65535如果 Tag1 字段里存了负数或超过 65535 的数写入会被拒绝而且不报错。第三是 Tag1 字段类型为文本读出来是字符串隐式转换失败。解决方法是写之前用CLng显式转换并先做一个范围检查If IsNumeric(objRecordset.Fields(0).Value) Then lngValue CLng(objRecordset.Fields(0).Value) If lngValue 0 And lngValue 65535 Then HMIRuntime.Tags(U16Tag1).Write lngValue End If End If这类“写入不报错但画面没反应”的问题靠看代码是看不出来的必须回读或加 Trace我习惯把这种问题划成玄学类问题后面第六章给完整的验证套路。4.4 现象WinCC 编译 VBS 报“语句未结束”或语法错误从 PDF 或网页复制代码到 WinCC 脚本编辑器时最容易出现引号变成中文引号、全角分号、多余换行这类肉眼难察觉的问题。VBScript 对语法要求严格If 必须有配对的 End If字符串必须用英文双引号包裹一行写不下要续行时要在行尾加下划线_。如果代码里出现类似HMIRuntime.Trace xxx ·不要硬背语法先把代码在纯文本编辑器里重新敲一遍引号再粘贴进 WinCC。本地验证的快捷方式是另存为 .vbs 文件把HMIRuntime.Tags(U16Tag1).Write lngValue这一行替换成WScript.Echo lngValue然后在命令行用 cscript 跑一遍能过说明语法没问题再把写变量的那句换回去贴进 WinCC。4.5 现象连接 Access 时提示文件正被使用或无法独占打开Access 是文件型数据库默认打开方式偏独占。如果你在电脑上开着 Access 窗口查看 Wincc_Data.accdb同时脚本又去连接就会报“文件正在使用中”或“无法打开因为另一个用户已将其锁定”。另一个常见源头是上次脚本异常退出Access 进程没释放任务管理器里还挂着 MSACCESS.EXE。解决方法是先关闭所有 Access 窗口任务管理器结束残留进程然后在 ODBC 数据源配置里把“独占”选项取消勾选。代码层面也可以在连接字符串里追加ModeRead|Share Deny None允许共享只读访问strConnectionString ProviderMSDASQL;DSNSample;UID;PWD;ModeRead|Share Deny None;加了这个参数后即使数据库文件被其他程序打开脚本也能以只读方式读取数据适合生产环境里数据库文件由第三方软件维护的场景。5. 扩展写法循环批量、多字段映射与参数化查询防注入5.1 批量读写把第 50 条改造成 ID 区间循环实际项目不会只读一条记录。考试系统里可能有几百个考生的成绩要分层推送设备参数有几十个批次要逐一加载。这种场景把单条查询改成循环即可用Do While配合MoveNext遍历记录集strSQL select ID, Tag1, Tag2 from WINCC_DATA where ID between 1 and 100 order by ID Set objRecordset objCommand.Execute objRecordset.MoveFirst Do While Not objRecordset.EOF lngValue CLng(objRecordset.Fields(Tag1).Value) HMIRuntime.Tags(U16Tag1).Write lngValue objRecordset.MoveNext Loop这里要注意objRecordset.EOF是记录集结束标志每次循环末尾必须MoveNext否则会造成死循环。循环内每次Write都是异步写如果两次写入的间隔小于 WinCC 画面刷新周期画面上看到的可能是跳变后的最终值中间过程值丢失。我一般建议循环里只做最大值和最小值的写入或者配合 WinCC 的变量归档做趋势记录不要指望画面逐条显示。批量读取时也不要一次把整表拉回来数据量大时用where ID between 1 and 100做分页过滤给 Access 减负。5.2 多字段映射把 Tag1~Tag5 同时写入多个 WinCC 变量正文只写了 Tag1 到 U16Tag1实际画面经常需要一次更新五个变量。这时可以直接按字段名取值顺序清晰、不容易因为 select 调整列而错位strSQL select Tag1, Tag2, Tag3, Tag4, Tag5 from WINCC_DATA where ID 50 Set objRecordset objCommand.Execute objRecordset.MoveFirst HMIRuntime.Tags(U16Tag1).Write CLng(objRecordset.Fields(Tag1).Value) HMIRuntime.Tags(U16Tag2).Write CLng(objRecordset.Fields(Tag2).Value) HMIRuntime.Tags(U16Tag3).Write CLng(objRecordset.Fields(Tag3).Value) HMIRuntime.Tags(U16Tag4).Write CLng(objRecordset.Fields(Tag4).Value) HMIRuntime.Tags(U16Tag5).Write CLng(objRecordset.Fields(Tag5).Value)如果你用Fields(0)这种下标方式一旦 select 里加了其他列比如改成select ID, Tag1, Tag2, ...下标就整体错一位写进 WinCC 变量的值会串。所以字段较多时优先用Fields(字段名)代码稍微啰嗦一点但排查时一眼能看出谁对应谁。目标变量名写错一个字母HMIRuntime.Tags 对象会返回空引用VBS 里直接报错建议把这些变量名集中定义成常量放在脚本开头方便维护。5.3 参数化查询用户输入拼 SQL 的注入风险怎么防当 SQL 条件来自画面输入框时比如用户输入考号或设备编号直接拼字符串会引入一个经典安全隐患。很多人图省事写成这样strSQL select * from WINCC_DATA where TagName userInput 如果 userInput 里包含单引号和分号这条 SQL 就可能被恶意构造这正是常说的 access 注入场景。Access 虽然是单机文件数据库但 JET/ACE 引擎一样会执行拼接后的 SQL足以把成绩记录改掉或整表删除。安全做法是用 ADODB.Command 的参数化查询让引擎把输入当参数而不是 SQL 语句Set objCommand CreateObject(ADODB.Command) objCommand.ActiveConnection objConnection objCommand.CommandText select * from WINCC_DATA where TagName ? objCommand.Parameters.Append objCommand.CreateParameter(p1, 202, 1, 50, strSearch) Set objRecordset objCommand.ExecuteCreateParameter的四个参数里202 表示字符串类型1 表示输入参数50 是最大长度strSearch 是画面传进来的实际值。通过问号占位符绑定参数后即使用户输入单引号或11这类攻击载荷也只会被当作普通字符串去匹配字段值。这个写法比拼 SQL 多三行但生产环境必用。6. 验证这件事Trace 输出、回读与画面联动三步确认脚本写完不等于数据进了变量我每次都会按三个步骤验证少一步都可能在现场翻车。第一步是在脚本里插入 HMIRuntime.Trace 输出把读到的数据库值和写入动作分开打印lngValue CLng(objRecordset.Fields(Tag1).Value) HMIRuntime.Trace read from db: lngValue vbNewLine If HMIRuntime.Tags(U16Tag1).Write lngValue Then HMIRuntime.Trace write ok vbNewLine Else HMIRuntime.Trace write fail vbNewLine End IfWinCC 里 Trace 的输出会显示在诊断窗口或消息队列里能看到 read 和 write 两行。这里有个细节Write的返回值在不同 WinCC 版本里语义有差异有的返回布尔值有的返回 0 或非 0 整数不能绝对依赖它判断成功。第二步是写完之后立刻回读变量lngReadBack HMIRuntime.Tags(U16Tag1).Read HMIRuntime.Trace readback: lngReadBack vbNewLine回读值和写入值一致才能确认变量确实被更新了。注意异步写完成后立刻回读可能读到旧值最好在 Trace 里输出后加一句WScript.Sleep 200或在画面刷新一个周期后再验证。第三步是画面联动。在图形编辑器里放一个 I/O 域连接 U16Tag1运行 WinCC 后观察这个域显示的数值。如果是考试系统把考生姓名、成绩分别映射到多个变量画面就能形成完整的记录展示。也可以通过一个内部布尔变量做“读取成功”信号截图时能直观看到状态翻转。有一回现场调试脚本里 Trace 一直打印 write ok画面上却纹丝不动折腾两小时才发现 U16Tag1 这个变量同时被 PLC 侧周期刷新覆盖了数据库写入的值下一秒就被外部值顶掉。从那以后我每次做数据库写变量都强制走一遍“先在 Access 里跑 SQL、再 Trace 看值、最后回读比对”这三步任何一步不对就直接分屏查证不再凭感觉猜。希望帮到你。本文还有配套的精品资源点击获取
返回列表