作者简介:梁帅(1986-),男,电气工程师,本科,主要从事双模定型硫化机的电气设计研发工作。
收稿日期:2020-09-11
轮胎硫化生产中有三个关键要素,即温度、压力、时间。这三个要素决定了轮胎硫化的质量。为了掌控轮胎硫化质量及在轮胎售出后做质量追溯,一般轮胎生产厂家都会记录并保存这三要素的相关数据。关于数据的记录方法之前是使用机械式圆盘记录仪、打点记录仪,后来发展到智能无纸记录仪及上位机监控系统。圆盘曲线是指上位机监控系统中的一个功能,圆盘曲线可以在一屏同时显示24 h 的温度、压力曲线,可以方便的观察一天中设备停机情况、预热时间、班次产量等信息,在轮胎生产厂家使用过程中已成为必备功能之一。上位机监控系统的画面软件可使用高级语言编写,也可使用成熟的组态软件实现。本文将介绍使用WINCC 软件实现圆盘曲线功能的一种方法,文中的硫化机控制系统采用西门子S7 1500系列PLC ,上位机采用西门子工控机,监控软件采用西门子WINCC 组态软件。上位机与工控机通过以太网连接。
1 WINCC 软件
SIMATIC WinCC (Windows Control Center )--
视窗控制中心,它是西门子最经典的过程监视系统,已成为市场的领导者,乃至业界遵循的标准。WinCC
能为工业领域提供完备的监控与数据采集(SCADA )功能,涵盖单用户系统直到支持冗余服务器和远程 Web 服务器解决方案的多用户系统。SIMATIC WinCC 是公司垂直集成交换信息的基础,具有良好的
基于WINCC 的轮胎硫化机圆盘曲线
的实现
梁帅1,杨华1,张树伟1,赵尊梅1,丁建华2,徐敬志1,陆永高
1
(1.青岛海琅特种装备科技有限公司,山东  青岛  266400;
2.青岛双星轮胎工业有限公司,山东  青岛  266400)
摘要:硫化机生产过程中,WINCC 自动化控制系统自动采集并记录轮胎硫化时实时的温度、压力、时间等数据,并将这些数据绘成圆盘曲线。圆盘曲线是指上位机监控系统中的一个功能,圆盘曲线可以在一屏同时显示24 h 的温度、压力曲线,可以方便的观察一天中设备停机情况、预热时间、班次产量等信息,在轮胎生产厂家使用过程中已成为必备功能之一。
关键词:WINCC ;PLC ;圆盘曲线中图分类号:TQ330.493
文章编号:1009-797X(2021)01-0018-07
文献标识码:B      DOI:10.13520/jki.rpte.2021.01.005
开放性和灵活性,它采用了工厂智能,助力用户实现更大程度的生产过程透明化。虽然WinCC 的功能很强大,但它未对硫化机行业做专门的定制开发,未提供圆盘曲线的控件,用户需自己通过WinCC 脚本系统开发相应功能。
2 WinCC 脚本系统
WinCC 的脚本系统支持C 脚本和VBS 脚本。脚
本本质上是一段用C 或VB 编写的代码,用以实现一些特定的功能。这里,我们简单介绍一下C 脚本的概念。如图1所示,为WinCC
双星轮胎
脚本的分类。
图1 脚本分类
2.1 函数动作
函数和动作本质上都是一段代码。如图1所示,函数分为嵌入函数和用户函数。嵌入函数用户只能使用,不能修改;而用户函数则可由用户根据实际需要
创建和修改,用户函数又分为项目函数、标准函数和DLL 函数。
动作由用户自己创建,必要时可以进行口令保护,防止未经授权的人对其进行修改和查看。动作要想执行,必须至少为其分配一个触发器。
动作分为全局动作和局部(本地)动作。在客户机-服务器项目中,全局动作在项目中所有计算机中都可执行;而局部动作则只能在对其进行分配的计算机上执行。当创建的是单用户项目时,全局动作和局部动作之间就没有太大的差别了。
2.2 脚本的执行过程
图2为脚本的执行过程。WinCC 脚本的核心是动作。动作通过触发器触发来实现相应事件或改变画面中对象的属性等。函数则是一段特定功能的代码,它本身并不能参与到WinCC 的动态响应中去,动作在
需要的时候,调用某个函数来实现既定功能。
图2 脚本的执行过程
一个动作触发后,会执行其对应的代码,在该代码中,可能会调用到其他C 代码编写的函数,相当于子程序。
2.3 触发器
触发器的类型如图3所示。一个动作可以由定时器触发,也可以用变量触发。定时器触发又可分为循环
触发和非循环触发;而变量触发则可以选择在某一变量值发生变化的时候触发动作,也可以选择采用"循环监视变量值"
的方式。
图3 触发器的类型
一个动作可以同时分配若干个触发器,任何一个触发器有效了,动作就将被执行,而且,动作要想被
执行,必须至少分配一个触发器。
3 WinCC 圆盘曲线的实现
利用WinCC 自带的WINCC FunctionTrendContr ol 控件,可实现直角曲线功能,但不能实现圆盘曲线的显示。为实现圆盘曲线功能,我们需要做以下工作:
(1)将记录的数据转换成极坐标形式
将一天24个小时平均分布到圆盘图中,然后根据系统时间将当前时刻转换为极坐标形式。再将PLC 读取的实时数据转换成对应的当前时刻极坐标形式。C 脚本如下所示:
#include "apdefap.h"int gscAction( void ){
// WINCC:TAGNAME_SECTION_START // s y n t a x : #d e f i n e  T a g N a m e I n A c t i o n "DMTagName"
/
/ next TagID : 1
// WINCC:TAGNAME_SECTION_END
// WINCC:PICNAME_SECTION_START
// s y n t a x : #d e f i n e  P i c N a m e I n A c t i o n "PictureName"
// next PicID : 1
// WINCC:PICNAME_SECTION_END
short a1,b1,c1,year,month,week,day,hour,minute ,second,msecond;
double a, b,c,d,e,f,g,h,i,j,k,e0,f0,g0,e1,f1,g1,e2,f2,g2,e3,f3,g3,e4,f4,g4,e5,f5,g5,e6,f6,g6,e7,f7,g7;
// 获取系统时间
a1=GetTagWord("hour"); //Return-Type: WORD b1=GetTagWord("minute"); //R e t u r n -T y p e : WORD
c1=GetTagWord("second"); //R e t u r n -T y p e : WORD
a = a1*3600+b1*60+c1;  //当前时刻转换成0点
开始的秒数;
e=3.14;  //定义e 的值为π
f=a/86400;  //当前时刻在一天中占的比例; c=0.5*e -2*f*e;  //当前时刻在圆盘图中的弧度;
//sin()函数接受的参数是弧度;double 类型;//数值转换成坐标;
b=sin(c); //Return -Type: double  Y 轴d=cos(c);  //Return -Type: double  X 轴//printf("a:%d  ",a); //printf("c:%f  ",c);//printf("b:%f  ",b);//printf("d:%f  ",d);//printf("f:%d  ",f);//printf("e0:%f  ",e0);//printf("f0:%f  ",f0);//printf("g0:%f  ",g0);
//获取当前时刻的左热板温度,转换成极坐标e 0 = G e t Ta g F l o a t ("y u a n p a n _t e s t _D B _r e b a n _L");//Return-Type: float
f0 = e0*d; //x 轴坐标;g0 = e0*b; //y 轴坐标;
SetTagDouble("yuanpan_test_DB_yp_reban_x_L",f0); //Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_reban_y_L",g0); //Return-Type: BOOL
//获取当前时刻的右热板温度,转换成极坐标e 1 = G e t Ta g F l o a t ("y u a n p a n _t e s t _D B _r e b a n _R");//Return-Type: float
f1 = e1*d;g1 = e1*b;
SetTagDouble("yuanpan_test_DB_yp_reban_x_R",f1); //Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_reban_y_R",g1); //Return-Type: BOOL
//获取当前时刻的左模套温度,转换成极坐标e2 = GetTagFloat("yuanpan_test_DB_motao_L");//Return-Type: float
f2 = e2*d;g2 = e2*b;
SetTagDouble("yuanpan_test_DB_yp_motao_x_L",f2); //Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_motao_y_L",g2); //Return-Type: BOOL
//获取当前时刻的右模套温度,转换成极坐标e3 = GetTagFloat("yuanpan_test_DB_motao_R");//Return-Type: float
f3=e3*d;g3=e3*b;
SetTagDouble("yuanpan_test_DB_yp_motao_x_R",f3);//Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_motao_y_R",g3);//Return-Type: BOOL
//获取当前时刻的左内温温度,转换成极坐标e4 = GetTagFloat("yuanpan_test_DB_neiwen_L");//Return-Type: float
f4 = e4*d;g4 = e4*b;
SetTagDouble("yuanpan_test_DB_yp_neiwen_x_L",f4);//Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_neiwen_y_L",g4);//Return-Type: BOOL
//获取当前时刻的右内温温度,转换成极坐标e5 = GetTagFloat("yuanpan_test_DB_neiwen_R");//Return-Type: float
f5 = e5*d;g5 = e5*b;
SetTagDouble("yuanpan_test_DB_yp_neiwen_x_R",f5);//Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_neiwen_y_R",g5);//Return-Type: BOOL
//获取当前时刻的左内压压力,转换成极坐标e6 = GetTagFloat("yuanpan_test_DB_neiya_L"); //Return-Type: float
f6 = e6*d;g6 = e6*b;
/*if (f6 < 4 && f6 > -4 && g6 < 4 && g6 > -4){
SetTagDouble("yuanpan_test_DB_yp_neiya_x_L",f6);  //Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_neiya_y_L",g6);//Return-Type: BOOL
} */
SetTagDouble("yuanpan_test_DB_yp_neiya_x_L",f6);  //Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_neiya_y_L",g6);//Return-Type: BOOL
//获取当前时刻的右内压压力,转换成极坐标e 7 = G e t Ta g F l o a t ("y u a n p a n _t e s t _D B _n e i y a _R");//Return-Type: float
f7 = e7*d;g7 = e7*b;
SetTagDouble("yuanpan_test_DB_yp_neiya_x_R",f7); //Return-Type: BOOL
SetTagDouble("yuanpan_test_DB_yp_neiya_y_R",g7); //Return-Type: BOOL
return 0; }
(2)将转换完成的变量记录到数据库中
用户归档编辑器是WinCC 的一个附加选件,通过它可以周期性的把PLC 读取的数据保存到数据库中。 在图形编辑器中,可以通过组态 WinCC 用户归档表格元素来以表格显示运行系统中用户归档的在线数据。可通过用户归档的控制变量实现数据的读取和写入,而不需要用户自己写脚本,使用起来非常方便。在用户归档编辑器中,可以最多组态 500 个归档和 500 个视图。 每个归档最多可创建 500 个域。归档中的数据记录的最大数目,取决于已组态列的数目和归档中包含的数据记录。列和数据记录的乘积不能大于 320 000。对于数据存储量不是很大的需求,WinCC 用户归档基本上可以满足。通过WINCC 的归档功能,我们可以将转换完成的极坐标数据周期性的保存进数据库中,如图4
所示。
图4 WINCC 归档设置
(3)设置WINCC FunctionTrendControl 控件属
性,组态要显示的曲线,选择相应曲线连接的数据源,曲线显示的Y 轴坐标等,如图5
所示。
图5 WINCC FunctionTrendControl 控件属性
(4)编写查询曲线用的C 脚本,具体脚本如下#include "apdefap.h"
v o i d  O n C l i c k (c h a r * l p s z P i c t u r e N a m e , c h a r * lpszObjectName, char* lpszPropertyName)
{
// WINCC:TAGNAME_SECTION_START // s y n t a x : #d e f i n e  T a g N a m e I n A c t i o n "DMTagName"
// next TagID : 1
// WINCC:TAGNAME_SECTION_END // WINCC:PICNAME_SECTION_START
// s y n t a x : #d e f i n e  P i c N a m e I n A c t i o n "PictureName"
// next PicID : 1
// WINCC:PICNAME_SECTION_END
//SetPropBOOL(lpszPictureName,"control1","D eleteData",TRUE);
SetPropWord(lpszPictureName,"control1","Tren dIndex",0);//Return-Type: BOOL
SetPropBOOL(lpszPictureName,"control1","onl ine",0); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dRangeType",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeFactor",1); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeBase",86400000);//Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tren dBeginTime",GetTagChar("chaxunriqi_begin")); //Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tren dEndTime",GetTagChar("chaxunriqi_end")); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dIndex",1);//Return-Type: BOOL
SetPropBOOL(lpszPictureName,"control1","onl ine",0); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dRangeType",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeFactor",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeBase",86400000);//Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tren dBeginTime",GetTagChar("chaxunriqi_begin")); //Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tren dEndTime",GetTagChar("chaxunriqi_end")); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dIndex",2);//Return-Type: BOOL
SetPropBOOL(lpszPictureName,"control1","onl ine",0); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dRangeType",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeFactor",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeBase",86400000);//Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tren dBeginTime",GetTagChar("chaxunriqi_begin")); //Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tren
dEndTime",GetTagChar("chaxunriqi_end")); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dIndex",3);//Return-Type: BOOL
SetPropBOOL(lpszPictureName,"control1","onl ine",0); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dRangeType",0);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeFactor",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeBase",86400000);//Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tre ndBeginTime",GetTagChar("chaxunriqi_begin"));//Return-Type: BOOL
//S e t P r o p C h a r (l p s z P i c t u r e N a m e ,"c o n t r o l 1","TrendEndTime",GetTagChar("chaxunriqi_end"));//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dIndex",4);//Return-Type: BOOL
SetPropBOOL(lpszPictureName,"control1","onl ine",0); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dRangeType",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeFactor",1); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dTimeRangeBase",86400000);//Return-Type: BOOL
SetPropChar(lpszPictureName,"control1","Tre ndBeginTime",GetTagChar("chaxunriqi_begin"));//Return-Type: BOOL
S e t P r o p C h a r (l p s z P i c t u r e N a m e ,"c o n t r o l 1","T r e n d E n d Ti m e ",G e t Ta g C h a r ("c h a x u n r i q i _e n d "));//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dIndex",5);//Return-Type: BOOL
SetPropBOOL(lpszPictureName,"control1","onl ine",0); //Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren dRangeType",1);//Return-Type: BOOL
SetPropWord(lpszPictureName,"control1","Tren