介绍
TwinCAT3
TwinCAT3是Beckhoff推出的一款基于PC的控制器软件,简单理解是一套集成开发环境,里边有各种分析工具以及通信中间件;开发者可以很方便的用它来进行IPC和PLC之间的通信连接
ADS
倍福ADS(Automation Device Specification)是一个跨设备的网络通信协议(基于TCP/IP),依托TwinCAT提供的通信组件,它允许PLC、IPC之间进行数据分发、读写,支持同步、异步通信方式
环境搭建
VS2019
安装C++桌面开发组件
安装完Visual Studio版本信息页面如下
TwinCAT3
在使用ADS之前需要先安装TWinCAT3环境,我这里装的是V3.1.4024.55,属于TwinCAT3 Full版本,下载页面:https://www.beckhoff.com.cn/en-en/download/650023470
TwinCAT3 Full版本分XAR和XAE两部分,需要搭配Visual Studio版本使用
- XAE:eXtended Automation Engineerin,XAE是基于Visual Studio作为开发环境,进行多种语言的编程和硬件组态
- XAR:eXtended Automation Runtime,XAR是实时运行环境,对 TwinCAT 模块加载、执行、管理、实时运行与调用
TwinCAT3安装比较简单,勾选相应的组件,默认安装就可以了
Qt6.7.2
使用在线工具安装Qt6.7.2,第一次打开需要使用--mirror
命令指定软件源
qt-online-installer-windows-x64-4.8.0.exe --mirror https://mirror.nju.edu.cn/qt
Qt组件勾选
通信实验
操作流程
- VS2019 XAE新建PLC工程,配置工程,编译工程登入后可以查看PLC变量内存地址
- QtCreator新建C++ ADS Reader工程,根据PLC工程的IP和端口配置ADS连接
- QtCreator新建C++ ADS Writer工程,根据PLC工程的IP和端口配置ADS连接
- 在Reader进行数据读取操作,在Writer进行数据写入操作
PLC 编写PLC程序:定义BOOL、INT、REAL等3个变量类型数据
PROGRAM MAIN
VAR
boolVar1 AT%M*:BOOL;
intVar2 AT%M*:INT;
realVar3 AT%M*:REAL;
END_VAR
编译生成PLC应用并登入
打开Target Brownser
查看变量内存地址分布
变量 | 类型 | group | offset |
---|---|---|---|
boolVar1 | BOOL | 0x4020 | 0x5DFF0 |
intVar2 | INT | 0x4020 | 0x5DFF2 |
realVar3 | REAL | 0x4020 | 0x5DFF4 |
PLC和C++之间变量大小对应关系
变量类型 | C++ | 长度 |
---|---|---|
BOOL | bool | 1 |
INT | int | 4 |
UINT | unsigned int | 4 |
REAL | float | 4 |
LREAL | double | 8 |
Reader 建立ADS连接后读取指定地址(group + offset)的变量数据
#include <QCoreApplication>
#include <Windows.h>
#include "TcAdsDef.h"
#include "TcAdsAPI.h"
int main(int argc, char *argv[])
{
long ret, port;
AmsAddr addr;
bool byte;
port = AdsPortOpen();
ret = AdsGetLocalAddress(&addr);
if (ret)
{
qDebug() << "AdsGetLocalAddress : " << ret;
}
if (port == addr.port)
{
qDebug() << "LocalAdsPort: " << port << " opened!";
}
else
{
qDebug() << "LocalAdsPort open failed!";
}
addr.port = 851;
int time = 0;
int indexGroup = 0x4020;
float var;
while (1)
{
ret = AdsSyncReadReq(&addr, indexGroup, 0x5dff0, sizeof(bool), &byte);
if(!ret) {
qDebug() << "boolVar1 : " << byte;
}
ret = AdsSyncReadReq(&addr, indexGroup, 0x5dff2, sizeof(int), &time);
if(!ret) {
qDebug() << "intVar2 : " << time;
}
ret = AdsSyncReadReq(&addr, indexGroup, 0x5dff4, sizeof(float), &var);
if(!ret) {
qDebug() << "realVar3 : " << var;
}
Sleep(1000);
}
return 0;
}
Writer 建立ADS连接后往指定变量地址(group + offset)写入数据
#include <QCoreApplication>
#include <Windows.h>
#include "TcAdsDef.h"
#include "TcAdsAPI.h"
int main(int argc, char *argv[])
{
long ret, port;
AmsAddr addr;
bool byte = false;
port = AdsPortOpen();
ret = AdsGetLocalAddress(&addr);
if (ret)
{
qDebug() << "AdsGetLocalAddress : " << ret;
}
if (port == addr.port)
{
qDebug() << "LocalAdsPort: " << port << " opened!";
}
else
{
qDebug() << "LocalAdsPort open failed!";
}
addr.port = 851;
int time = 0;
int indexGroup = 0x4020;
while (1)
{
byte = !byte;
ret = AdsSyncWriteReq(&addr, indexGroup, 0x5dff0, sizeof(bool), &byte);
time++;
ret = AdsSyncWriteReq(&addr, indexGroup, 0x5dff2, sizeof(int), &time);
float var = time * 0.9 + 3.14;
ret = AdsSyncWriteReq(&addr, indexGroup, 0x5dff4, sizeof(float), &var);
Sleep(1000);
}
return 0;
}
CMakeLists.txt
两个工程的CMake写法参考:需要include几个头文件(afxstr.h、TcAdsAPI.h、TcAdsDef.h、wingdi.h),然后链接TcAdsDll这个库
cmake_minimum_required(VERSION 3.14)
project(QtADS LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
include_directories(${CMAKE_SOURCE_DIR}/Include)
link_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(QtADS
main.cpp
)
target_link_libraries(QtADS Qt${QT_VERSION_MAJOR}::Core TcAdsDll)
include(GNUInstallDirs)
install(TARGETS QtADS
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
接口说明
- 获取库版本号:AdsGetDllVersion
- 打开通信端口:ADSPortOpen
- 关闭通信端口:AdsPortClose
- 获取本机地址:AdsGetLocalAddress
- 获取错误信息:AdsGetLastError
- 同步写:AdsSyncWriteReq
- 同步读:AdsSyncReadReq
- 设备通知回调:AdsSyncAddDeviceNotificationReq
开源库
介绍
Qt封装的ADS组件也能很方便地进行ADS通信,支持QADSBOOL、QADSDINT、QADSDWORD、QADSENUM、QADSLREAL、QADSSTRING及对应的数组类型,所有数据类型都要持有通信的网络端口信息、节点信息,都要定义相应的value、setValue方法,但目前还没有支持Qt6,但改一改的话也可以用,需要进行两处改动:
① 将QString::SkipEmptyParts改为Qt::SkipEmptyParts
QString::SkipEmptyParts
改为
Qt::SkipEmptyParts
② QByteArray insert成员报错时需要把成员变成QByteArray兼容类型,通过toLatin1函数来转换
QByteArray sendValue = QByteArray(adsSymbolSize(),'\0');
sendValue.insert(0,val);
改为
QByteArray sendValue = QByteArray(adsSymbolSize(),'\0');
sendValue.insert(0,val.toLatin1());
示例
以BOOL类型数据访问为例:QADSBOOL通过配置端口、网络信息、节点名称等信息来访问节点
QADSBOOL *value = new QADSBOOL(this, 851, "local", "localhost", "MAIN.bTestVar1", QADSPLCVariable::ON_DEMAND, 0);
QtADS库封装了value、setValue等接口来进行读写操作
value->value();
value->setValue(false);
参考
【1】https://tr.beckhoff.com.cn/pluginfile.php/44857/mod_resource/content/0/ADS%E9%AB%98%E7%BA%A7%E5%9F%B9%E8%AE%AD.pdf
【2】https://tr.beckhoff.com.cn/mod/folder/view.php?id=2058 【3】https://github.com/Framatome/QtADS