C++倍福PLC通讯库

前段时间用上位机与倍福PLC通讯,调试通过了,代码发出来,大家一起学习

头文件

cpp 复制代码
#pragma once

#include <string>
using namespace std;


int TestPLCConn();

class PLC{
private:
	//记录PLC的IP地址和端口号
	string ip;
	int port;
	//暂时这么多参数,后续再添加

	int BeginCommu();

	int EndCommu();

	bool isOpen;

public:
	PLC();
	PLC(PLCPara &para);

	//测试PLC连接是否成功
	int TestConn();

	//设置PLC参数
	int SetPara(PLCPara& para);

	//接收心跳包
	int RecvHeartBeat(bool& heartBeat);

	//发送心跳包
	int SendHeartBeat();

};

CPP文件,其中的异常捕获机制是我自己写的,参考的朋友需要自行修改。

cpp 复制代码
#include "PLC.h"

#include <WinSock2.h>
#include "TcAdsDef.h"
#include "TcAdsAPI.h"
#include "CommonMatTool.h"

using namespace std;

#define RETURN_OK 0
#define RETURN_ERR -1

//用于记录PLC对象的执行情况,结束就置为true,自动发送心跳包直接关闭
bool isClose = false;

//用于记录PLC连接情况,连接就置为true
bool isLink = false;

//全局变量
AmsAddr Addr;

//将IP地址字符串解析成四个整数
void parseIPAddress(const std::string& ip, int& a, int& b, int& c, int& d) {
    // 使用 sscanf 函数解析 IP 地址字符串
    sscanf(ip.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d);
}


PLC::PLC()
{
}

PLC::PLC(PLCPara& para)
{
	ip = para.ip;
	port = para.port;
}

int PLC::TestConn()
{
    long nPort;
    int result = 0;
    nPort = AdsPortOpen();
    if (nPort == 0)
    {
        result = RETURN_ERR;
    }
    else
    {
        result = RETURN_OK;
    }
    AdsPortClose();

    return result;
    
}

//这是一个多线程的函数,用于发送心跳包给PLC

void AutoConnThread(void* para)
{
    while (true)
    {
        ((Robot*)para)->SendHeartBeat();

        Sleep(500);
        ((Robot*)para)->RecvHeartBeat(isLink);

        // 这个标志位为true,表明可以结束该进程了
        if (isClose)
        {
            break;
        }
    }
}


