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;
}
相关推荐
Hy行者勇哥2 小时前
Python 与 VS Code 结合操作指南
开发语言·python
麦兜*8 小时前
Swift + Xcode 开发环境搭建终极指南
开发语言·ios·swiftui·xcode·swift·苹果vision pro·swift5.6.3
mit6.8249 小时前
[openvela] Hello World :从零开始的完整实践与问题复盘
c++·嵌入式硬件
萧鼎9 小时前
Python pyzmq 库详解:从入门到高性能分布式通信
开发语言·分布式·python
艾伦~耶格尔10 小时前
【集合框架LinkedList底层添加元素机制】
java·开发语言·学习·面试
yujkss10 小时前
Python脚本每天爬取微博热搜-终版
开发语言·python
yzx99101310 小时前
小程序开发APP
开发语言·人工智能·python·yolo
啊阿狸不会拉杆11 小时前
《算法导论》第 32 章 - 字符串匹配
开发语言·c++·算法
小学生的信奥之路11 小时前
洛谷P3817题解:贪心算法解决糖果分配问题
c++·算法·贪心算法
曙曙学编程12 小时前
stm32——GPIO
c语言·c++·stm32·单片机·嵌入式硬件