「 C++ TwinCAT3 」倍福 “ADS通讯技术及工程实例”研究

本教程详细讲解了如何在Visual Studio与TwinCAT之间实现ADS通讯,包括上位机与下位机的工程搭建、变量定义、数据传输及程序编写流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

         本博客在具体的工程中,实现 Visual Studio(简称“上位机”) 与 TwinCAT(简称“下位机”) 之间的 ADS通讯,通过ADS通讯完成上位机与下位机之间的数据传输功能。

二、基本原理

   2.1 ADS通讯定义

     ADS(Advanced Design System)即先进设计系统,它为设备之间的通讯提供路由。在TwinCAT PC 和Beckhoff 的CX、BX、BC 系列控制器中都包含TwinCAT 信息路由器。因此各个ADS 设备之间都能够交换数据和信息。

   2.2 ADS通讯实现

    ADS通讯的实现思想并无难处,你可以简单理解两步:

  • 上位机把数据传给句柄
  • 句柄将数据赋值给下位机

     有一种“A传B, B传C”的感觉。理解这个理论后,你就已经掌握ADS通讯的80%了。本讲解面向ADS通讯的上位机程序与下位机程序在同一台电脑中运行,并且所有的执行过程都在上位机中编写。

三、ADS通讯技术研究

        3.1 引言

      这里将编写两部分工程文件,分别是 Visual Studio(上位机) 和 TwinCAT(下位机) 。

        3.2 Visual Studio (上位机)

      首先,在 Visual C++ 模板下建立一个名为:ADS_C_Program 的 MFC应用程序文件。

      然后,分别对下面三个文件进行编程

  • MFC
  • ADS_C_ProgramDlg.h
  • ADS_C_ProgramDlg.cpp

        3.2.1 MFC

      在做工程之前,需要明白两件事:我要做的什么?怎么实现?

      第一个问题可以在MFC文件中解决,本工程要求两机实现变量、数组和结构体的传输。所以设定界面如下图所示:

    3.2.2 ADS_C_ProgramDlg.h

       将 ADS_C_ProgramDlg.h 文件的编程分成分成三个模块

  • 头文件
  • 全局变量
  • 消息映射函数

      (1)头文件

       在添加头文件之前,我们需要添加链接库,以便实现通讯中用到的各种函数的直接调用。我们在左侧找到我们所建立的项目处,点击右键—>Properties 开始添加链接库,如下图所示:

        选择 Configuration Properties ->  Linker -> General -> Additional Library Directories,点击右边的按钮进入Additional Library Directories界面。如下图所示,添加我们的程序的所在目录( C:\TwinCAT\ADS Api\TcAdsDll\Lib ),点击确定。(本路径是以安装TWINCAT时的默认路径配置的,若用户在安装时选择自定义路径,则请用户自行修改)  。

       再选择Linker->input->Additional Dependencies,点击右边的按钮进入Additional Dependencies界面。如下图所示添加我们的.Lib文件的文件名(TcAdsDll.lib),点击确定。再次点击确定,链接库添加完成,如下图所示:

       这里共引入五个头文件,如下所示:

#include<iostream>		//标准的输入输出流头文件
#include<conio.h>		//控制台输入输出头文件
#include<windows.h>		//windowsAPI的函数声明和宏
#include"TcAdsDef.h"	//ADS函数的声明
#include"TcAdsAPI.h"	//结构体和常量的声明

         1)#include<iostream>           是:     标准的输入输出流头文件
         2)#include<conio.h>             是:     控制台输入输出头文件
         3)#include<windows.h>        是:     windowsAPI的函数声明和宏
         4)#include"TcAdsDef.h"        是:     ADS函数的声明
         5)#include"TcAdsAPI.h"        是:     结构体和常量的声明

         TcAdsDef.h 和 TcAdsAPI.h 需要研究员自行添加。方法:在 TwinCAT 文件夹中全局搜索这两个文件名,复制到你所做的工程下。然后,在解决方案的头文件文件夹中将添加两文件。最后,在程序中引用。

        (2)全局变量

//ADS通信变量
	long nErr;
	long nPort;
	AmsAddr Addr;
	PAmsAddr pAddr;

