比较实际趋势曲线和设定值(理想)曲线的实现方法

n

1概述
同时将实际的趋势曲线和设定值(理想)曲线显示在趋势图中,可以方便客户进行比较,运行时的效果如图1所示。在“函数趋势控件“上,横坐标代表绘制的点的序号,按照时间序列从左到右依次排列,纵坐标代表变量值。本例中每隔1秒钟读取一次变量值。图1中红色曲线代表理想曲线,根据一组设定值绘制,理想趋势的数值必须保持在用户归档中;蓝色曲线代表实际的趋势曲线,根据各个时刻变量的实际值绘制。n

比较实际趋势曲线和设定值(理想)曲线的实现方法
图1 实际趋势曲线和理想曲线的比较n

2用户归档的组态

2.1 使用用户归档存放曲线的设定值
新建用户归档,名称为“CompareSetPoint”,用于存放理想曲线的各个设定值。插入两个域,域“PointNumber”对应于“函数趋势控件”横坐标的点的序号,本例中为0到9。域“SetValue”对应于“函数趋势控件”纵坐标的相应点的设定值。用户归档表格“CompareSetPoint”的值由用户在组态时设定即可,如下图所示:n

比较实际趋势曲线和设定值(理想)曲线的实现方法
图2 用户归档的设定值表n

2.2 使用用户归档存放曲线的实际值
新建用户归档,名称为“CompareActualValue “,用于存放实际曲线的各个变量值。插入两个域,域“PointNumber”对应于“函数趋势控件”横坐标的点的序号,本例中为0到9。域“ActualValue”对应于“函数趋势控件”纵坐标的相应点的实际变量值。用户归档表格“CompareActualValue”的值在WinCC运行时,由实际的变量值进行填充。n

3 函数趋势控件的组态
从“对象选项板 “中的“控件”页中,将“WinCC Function Trend Control”托拽到画面上进行设置。n

3.1 如何组态设定值曲线
1. 双击函数趋势控件,单击“曲线”标签,选中“设定值趋势”复选框。单击“属性...”按钮,打开“设定值趋势的属性”对话框。n

比较实际趋势曲线和设定值(理想)曲线的实现方法
图3 “设定值趋势的属性”对话框n

2. 在“归档连接”的“源”中,使用标记有“...”的按钮,并选择用户归档“CompareSetPoint”。在“X 轴数值的列”中,选择“PointNumber”;
在“Y 轴数值的列”中,选择“SetValue”。为了定义希望显示的时间范围,可指定所要表示的数值对的数目10,以及第一个数值对的 ID 号1。选择用于设定趋势的颜色“红色”,显示类型为“带虚线的连接点”。单击“确定”关闭对话框,并保存设置。n

3.2 如何组态实际曲线
1. 单击“曲线”标签,组态实际曲线的“颜色”、“显示类型”和“线条粗细”,本示例中设置为“蓝色”。n

2. 单击“数据连接”标签,在“提供者”中选择“用户归档”,在“用户归档”的“源”中选择“CompareActualValue”。在“X 轴数值的列”中,选择“PointNumber”;在“Y 轴数值的列”中,选择“ActualValue”列。将“成对数值的数目“设为10,“从ID”设置为1。n

比较实际趋势曲线和设定值(理想)曲线的实现方法
图4 “数据连接”标签的参数设置n

3. 单击“X轴”标签, 将“粗略定标”设置为1,取消“精细定标“复选框,将“小数位”和“标尺的小数位”都设为0。取消“自动”复选框,设置值范围从0到9。“Y轴”标签和“X轴”标签设置相同。点击“确定”按钮,保存“函数趋势控件”的属性设置。n

比较实际趋势曲线和设定值(理想)曲线的实现方法
图5 “X轴”标签的参数设置n

4 编写C脚本插入用户归档记录以绘制实际曲线
1. 新建两个内部变量“StartCompare”和“SimulateValueIndex“,类型均为“无符号16位数”。变量“StartCompare”用于启动实际变量的读取和曲线的绘制,变量“SimulateValueIndex“用于记录仿真数组的索引号,对应于实际的点数。n

2. 设计一个全局C动作“MakeActualTrend.pas”,用于生成实际的趋势曲线,触发周期设置为1秒钟,需要编写如下的脚本:
int pointNumber, actualValue;
int simulateValueArray[10] = { 1, 2, 3, 4, 5, 4, 3, 2, 1, 2 };
if ( GetTagBit("StartCompare") == TRUE )
{
pointNumber = GetTagWord("SimulateValueIndex");
actualValue = simulateValueArray[pointNumber ];n

if( uaInsertRecords( "CompareActualValue", InsertJobCB, pointNumber, actualValue ) )
printf( "Insert point %d O.K. rn", pointNumber );
else printf( "Insert point %d failed ! rn", pointNumber );n

pointNumber++;
if ( pointNumber >=10 )
{
pointNumber =0;
SetTagBit( "StartCompare", FALSE );
printf( "========== Insert point end ==========rn");
}
SetTagWord( "SimulateValueIndex", pointNumber );
}
数组simulateValueArray[10]中存放的是用于测试的仿真数据,该全局脚本每隔1秒钟执行一次,当发现“StartCompare”变量为“TRUE“时,按照每隔1秒钟的周期,依次将仿真数组中的数据和数组的索引写入到用户归档表格“CompareActualValue“中,10个数据都写完后,将“StartCompare”变量置为“FALSE“。注意,在实际的项目中,用户可以根据需求,按照指定的周期从实际的设备变量中取值。此外,在“计算机属性”的“启动”列表中,需要勾选“全局脚本运行系统”。上述代码编译时提示“函数uaInsertRecords未定义”,下面新建一个项目函数“uaInsertRecords”,实现向用户归档中插入数据的功能,代码如下:
#include "apdefap.h"
BOOL uaInsertRecords(const char* pszArchiveName ,
BOOL (UserFunc) (UAHARCHIVE* phUA, int pointNumber, int actualValue), int pointNumber, int actualValue )
{
BOOL returnCode = TRUE;
const char* funcName = "uaInsertRecords" ;
UAHCONNECT hCoect ;n

// Get Coection to User Archives
returnCode = uaCoect( &hCoect );
if( !returnCode || !hCoect)
{
returnCode = FALSE;
printf( "#E110:%s fault in uaCoect rn", funcName );
}
else
{
// Get Handle to Actual Archive.
UAHARCHIVE hArchive;
if(! uaQueryArchiveByName( hCoect, pszArchiveName , &hArchive ))
{
printf( "#E210:%s: uaQueryArchive Error: %drn", funcName , uaGetLastError());
returnCode = FALSE;
}
else
{
// Open data returned by query.
if(uaArchiveOpen(hArchive))
{
// Delete all the archive records if restart to compare.
if ( pointNumber == 0 )
{
returnCode = uaArchiveDelete( hArchive, "" );
if ( !returnCode )
{
printf("#E:%s error uaArchiveDeletern", funcName );
}
}n

returnCode = uaArchiveRequery(hArchive);
if (!returnCode )
{
printf("#E322:%s error UAArchiveRequeryrn", funcName );
}n

// Insert the value to user archive table.
returnCode = UserFunc(&hArchive, pointNumber, actualValue);
if(!returnCode )
{
printf("#E340:%s error in User Funcion !! rn ", funcName);
}n

// Close the archive.
if (!uaArchiveClose (hArchive ))
{
printf("E810:%s error in uaArchiveClose ! rn ",funcName) ;
returnCode = FALSE ;
}
}
else
{
printf("#E820:%s error in uaArchiveOpen! rn ", funcName);
returnCode = FALSE;
}
if(!uaReleaseArchive (hArchive))
{
printf("#E830:%s error in uaReleaseArchive! rn ", funcName);
returnCode = FALSE;
}
}
if( !uaDiscoect(hCoect))
{
printf("#E840:%s error in uaDiscoect ! rn ", funcName);
returnCode = FALSE ;
}
}
return returnCode;
}
以上代码实现了如下的功能:
1. 建立到用户归档的连接。
2. 根据归档名称“CompareActualValue”获得用户归档的句柄。
3. 打开用户归档。
4. 如果重新开始比较,则删除表格中的所有数据。
5. 将当前变量的值和对应点的索引插入到用户归档表格中。
6. 关闭并释放用户归档。
7. 断开到用户归档的连接。
其中的UserFunc调用了项目函数“InsertJobCB”,实现插入数据到用户归档表格的功能。新建一个项目函数“InsertJobCB”,代码如下:
#include "apdefap.h"
BOOL InsertJobCB( UAHARCHIVE* phArchive , int pointNumber, int actualValue )
{
BOOL rc = TRUE; // Return coden

if( ! uaArchiveSetFieldValueLong( *phArchive, 1, pointNumber) || // write productname to archive
! uaArchiveSetFieldValueLong( *phArchive, 2, actualValue ) ) // write number of parts to archive
{
printf( "InsertJobCB: error on writing to record rn" );
rc = FALSE ;
}
else
{
if( !uaArchiveInsert( *phArchive ) ) // insert new line in archive
{
printf( "InsertJobCB: error on updating archive rn" );
rc = FALSE ;
}
}
return rc;
}
以上代码将当前变量的值和对应点的索引值写入用户归档表格“CompareActualValue ”中。此时,再次编译全局C动作“MakeActualTrend.pas”,则编译成功。n

