C++倍福PLC通讯库

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

头文件

#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文件,其中的异常捕获机制是我自己写的,参考的朋友需要自行修改。

#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;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

pzb19841116

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值