int PLC::SetPara(PLCPara& para)
{
    try
    {
        ip = para.ip;
        port = para.port;

        // 创建线程
        isClose = false;
        std::thread t(AutoConnThread, this);
        t.detach(); // 让线程在后台运行,不会自动销毁

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}

int PLC::BeginCommu()
{
    try
    {
        //如果已经建立了通信,需等待
        if (true == isOpen)
        {
            Sleep(10);
        }

        isOpen = true;

        long nPort;
        long nErr;

        //初始化内容:建立路由、获取NetID、设置PLC端口号
        nPort = AdsPortOpen();
        //如果是远程ADS则使用下面注释的两句确定AmsNetId,id填入远程控制器的ip
        int ip1, ip2, ip3, ip4;
        parseIPAddress(ip, ip1, ip2, ip3, ip4);

        AmsNetId id = { ip1,ip2,ip3,ip4,1,1 };
        Addr.netId = id;

        //确定端口号
        Addr.port = port;

        return RETURN_OK;
    }
    PRINT_ERR;
    
    return RETURN_ERR;
}

int PLC::EndCommu()
{
    try
    {
        // Close communication port
        AdsPortClose();

        isOpen = false;

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}


//写数据
int WriteData(string& str, void* p, int length)
{
    try
    {
        long nErr;
        ULONG     lHdlVar;
        char   szVar[100];// = { "MAIN.Test" };//通过变量名通讯
        std::strcpy(szVar, str.c_str());

        //得到句柄
        nErr = AdsSyncReadWriteReq(&Addr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar),
            &lHdlVar, sizeof(szVar), szVar);
        //写入值
        nErr = AdsSyncWriteReq(&Addr, ADSIGRP_SYM_VALBYHND, lHdlVar, length, p);
        //释放句柄
        nErr = AdsSyncWriteReq(&Addr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(lHdlVar), &lHdlVar);

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}

//读取数据
int ReadData(string& str, void* p, int length)
{
    try
    {
        long nErr;
        ULONG     lHdlVar;
        char   szVar[100];// = { "MAIN.Test" };//通过变量名通讯
        std::strcpy(szVar, str.c_str());


        //得到句柄

        nErr = AdsSyncReadWriteReq(&Addr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar), &lHdlVar, sizeof(szVar), szVar);
        //读出值
        nErr = AdsSyncReadReq(&Addr, ADSIGRP_SYM_VALBYHND, lHdlVar, length, p);
        //释放句柄
        nErr = AdsSyncWriteReq(&Addr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(lHdlVar), &lHdlVar);

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}

//读取PLC的状态
int PLC::GetStatus(STATUS& status)
{
    try
    {
        BeginCommu();
        bool result = false;

        string varName = "MAIN_Ads.st_plc_to_pc_check.bRq_GlassCheck";
        ReadData(varName, (void*)&result, sizeof(result));
        if (true == result)
        {
            status = STEP1;
            goto end;
        }

        varName = "MAIN_Ads.st_plc_to_pc_check.bRq_PositionTest";
        ReadData(varName, (void*)&result, sizeof(result));
        if (true == result)
        {
            status = STEP2;
            goto end;
        }

        varName = "MAIN_Ads.st_plc_to_pc_check.bRq_LoadCheck";
        ReadData(varName, (void*)&result, sizeof(result));
        if (true == result)
        {
            status = STEP3;
            goto end;
        }

        varName = "MAIN_Ads.st_plc_to_pc_check.bRq_UnloadCheck";
        ReadData(varName, (void*)&result, sizeof(result));
        if (true == result)
        {
            status = STEP4;
            goto end;
        }

        status = IDLE;

    end:
        EndCommu();

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}

/// <summary>
/// 接收PLC端的心跳信息
/// </summary>
/// <returns></returns>
int Robot::RecvHeartBeat(bool &heartBeat)
{
    try
    {
        heartBeat = false;
        BeginCommu();

        string varName = "MAIN_Ads.st_plc_to_pc_check.bConn";

        ReadData(varName, (void*)&heartBeat, sizeof(heartBeat));

        EndCommu();

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}

/// <summary>
/// 发送心跳信息
/// </summary>
/// <returns></returns>
int Robot::SendHeartBeat()
{
    try
    {
        static bool heartBeat = false;
        BeginCommu();

        string varName = "MAIN_Ads.st_pc_to_plc_check.bConn";
        //BOOL begin = true;

        WriteData(varName, (void*)&heartBeat, sizeof(heartBeat));

        //心跳信息取相反的值
        heartBeat = !heartBeat;

        EndCommu();

        return RETURN_OK;
    }
    PRINT_ERR;

    return RETURN_ERR;
}




//用作机器人通讯的测试,不是正式代码
int TestRobotConn()
{
    Robot robot;
    RobotPara para;
    para.ip = "192.168.1.2";
    para.port = 801;
    robot.SetPara(para);

    robot.SendHeartBeat();
    getchar();

    return RETURN_OK;
}
相关推荐
猷咪9 分钟前
C++基础
开发语言·c++
IT·小灰灰11 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧12 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q13 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳013 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾13 分钟前
php 对接deepseek
android·开发语言·php
CSDN_RTKLIB16 分钟前
WideCharToMultiByte与T2A
c++
2601_9498683617 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计31 分钟前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
蒹葭玉树42 分钟前
【C++上岸】C++常见面试题目--操作系统篇(第二十八期)
linux·c++·面试