3. 在画面上放置两个按钮“Start”和“Stop”,在按钮“Start”的“鼠标动作“中,添加C脚本,将“StartCompare”变量值设为“TRUE“,并将仿真数组的索引值设为0。
printf( "========== Insert point begin ==========rn");
SetTagBit( "StartCompare", TRUE );
SetTagWord( "SimulateValueIndex", 0 );n

在按钮“Stop”的“鼠标动作“中,添加C脚本,将“StartCompare”变量值设为“FALSE“,并将仿真数组的索引值设为0。
printf( "========== Insert point end ==========rn");
SetTagBit( "StartCompare", FALSE );
SetTagWord( "SimulateValueIndex", 0 );n

5需要注意的问题

1. 用户可根据实际的需求,通过脚本控制数据读取的逻辑。本例中利用全局动作脚本周期地读取变量值,由于所有的全局C动作位于同一个脚本队列中,因此如果还有其它的耗时的全局C动作在运行时,势必会影响实时曲线数据的周期采集,因此应尽量避免其它全局C动作的影响。如果希望采集周期尽可能准确,可以使用如下方法2:在画面上的“Start”按钮中使用脚本循环进行数据的采集,并插入到用户归档表格中,使用Sleep函数进行延时来控制时间间隔,由于这种方法在比较长的时间内独占了整个画面动作的脚本线程,只有该“Start”动作执行完成后,其他的画面动作才可以执行,因此使用时要慎重。

2. 本例中点击“Start”按钮后,并没有立即启动插入变量值到用户归档的过程,等到全局C动作执行到下一个周期后才开始启动插入的过程,其间有不到1秒钟的延时。如果希望点击“Start”按钮后立即执行,可以使用上述的方法2。如果用户对采集周期的精度有较高的要求,请对WinCC的脚本进行测试以确定是否可以达到客户的要求。

3. 附件中提供了完整的项目文件,是在WinCC V6.2 SP2版本中生成的。运行时点击“Start”或“Stop”按钮可以看到实际的效果。注意,本示例仅供用户参考使用。

关键词
趋势曲线、函数趋势控件、用户归档、比较、C脚本

附件下载:sample_project.zip (2706 KB) ( 2706 KB )

原创文章,作者:ximenziask,如若转载,请注明出处:https://www.zhaoplc.com/plc328791.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2020年11月5日 下午12:03
下一篇 2021年4月12日 上午12:00

相关推荐

发表回复

登录后才能评论