前言
建议初学者先看这一章节内容,里面包括一些基础的环境配置和项目建立流程,以后开发项目这些流程是通用的,务必掌握并熟练。
链接: 上位机使用C++通过ADS协议与倍福PLC通信例程-布尔变量的读取
ADS读写TwinCAT中变量的方式
ADS读写TwinCAT中变量的方式有两种,一种通过IndexGroup和IndexOffset信息访问变量,另一种方式是通过变量名的形式访问变量。
通过IndexGroup和IndexOffset访问变量
如上图所示,PLCVar1的IndexGroup和IndexOffset分别是4040和5DFE8,这样在使用倍福提供的库函数时,只需要填写以上信息就可以。例如使用ADS的读取函数,当读取PLCVar1时,若在上位机上声明一个变量 PLCVar1Get来存放读取上来的值,那么nLength=4(按字节计量变量的大小,在函数的形参中通常以sizeof(PLCVar1Get)出现,编程人员应该自己检查确保计算的结果是4bytes),
float PLCVar1Get;
那么pData就是指向PLCVar1Get的指针,一般在形参中以“&PLCVar1Get”出现。
LONG AdsSyncReadReq(
PAmsAddr pAddr,
ULONG nIndexGroup,
ULONG nIndexOffset,
ULONG nLength,
PVOID pData);
pAddr结构体包含PLC中的AMS地址和ADS端口号,可参考文章开头部分提供的例程理解,此处不再赘述。
通过IndexGroup和IndexOffset读写有什么劣势呢?
在实际编程中,如果变量名起的不合理,或者类型需要更改时,IndexOffset就有可能变动,导致程序更改麻烦且困难,极容易漏掉一些忘记更改的程序行导致出错,下面以更改变量名字为例,看一下更改后的情况,把PLCVar1更改为PLCVar1_1后,IndexOffset的值由5DEF8变为了608D0,此时就需要把程序中用的5DEF8的地方更改为608D0,程序较大时就显得繁琐低效。
通过变量名的方式访问变量
倍福的官方文档中是推荐用户优先使用通过变量名方式来访问变量,通过变量名的方式访问变量的本质是先通过变量名获取该变量的句柄,之后对该变量的操作均以句柄进行,这里的句柄是指windows中的句柄,不能简单等同于变量的指针(嵌入式中有此种叫法),详细解释可参阅百度百科的说明
链接: 句柄
例如,我们要通过变量名的方式访问变量PLCVar1,通过上位机来读写PLCVar1,下面给出了上位机中的程序,如果需要更改变量的名字,那么只需要更改szVar[]数组内的字符串即可。
变量名的全称即为上图中的Full-Name栏的内容
#include <iostream>
#include <windows.h>
#include <conio.h>
// ADS headers for TwinCAT 3
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsAPI.h"
using namespace std;
int main()
{
long nErr, nPort;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
ULONG lHdlVar;//用来存放MAIN.PLCVar1变量的句柄
float PLCVar1Get;//该变量存放要写入PLC中的值
char szVar[] = { "MAIN.PLCVar1" };//需要读写的PLC中的变量名的全称
// Open communication port on the ADS router
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
// TwinCAT 3 PLC1 = 851
pAddr->port = 851;
// 获取MAIN.PLCVar1变量的句柄
nErr = AdsSyncReadWriteReq(pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar), &lHdlVar, sizeof(szVar), szVar);
cout << "HandleNum Of Variable:"<<lHdlVar << endl;
if (nErr) cerr << "Error: AdsSyncReadWriteReq: " << nErr << '\n';
while(1)
{
// Read value of a PLC variable (by handle)
nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(PLCVar1Get), &PLCVar1Get);
if (nErr)
cerr << "Fehler: AdsSyncReadReq: " << nErr << '\n';
else
cout << "MAIN.PLCVar1: " << PLCVar1Get << '\n';
cout.flush();
cin >> PLCVar1Get;
nErr = AdsSyncWriteReq(pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(PLCVar1Get), &PLCVar1Get);
if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';
}
/*
//Release handle of plc variable
nErr = AdsSyncWriteReq(pAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(lHdlVar), &lHdlVar);
if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';
// Close communication port
nErr = AdsPortClose();
if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';
return 0;
*/
}
下面给出PLC中的程序
PROGRAM MAIN
VAR
PLCVar1:REAL;
PLCVar2:BOOL;
PLCVar3:INT;
END_VAR
运行结果如下图所示,PLC中的变量初始值我们设为30.22,运行上位机程序后可以读到变量是30.22
把变量更改为50.1478,可以看到PLC中的变量已经变为50.1478
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)