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;
}
相关推荐
DARLING Zero two♡22 分钟前
关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
c语言·开发语言·科技
7年老菜鸡23 分钟前
策略模式(C++)三分钟读懂
c++·qt·策略模式
Gu Gu Study24 分钟前
【用Java学习数据结构系列】泛型上界与通配符上界
java·开发语言
Ni-Guvara31 分钟前
函数对象笔记
c++·算法
似霰35 分钟前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
芊寻(嵌入式)1 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
獨枭1 小时前
C++ 项目中使用 .dll 和 .def 文件的操作指南
c++
霁月风1 小时前
设计模式——观察者模式
c++·观察者模式·设计模式
橘色的喵1 小时前
C++编程:避免因编译优化引发的多线程死锁问题
c++·多线程·memory·死锁·内存屏障·内存栅栏·memory barrier
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript