简介:面向SCADA系统工程师与Intouch组态开发者的实操文档,聚焦WonderWare Intouch 2014R2与SQL Server 2012数据库集成及Excel报表系统搭建这一常见工程需求,适合具备一定HMI基础、需要打通数据存储与报表输出链路的中级技术人员参考。资源包共1个doc文件,约2.48MB,以图文步骤形式组织内容,涵盖数据库登录方式与权限配置、新建库表、标记名字典中连接状态与时间变量的建立、SQL访问管理器绑定列表、SQLConnect与SQLDisconnect脚本编写,以及Excel报表模板与VBA引用设置、数据库文件附加恢复等环节。已有533人学习下载,读者可据此对照完成从数据写入、定时触发到报表呈现的完整流程,并掌握连接字符串参数含义与常见配置要点,减少现场调试中的反复试错。
1. 从一次“数据对不上”的夜班说起:Intouch 写库与 Excel 报表这套方案到底解决什么
凌晨两点,某水厂中控室的运行人员发现,白天班报里 8 点整的出水浊度比现场仪表历史曲线高出一截,值班人员翻遍 Intouch 画面也找不到原因——数据在画面上是好的,落到数据库里却对不上。这类问题在 SCADA 项目里非常典型:HMI 画面跑得好好的,一到“数据落库 + 报表出数”这一段就出岔子。这套方案要解决的正是这条链路:在 WonderWare Intouch 2014 R2(IDE 平台)里把实时数据稳定写入 SQL Server 2012,再用 Excel 报表系统把库里的历史数据取出来形成日报、参数报表,同时把数据库的备份与恢复流程固定下来。它适合正在做 SCADA 课程设计、工控毕设,或者要交付一套中小型监控系统数据存贮方案的人。下面按“库怎么建、数据怎么写、报表怎么出、库怎么恢复、怎么验收”的顺序,把每一步的设计取舍和可复现操作讲清楚。
2. 数据库与连接的前置设计:从登录方式到标记字典的完整准备
很多人一上来就写SQLConnect,结果连不上就开始怀疑驱动、怀疑网络,其实八成问题出在数据库这一侧没准备好。这一章把“写库之前必须落地的东西”一次讲完:数据库实例的认证方式、专用登录名、业务表结构,以及 Intouch 侧那几个专门为连接服务的内部标记。顺序不能乱,乱了后面全是玄学。
2.1 认证方式与登录名:先把门打开
进入 SQL Server Management Studio,在实例上右键打开“属性”,左侧选“安全性”,右侧服务器身份验证选“SQL Server 和 Windows 身份验证模式”。这一步的意义在于:Intouch 的 SQL 函数走的是 SQL 身份验证,如果实例只开了 Windows 验证,SQLConnect会直接返回失败,而且失败信息很含糊,容易让人误判成连接字符串写错。
改完认证方式必须重启 SQL Server 服务才生效,这是血泪经验里最常见的一条。重启后在“安全性 → 登录名”上右键“新建登录名”,建一个专供 SCADA 使用的账号,比如scada_user,设置密码并取消“强制密码过期”,服务器角色至少给public,数据库映射里给它目标库的db_datareader和db_datawriter。不建议直接用sa跑生产,虽然文档示例里常这么写,但一旦密码泄露,整个实例都暴露了。
提示:改完认证模式后如果 SSMS 还能用 Windows 身份进,但 Intouch 连不上,先确认服务是否真的重启过,再看该登录名是否被禁用。
2.2 业务表结构:列名和类型要和绑定列表一一对上
建库之后建表,表结构不是随便定的,它必须和 Intouch 绑定列表里的变量严格对应。以一张按日汇总的参数表为例,通常的做法是这样:
-- 按日参数汇总表,列名与 Intouch 绑定列表变量名保持一致 CREATE TABLE TDays ( RecTime DATETIME NOT NULL, -- 记录时间,对应 Intouch 的 GetDateTimeS NodeName VARCHAR(32) NOT NULL, -- 采集站计算机名,对应 NodeName OutTurb FLOAT NULL, -- 出水浊度 OutPH FLOAT NULL, -- 出水 PH OutCl FLOAT NULL -- 出水余氯 );这里有两个设计点值得说清楚。第一,RecTime用DATETIME而不是字符串,方便 Excel 侧按时间筛选和排序;第二,NodeName保留下来,多站点共用一个库时靠它区分数据来源,后面 Excel 报表按站点过滤就靠这一列。列名大小写不敏感,但拼写必须和绑定列表完全一致,差一个字母SQLInsert就会报“无效的列名”。
2.3 Intouch 侧的内部标记:连接状态、时间与站名
在 Intouch 的“标记名字典”里,先建三个不参与画面显示、只服务于写库逻辑的内存标记:
| 标记名 | 类型 | 用途 |
|---|---|---|
| Connid1 | 内存整型 | 保存SQLConnect返回的连接号 |
| GetDateTimeS | 内存消息 | 保存写库时刻的时间字符串 |
| NodeName | 内存消息 | 保存本机计算机名,用于多站判断 |
| WSQLS | 内存离散 | 写库完成标志,防止同一周期重复写入 |
Connid1是整型而不是消息型,因为SQLConnect的第一个参数要求是整型连接号;GetDateTimeS和NodeName用消息型(字符串),因为GetNodeName和格式化时间都输出字符串。WSQLS这个离散标记是整个写库逻辑的“后悔药”——没有它,条件脚本每个扫描周期都可能触发一次插入,一分钟能给你灌进去几十条重复记录。
2.4 绑定列表:变量与列的映射关系
打开左侧工具视图里的 SQL 访问管理器,进入“绑定列表”,新建一个名为TDays的绑定列表(名字和数据库表名一致,便于记忆),把要记录的 Intouch 变量逐个加进去,每个变量指定对应的数据库列名和数据类型。绑定列表本质是一张映射表:Intouch 变量名 → 表列名,变量类型 → 列类型。FLOAT列对应实型变量,DATETIME列对应消息型的时间字符串,VARCHAR对应消息型。映射错位的典型表现是插入成功但数值全是 0 或者乱码,排查时先看绑定列表,再看表结构,最后才怀疑脚本。
3. 写库脚本的落地实现:连接、条件触发与防重复写入
数据库和标记准备好之后,真正决定数据质量的是一段几十行的脚本。这段脚本要处理四件事:什么时候连、连上之后什么时候写、写完怎么防止重复、程序退出怎么收尾。很多课程设计只写了SQLInsert那一行,答辩时被问“重复写入怎么办”“断连怎么办”就答不上来,问题都出在这一章。
3.1 连接与断开:成对出现才安全
在“脚本 → 应用程序”里,应用程序脚本的“启动时”或某个条件脚本中建立连接:
' 建立数据库连接,连接号存入 Connid1 SQLConnect(Connid1, "provider=sqloledb;Data Source=OP_01;Initial Catalog=YADC_BB;UserID=scada_user;Password=******");连接字符串五个部分逐个解释:provider=sqloledb指定用 SQL Server 的 OLE DB 提供程序;Data Source是数据库所在计算机名或实例名,单机部署就写本机名;Initial Catalog是数据库名;UserID和Password是 2.1 节建的专用账号。这里最容易翻车的是Data Source写成 IP 而目标机没开 TCP/IP 协议,或者写成实例名却漏了反斜杠,表现都是连接超时。
连接必须配对断开,在应用程序脚本的“关闭时”里加:
' 程序退出时释放连接,避免连接句柄泄漏 SQLDisconnect(Connid1);不断开的后果在调试期看不出来,运行几天后数据库连接数打满,新连接全部失败,现场表现为“昨天还好好的,今天突然不写库了”。
3.2 条件脚本:用系统秒做触发节拍
Intouch 的条件脚本挂在“条件”视图下,靠系统变量驱动。原文用的是$Second==3和$Second==5两个节拍,这个思路是对的:$Second每秒变化一次,等于某个值时触发一次,天然形成周期任务。写库脚本一般放在$Second==5这个条件上,逻辑如下:
' 条件:$Second==5,条件类型:为真时 GetNodeName(NodeName, 131); ' 取本机名,131 为名称长度上限 IF NodeName == "OP_01" THEN ' 只允许采集站写库,避免多站重复 IF $Minute >= 58 THEN ' 每小时最后两分钟才执行汇总写入 IF WSQLS == 0 THEN ' 本周期尚未写入 GetDateTimeS = $Date + " " + $Time; ' 组装写库时间 SQLInsert(Connid1, "TDays", "TDays"); ' 表名, 绑定列表名 WSQLS = 1; ' 置位,标记已写 ENDIF; ENDIF; ENDIF;逐行说明设计意图。GetNodeName的第二个参数是缓冲区长度,131 足够容纳常规计算机名;NodeName == "OP_01"这层判断解决的是多台上位机同时运行同一套程序时的重复写库问题,只有指定的采集站有写权限。$Minute >= 58是业务节拍,按小时汇总的场景下在整点前两分钟落一次数,具体阈值按报表粒度改,做日报就改成$Hour==23 AND $Minute>=58。WSQLS的判断和置位是防重复的核心,没有它,58 分和 59 分两个整分钟里脚本会各触发一次,一天下来多出一倍的重复行。
3.3 标志复位:把“后悔药”留到下一个周期
WSQLS置位之后必须复位,否则第二天永远不会再写。复位的时机有讲究:不能在同一个条件脚本里紧接着复位,那样等于没防重复;通常的做法是放在另一个条件上,比如$Second==10时执行WSQLS = 0;,或者放在整点过后的第一个扫描周期。原文里置位和复位写在同一个脚本块中,实际调试时会发现防重复失效,这是需要修正的地方。我一般把复位单独挂一个条件,并在注释里写清楚“复位必须晚于写入至少一个节拍”。
3.4 时间格式:写库前先统一系统格式
原文专门提到在操作系统“日期和时间”里改格式,这不是多余步骤。Intouch 的$Date输出格式跟随系统区域设置,如果系统是“yyyy/M/d”而数据库期望“yyyy-MM-dd”,插入DATETIME列时可能解析失败或错位。稳妥的做法是把系统短日期格式统一为yyyy-MM-dd,时间统一为HH:mm:ss,或者在脚本里用StringMid、StringReplace手工拼装标准格式再赋值给GetDateTimeS。这一步在单机上改一次就行,但部署到多台机器时每台都要改,漏一台就多一个数据异常源。
4. Excel 报表系统的搭建:模板、VBA 引用与取数逻辑
数据进了库,接下来是把它变成运行人员看得懂的报表。Excel 在这里扮演的是“轻量报表客户端”的角色:不额外买报表软件,用 Excel 的 VBA 直连 SQL Server 取数,按模板排版输出。这套做法在中小型 SCADA 项目里性价比很高,代价是要把模板和宏维护好。
4.1 模板结构:控制面板 + 参数日报双页设计
报表工作簿通常分两个工作表。“控制面板”页放查询条件:起始日期、结束日期、站点选择,用单元格做输入,旁边放一个“生成报表”按钮绑定宏。“参数日报”页是输出页,表头固定,数据区按日期逐行填充。这种双页结构的好处是查询参数和展示内容分离,运行人员只碰控制面板,不会误改报表格式。模板建好后另存为.xlsm启用宏的格式,普通.xlsx存不住 VBA 代码。
4.2 VBA 引用:三项必须勾选
打开 VBA 编辑器(Alt+F11),在“工具 → 引用”里至少勾选三项:Visual Basic For Applications、Microsoft Excel 16.0 Object Library、Microsoft ActiveX Data Objects 6.1 Library。第三项是 ADO 取数的核心,漏勾的话代码里ADODB.Connection直接报“用户定义类型未定义”。版本号随 Office 安装不同会有差异,选本机可用的最高版本即可,不必强求 6.1。
4.3 取数代码:参数化查询避免拼接
' 按日期区间从 SQL Server 取日报数据 Sub LoadDailyReport() Dim conn As ADODB.Connection Dim rs As ADODB.Recordset Dim sql As String Dim d1 As String, d2 As String d1 = Sheets("控制面板").Range("B2").Value ' 起始日期 d2 = Sheets("控制面板").Range("B3").Value ' 结束日期 Set conn = New ADODB.Connection ' 连接字符串与 Intouch 侧保持同一账号体系 conn.ConnectionString = "Provider=SQLOLEDB;Data Source=OP_01;" & _ "Initial Catalog=YADC_BB;User ID=scada_user;Password=******;" conn.Open sql = "SELECT RecTime, NodeName, OutTurb, OutPH, OutCl FROM TDays " & _ "WHERE RecTime BETWEEN ? AND ? ORDER BY RecTime" Set rs = New ADODB.Recordset ' 用参数占位,避免日期字符串拼接导致的格式错误 rs.Open sql, conn, adOpenStatic, adLockReadOnly, adCmdText ' 实际执行时通过 Command 对象传参,此处示意查询结构 Sheets("参数日报").Range("A5").CopyFromRecordset rs rs.Close: conn.Close Set rs = Nothing: Set conn = Nothing End Sub这段代码的关键设计有三处。第一,连接字符串和 Intouch 侧用同一个账号,权限模型统一,不用维护两套密码。第二,查询用BETWEEN ? AND ?占位而不是把日期拼进 SQL 字符串,拼接写法在日期格式变化时会静默返回空结果,占位参数则直接报类型错误,问题暴露得更早。第三,CopyFromRecordset一次性把结果集灌进单元格区域,比逐行循环快一个数量级,几千行日报秒级完成。实际落地时把占位参数换成ADODB.Command加CreateParameter传值,代码略长但更稳。
4.4 报表刷新节拍与数据一致性
报表不需要像画面那样秒级刷新,通常按班次或按日生成。如果要做“准实时”报表,刷新间隔不要低于写库节拍,否则会读到半天前的数据还以为是实时值。一个务实的做法是:写库在整点前两分钟完成,报表在整点后五分钟生成,中间留出缓冲,避免查询正好撞上插入事务。
5. 数据库备份与恢复:把 .mdf 和 .ldf 管起来
工控项目里数据库恢复这件事,平时没人提,出事时是救命的。SQL Server 的库文件就两个:数据文件.mdf和日志文件.ldf,默认放在安装目录,规范的做法是建库时就指定到独立数据盘,比如E:\DataBase,和系统盘分开,系统重装不丢数据。
5.1 冷备份流程:停库、拷贝、附加
备份时先停掉写入(停 Intouch 写库脚本或直接停 SQL 服务),把DataBase目录连同两个文件整体拷到备份介质。恢复时把目录拷回目标机的E:\下,在 SSMS 里对“数据库”节点右键选“附加”,在“附加数据库”界面点“添加”,定位到E:\DataBase\YADC_BB.mdf,确定后 SQL Server 会自动关联同目录下的.ldf。附加失败的常见原因是文件权限:SQL 服务账号对拷贝过来的目录没有读写权限,表现是“无法打开物理文件,操作系统错误 5”,给目录加NETWORK SERVICE或对应服务账号的完全控制即可。
5.2 恢复后的校验:三查一对比
附加成功不等于数据可用,通常要做三查:查表数量是否与备份前一致、查最新一条RecTime是否接近备份时刻、查行数是否在合理量级。再拿一张已知日期的日报和备份前的报表对比一次,数值对得上才算恢复完成。这一步在课程设计里可以写成验收项,答辩时能直接展示。
6. 避坑与排查:这套链路最容易翻车的五个点
6.1 连接成功但插入报“无效的列名”
现象是SQLConnect返回正常,SQLInsert执行后数据库里没有新行,日志提示列名无效。原因基本是绑定列表里的变量映射列名和表结构拼写不一致,或者绑定列表选错了表。解决方法是打开绑定列表逐列核对,把表结构脚本和绑定列表截图并排放着对,别凭记忆。
6.2 数据重复写入,一天多出成倍记录
现象是同一时刻出现两条以上相同数据。原因有两个:WSQLS置位后没有在后续节拍复位,或者复位和置位写在同一脚本块里导致防重复形同虚设;多台上位机同时运行程序且没有NodeName判断。解决方法是把复位拆到独立条件,并加上站名白名单。
6.3 运行几天后突然不写库
现象是前几天正常,某天开始数据库不再新增记录,重启 Intouch 又恢复。原因是连接只建不断,连接句柄累积耗尽。解决方法是在应用程序“关闭时”补SQLDisconnect,并在写库脚本里对Connid1做有效性判断,连接号为 0 时重新SQLConnect。
6.4 Excel 报表查询结果为空
现象是库里明明有数据,报表生成后一片空白。原因多为日期参数格式与DATETIME列不匹配,或者查询区间写成了开区间漏掉边界。解决方法是统一用yyyy-MM-dd HH:mm:ss格式传参,查询用>=和<=闭区间,并先在 SSMS 里用同样条件手跑一遍 SQL 确认有结果。
6.5 数据库附加失败,提示操作系统错误
现象是恢复时附加.mdf报错,错误码指向文件访问。原因是文件权限或文件正被其他实例占用。解决方法是确认 SQL 服务账号对目录有完全控制权限,确认没有同名数据库已附加,必要时先分离旧库再附加。
7. 验收与答辩:用一张检查表把整条链路跑通
这套方案的验收不靠“看起来能用”,靠一条可复现的检查链。我一般会准备一张验收表,从数据库到报表逐项打勾,答辩时按表演示,评委问哪一环都能当场指出来。
| 验收项 | 操作 | 通过标准 |
|---|---|---|
| 认证与登录 | 用专用账号在 SSMS 登录 | 能登录且仅有目标库读写权限 |
| 表结构 | 执行建表脚本后查列 | 列名、类型与绑定列表一致 |
| 连接建立 | 启动 Intouch 后查Connid1 | 连接号非 0 |
| 周期写入 | 等到触发节拍后查表 | 新增一行且时间正确 |
| 防重复 | 连续观察两个触发周期 | 每周期仅一行 |
| 断开释放 | 关闭 Intouch 后查连接数 | 连接数回落 |
| 报表取数 | 控制面板选日期生成 | 行数与库内查询一致 |
| 备份恢复 | 拷贝文件到另一实例附加 | 表数量与最新记录时间吻合 |
答辩时最容易被追问的三个问题,提前准备好答案:为什么用条件脚本而不是定时器——因为 Intouch 条件脚本依托系统变量,部署简单且与画面脚本同源;为什么 Excel 而不是专业报表工具——中小项目里 Excel 模板改版成本最低,运行人员自己就能调格式;数据重复怎么保证——靠WSQLS标志加站名白名单双保险。演示顺序建议按“写一条 → 查一条 → 出一张报表 → 恢复一次库”走,全程不超过十分钟,每一步都有可见结果。
从那以后我每次交付这类 SCADA 数据链路,都会在写第一行脚本之前先把验收表列出来,表列不出来的功能就不写,因为那说明自己还没想清楚怎么证明它对。希望帮到你。
本文还有配套的精品资源,点击获取