概述
Rexroth PLC与 CVI OPC通讯的实现
- OPC Server 安装
- OPC Server配置
- OPC Configurator 配置
- OPC Test Client 测试
- PLC端配置
- CVI OPC通讯编程
OPC Server 安装
力士乐开发软件中已经集成了OPC Server的相关组件,只需要安装Indraworks里的communication 组件即可,当前我使用的版本是Indraworks 12v08,这里就不详细介绍安装方法了。
只是要注意一点:最好将电脑非Unicode设置成非中文,再安装,我碰到许多次出现Indraworks安装失败,或者在配置后测试 noconfig的状态。
OPC Server配置
OPC Configurator 配置
- 打开Rexroth>IndraLogic>OPC Configurator
- 添加PLC, 如果是一个客户端选择 Single PLC,如果位多个可以右击append PLC。.
- Edit创建通讯参数,如果已有Gateway可以直接点添加New…,如有没有先添加Gateway 选择TCP/IP
- 添加PLC配置时,请选择TCP/IP(Level 2 Route)。
OPC Test Client 测试
如果想要确认新建的OPC Server运行状态如何,可以使用 OPC Test Client 程序。
Rexroth>Communication>OPC Test Client
选择IndraLogic.OPC状态信息栏里显示运行状态
如果出现状态noconfig的状态,你的PLC是连接到你的服务器的,只是读不到你的配置文件,或者读不到 你的变量表。
遇到这个问题
1.首先确认你的电脑是否设置成了Unicode简体中文,可先将他设置成英文。
2.变量表是你的PLC编译后生成的.SDB文件。可以将他手动配置到你的Gateway Files里。
连接好PLC后可以通过添加Item 来确认变量是否可以遍历到
PLC端配置
新建变量
Project>Option>Symbol Configuration>Configure symbol file 选中所有变量
CVI OPC通讯编程
当前使用的是Labwindows CVI 2013版本
从文件读取配置信号ini配置文件如下
[PLC_TO_IPC]
Num=16
;
[IPC_TO_PLC]
Num=25
;
[PO_0]
EN=“HeartBeat”
CN=“心跳信号”
GM=“HeartBeat”
URL=“opc://localhost/IndraLogic.OPC.02/PLC1:.stPLC.bPuls”
TYPE=111
SIZE=2
;
[PO_1]
EN=“DMC”
CN=“ID码”
GM=“DMC”
URL=“opc://localhost/IndraLogic.OPC.02/PLC1:.stPLC.chDMC”
TYPE=115
SIZE=50
;
[PO_2]
EN=“Mode”
CN=“模式”
GM=“Mode”
URL=“opc://localhost/IndraLogic.OPC.02/PLC1:.stPLC.iMode”
TYPE=102
SIZE=4
;
封装部分直接上源代码
当前只读取PLC 的四种类型。CodeSys下的 REAL,BOOL,INT,STRING
// Include files
#include "dataskt.h"
#include <ansi_c.h>
#include "inifile.h"
#include "PLCCom.h"
//==============================================================================
// Constants
#define GETURL(section,chvalue) if(0>=Ini_GetPointerToRawString (handle,section,"URL",&chvalue)) return -1001;else //get the url if wrong return -1;
#define GETTYPE(section,value) if(0>=Ini_GetInt(handle,section,"TYPE",&value)) return -1002;else //get the valible type if wrong return -1;
#define GETSIZE(section,value) if(0>=Ini_GetInt(handle,section,"SIZE",&value)) return -1005;else //get the valible type if wrong return -1;
#define GETHANDLE(url,section,i) if(0>DS_OpenEx(url,DSConst_ReadWriteAutoUpdate,NULL,NULL,DSConst_EventModel,1,§ion)) return -1003000-i;else //get the handle of the valible
#define CHECK_HANDLE(handle,i) if(handle== 0) return -1000000-10000*i;else
#define OPC_GETTYPE(handle,type,i) if(0>DS_GetDataType(handle,&type,&uiSize,NULL)) return -2000000-10000*i;else
#define CHECK_TYPE(type,type2,i) if(type2!=type) return -3000000-10000*i-type2;else
#define ErrCheck(function,i) if(function<0) return -4000000-10000*i;else
//==============================================================================
// Types
//==============================================================================
// Static global variables
static struct SignalInfo stPLC[56];
static struct SignalInfo stIPC[56];
int PLCNO=0;
int IPCNO=0;
//==============================================================================
// Static functions
enum Type
{
T_BOOL=111,
T_INT=102,
T_REAL=104,
T_STRING=115,
};
unsigned char *pPlcData;
unsigned char *pIpcData;
//==============================================================================
// Global variables
//==============================================================================
// Global functions
/***************** initial the url********************/
//RootPath the root path of the program
//pPlcInfo plc 信息的结构体指针
//pIpcInfo ipc信息结构体指针
//success 返回0 失败返回负数
// -1 FAIL TO GET URL
// -2 FAIL TO GET THE HANDLE
// -3 FAIL TO GET THE TYPE
// -4 FAIL TO fIND THE FILE
extern "C" __declspec(dllexport)int PLC_COM_Initial(char *RootPath,unsigned char *pPlcInfo , unsigned char *pIpcInfo)
{
char path[225]="";
char *chval;
char temp[20]="";
char *opcURLs;
pPlcData=pPlcInfo;
pIpcData=pIpcInfo;
strcpy(path,RootPath);
strcat(path,"\Configuration\PLCInterface.ini"); //文件路径获取
IniText handle=Ini_New (0);
if(0!=Ini_ReadFromFile(handle,path)) {Ini_Dispose(handle);return -1004;}
if(0>=Ini_GetInt (handle,"PLC_TO_IPC","Num",&PLCNO)) return -1005;
if(0>=Ini_GetInt (handle,"IPC_TO_PLC","Num",&IPCNO)) return -1006;
unsigned int uiType=0, uiSize=0;
//read the url for the config file
for(int i=0; i<PLCNO; i++)
{
sprintf(temp,"PO_%d",i);
GETURL(temp,chval);
opcURLs=StrDup(chval);
GETHANDLE(opcURLs,stPLC[i].iHandle,i);
free(opcURLs);
GETTYPE(temp,stPLC[i].iType);
GETSIZE(temp,stPLC[i].iSize);
OPC_GETTYPE(stPLC[i].iHandle,uiType,i);
CHECK_TYPE(stPLC[i].iType,uiType,i) ;
}
for(int i=0; i<IPCNO; i++)
{
sprintf(temp,"IO_%d",i);
GETURL(temp,chval);
opcURLs=StrDup(chval);
GETHANDLE(opcURLs,stIPC[i].iHandle,i);
free(opcURLs);
GETTYPE(temp,stIPC[i].iType);
GETSIZE(temp,stIPC[i].iSize);
OPC_GETTYPE(stIPC[i].iHandle,uiType,i);
CHECK_TYPE(stIPC[i].iType,uiType,i) ;
}
Ini_Dispose(handle);
return 0;
}
/***************** read the signal from plc********************/
//success 返回0 失败返回负数
// -1 FAIL CHECK THE HANDLE
// -2 FAIL TO GET THE TYPE
// -3 FAIL TO CHECK THE TYPE
// -4 FAIL TO GET THE VALUE
extern "C" __declspec(dllexport)int PLC_COM_Read()
{
int index=0;
unsigned int uiType=0;
unsigned int uiSize=0;
//plc to ipc signal receive
for(int i=0; i<PLCNO; i++)
{
int *piVal=(int *)(pPlcData+index);
short *psVal=(short *)(pPlcData+index);
char *pcVal=(char *)(pPlcData+index);
float *pfVal =(float *)(pPlcData+index);
int iVal=0;
short sVal=0;
float fVal=0;
CHECK_HANDLE(stPLC[i].iHandle,i);
OPC_GETTYPE(stPLC[i].iHandle,uiType,i);
switch(stPLC[i].iType)
{
case T_BOOL:
ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_SHORT, &sVal, uiSize+1, NULL,NULL),i);
sVal=abs(sVal);
*psVal=sVal;
break;
case T_INT:
ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_INT, &iVal, uiSize+1, NULL,NULL),i);
*piVal=iVal;
break;
case T_STRING:
ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_CSTRING,pcVal, uiSize+1, NULL,NULL),i);
break;
case T_REAL:
ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_FLOAT, &fVal, uiSize+1, NULL,NULL),i);
*pfVal=fVal;
break;
default:
return -600000-i*1000-stPLC[i].iType;
}
index+=stPLC[i].iSize;
}
return 0;
}
/***************** write the signal to plc ********************/
//success 返回0 失败返回负数
// -1 FAIL CHECK THE HANDLE
// -2 FAIL TO GET THE TYPE
// -3 FAIL TO CHECK THE TYPE
// -4 FAIL TO set THE VALUE
extern "C" __declspec(dllexport)int PLC_COM_Set()
{
int index=0;
//ipc to plc signal receive
for(int i=0; i<IPCNO; i++)
{
int *piVal=(int *)(pIpcData+index);
short *psVal=(short *)(pIpcData+index);
char *pcVal=(char *)(pIpcData+index);
float *pfVal =(float *)(pIpcData+index);
int iVal=0;
short sVal=0;
float fVal=0;
CHECK_HANDLE(stIPC[i].iHandle,i);
switch(stIPC[i].iType)
{
case T_BOOL:
sVal=*psVal;
ErrCheck(DS_SetDataValue (stIPC[i].iHandle,CAVT_SHORT, &sVal,0,0),i);
break;
case T_INT:
iVal=*piVal;
ErrCheck(DS_SetDataValue(stIPC[i].iHandle,CAVT_INT, &iVal, 0,0),i);
break;
case T_STRING:
ErrCheck(DS_SetDataValue (stIPC[i].iHandle,CAVT_CSTRING, pcVal,0,0),i);
break;
case T_REAL:
fVal=*pfVal;
ErrCheck(DS_SetDataValue(stIPC[i].iHandle,CAVT_FLOAT, &fVal, 0,0),i);
break;
default:
return -700000-i*1000-stIPC[i].iType;
}
index+=stIPC[i].iSize;
}
return 0;
}
调用以上函数的方法
//此部分位初始化调用
int PLCInterface_Initial()
{
int iRetVal=0;
if(Initialed==0)
iRetVal=PLC_COM_Initial(gPara.SWPath,(unsigned char*)&stPLC,(unsigned char*)&stIPC);
if(iRetVal==0)
{
Initialed=1;
stIPC.bIsReady=TRUE;
}else
{
char temp[20]="";
sprintf(temp,"Code:%d",iRetVal);
MessageAlarm("1081",temp,gPara.ActLanguage);
}
return iRetVal;
}
//此部分贴入定时器循环扫描
int PLC_IPC_Ctrol()
{
static int bPulseEx=0;
static double dTimerA=0,dTimerB=0;//timer count
static char Trigger=0;
static int ModeEx=-1;
if(!Initialed) return 0; //
//READ AND WRITE
int ret=PLC_COM_Read();
if(0!=ret)
{
char temp[20]="";
sprintf(temp,"RCode:%d",ret);
MessageAlarm("1070",temp,gPara.ActLanguage);
return 0;
}
ret=PLC_COM_Set();
if(0!=ret)
{
char temp[20]="";
sprintf(temp,"WCode:%d",ret);
MessageAlarm("1070",temp,gPara.ActLanguage);
return 0;
}
}
至此,整个OPC通讯的实现就已完成。
划重点
DS_GetDataValue(stPLC[i].iHandle,CAVT_SHORT, &sVal, uiSize+1, NULL,NULL),i);
CAVT_SHORT 是指 在上位机程序变量的定义类型 而非PLC端变量的定义类型。
运行效果
最后
以上就是顺心冬日为你收集整理的Rexroth(力士乐)PLC与Labwindows CVI OPC通讯的实现OPC Server 安装OPC Server配置PLC端配置CVI OPC通讯编程的全部内容,希望文章能够帮你解决Rexroth(力士乐)PLC与Labwindows CVI OPC通讯的实现OPC Server 安装OPC Server配置PLC端配置CVI OPC通讯编程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复