//全局变量
//bool 变量
	bool writebool;
	bool readbool;
//Int
	short writeint;
	short readint;
//long
	long writelong;
	long readlong;
//single
	float writesingle;
	float readsingle;
//double
	double writedouble;
	double readdouble;
//string
	char writestring;
	char readstring;
//struct 涉及到占位问题,因此添加几个Dummy占位,没有具体意义。
	typedef struct teststruct
	{
		bool test1;	//1
		bool dummy1;
		bool dummy2;
		bool dummy3;
		short test2;	//2
		short dummy4;
		long test3;		
		float test4;	
		double test5;	
	};
	teststruct writestruct;
	teststruct readstruct;

	short writearray[5];
	short readarray[5];

    (3)消息映射函数

       消息映射函数几乎都是由添加MFC工具时自动生成,也有一些为用户自行定义函数。本工程消息映射函数列表如下所示:

protected:
	HICON m_hIcon;
	
	ULONG testlHdlVar; 
	char testszVar;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedButton1();
	afx_msg void OnBnClickedButton2();
	afx_msg void OnDestroy();     
	afx_msg void OnBnClickedButton3();
	afx_msg void OnBnClickedButton4();
	afx_msg void OnBnClickedButton5();
	afx_msg void OnBnClickedButton6();
	afx_msg void OnBnClickedButton7();
	afx_msg void OnBnClickedButton8();
	afx_msg void OnBnClickedButton9();
	afx_msg void OnBnClickedButton10();
	afx_msg void OnBnClickedButton11();
	afx_msg void OnBnClickedButton12();
	afx_msg void OnBnClickedButton15();
	afx_msg void OnBnClickedButton16();
	afx_msg void OnBnClickedButton13();
	afx_msg void OnBnClickedButton14();
	afx_msg void OnBnClickedButton17();
	afx_msg void OnBnClickedButton18();
	afx_msg void OnBnClickedopenthread();
	afx_msg void OnBnClickedclosethread();
	virtual void Run(void);

        3.2.3 ADS_C_ProgramDlg.cpp

        将 ADS_C_ProgramDlg.cpp 文件的编程分成分成两个模块

  • 数据初始化
  • ADS通讯

        (1)数据初始化

           数据初始化包括:建立路由、获取NetID、设置PLC端口号、确定端口号、全局变量初始化。本工程设定数据如下:

//建立路由、获取NetID、设置PLC端口号
	pAddr = &Addr;
	nPort = AdsPortOpen();
	nErr = AdsGetLocalAddress(pAddr);

//确定端口号
	pAddr->port =851;

//全局变量初始化
//bool 变量
	writebool = 0;
	readbool = 0;
//Int
	writeint = 0;
	readint = 0;
//long
	writelong = 0;
	readlong = 0;
//single
	writesingle = 0;
	readsingle = 0;
//double
	writedouble = 0;
	readdouble = 0;
	writestruct.test1 = 0;
	writestruct.dummy1 = 0;
	writestruct.dummy2 = 0;
	writestruct.dummy3 = 0;
	writestruct.test2 = 0;
	writestruct.dummy4 = 0;
	writestruct.test3 = 0;
	writestruct.test4 = 0;
	writestruct.test5 = 0;
//数组初始化
	int i;
	for (i=0;i<5;i++)
	{
		writearray[i]=0;
		readarray[i]=0;
	}

      (2)ADS通讯

         本工程的ADS通讯部分涉及两个内容,数据写入和数据读取。这里以Int型数据传输为例。

        1)使用语句

             a. 定义句柄

        ULONG lHdlVar;

              b. 获取下位机变量

	char szVar[]={"MAIN.IntTest"};

              c. 获得句柄         

	nErr = AdsSyncReadWriteReq(pAddr,ADSIGRP_SYM_HNDBYNAME,0x0,sizeof(lHdlVar),&lHdlVar,sizeof(szVar),szVar);

               d. 写入值

	nErr = AdsSyncWriteReq(pAddr,ADSIGRP_SYM_VALBYHND,lHdlVar,2,&writeint);

               e. 读出值

	nErr = AdsSyncReadReq(pAddr,ADSIGRP_SYM_VALBYHND,lHdlVar,2,&readint);

               f. 释放句柄

	nErr = AdsSyncWriteReq(pAddr,ADSIGRP_SYM_RELEASEHND,0,sizeof(lHdlVar),&lHdlVar);

         2)完整代码

