我是靠谱客的博主 顺心冬日,最近开发中收集的这篇文章主要介绍Rexroth(力士乐)PLC与Labwindows CVI OPC通讯的实现OPC Server 安装OPC Server配置PLC端配置CVI OPC通讯编程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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 配置

  1. 打开Rexroth>IndraLogic>OPC Configurator
    在这里插入图片描述
  2. 添加PLC, 如果是一个客户端选择 Single PLC,如果位多个可以右击append PLC在这里插入图片描述.在这里插入图片描述
  3. Edit创建通讯参数,如果已有Gateway可以直接点添加New…,如有没有先添加Gateway 选择TCP/IP
  4. 在这里插入图片描述在这里插入图片描述
  5. 添加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,&section)) 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通讯编程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部