//WriteInt
void CADS_C_ProgramDlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	ULONG lHdlVar;

	char szVar[]={"MAIN.IntTest"};
	
	CString str;
	
	nErr = AdsSyncReadWriteReq(pAddr,ADSIGRP_SYM_HNDBYNAME,0x0,sizeof(lHdlVar),&lHdlVar,sizeof(szVar),szVar);
	
	GetDlgItemText(IDC_EDIT7,str);

	writeint=atoi(str);

	nErr = AdsSyncWriteReq(pAddr,ADSIGRP_SYM_VALBYHND,lHdlVar,2,&writeint);

	nErr = AdsSyncWriteReq(pAddr,ADSIGRP_SYM_RELEASEHND,0,sizeof(lHdlVar),&lHdlVar);

}

//ReadInt
void CADS_C_ProgramDlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	ULONG lHdlVar;
	char szVar [] = {"MAIN.IntTest"};
	CString str;
	nErr = AdsSyncReadWriteReq(pAddr,ADSIGRP_SYM_HNDBYNAME,0x0,sizeof(lHdlVar),&lHdlVar,sizeof(szVar),&szVar);

	nErr = AdsSyncReadReq(pAddr,ADSIGRP_SYM_VALBYHND,lHdlVar,2,&readint);

	nErr = AdsSyncWriteReq(pAddr,ADSIGRP_SYM_RELEASEHND,0,sizeof(lHdlVar),&lHdlVar);

	str.Format("%d",readint);
	SetDlgItemText(IDC_EDIT8,str);

}

        3.3 TwinCAT (下位机)

     在整个工程中,ADS通讯都是在上位机中编写的,这使得下位机变简单。首先,在  TwinCAT Project 模板下建立一个名为:ADS_PLC_Program 的文件。然后,整个程序分成两部分:

  • 定义变量
  • 编写程序

        3.3.1 定义变量

     (1)在建立一个工程后,我们需要在MAIN(PRG)中的变量区定义变量。代码如下:

PROGRAM MAIN
VAR
	BoolTest : BOOL; 	//布尔值测试
	IntTest : INT;	//整型测试
	LongTest : DINT;	//长整型测试
	SingleTest : REAL;	//单精度测试
	DoubleTest : LREAL;	//双精度测试
	StringTest : STRING;	//字符串测试
	readstringlen : INT;	//数组测试
	plcstruc : plcstructure;	//结构体测试
	
	plcarraytest : ARRAY[1..5] OF INT;	//五个整型
	override : ARRAY[1..10] OF LREAL;  //10个长实型
	
END_VAR

    (2)在DUTs建立新的数据单元(plcstructure)声明一个结构体。代码如下:

TYPE plcstructure :
STRUCT
	plcs1 : BOOL;
	dummy1:BOOL;
	dummy2:BOOL;
	dummy3:BOOL;
	
	plcs2:INT;
	dummy4:INT;
	
	plcs3:DINT;
	plcs4:REAL;
	plcs5:LREAL;
	
END_STRUCT
END_TYPE

        3.3.2 编写程序

        在本工程中,不需要下位机实现任何功能,所以随意写一句即可,如下图所示:

readstringlen:=LEN(StringTest);

        现在同时运行上位机和下位机,就可以实现ADS的通讯了。

四、小结

        ADS通讯并无难点,有固定的编程思维和程序模板。值得注意是,上位机中两个ADS通讯头文件的添加有点复杂。学习完本教程后,最好做到知识与实践相结合。

        小白将上述例程放在附件中,包含上位机、下位机和例程说明三部分,并且涉及到的知识点都做了详细的注释。例程只是辅助,若能通过上面的讲解独自实现功能,可称为学以成。

五、附件

       例程。链接:ADS通讯-例程_ads通讯-C++代码类资源-CSDN下载

       功能包括: ADS通讯、多媒体定时器、线程的应用。训练技能以ADS通讯为主。

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Robot_Starscream

祝好!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值