Unity使用Modbus协议

news2024/11/16 18:34:54

最近一直在工业领域干活,学习下Modbus协议,这里做个记录,理解不对的地方希望大佬指出修正。
一、先上测试工具和Unity脚本。
1.测试工具使用的 Modsim32
2.Unity测试脚本如下

/*
· 0x01:读线圈
· 0x05:写单个线圈
· 0x0F:写多个线圈
· 0x02:读离散量输入
· 0x04:读输入寄存器
· 0x03:读保持寄存器
· 0x06:写单个保持寄存器
· 0x10:写多个保持寄存器

*/

using Modbus.Device;
using Modbus.Extensions.Enron;
using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Unity.Collections.LowLevel.Unsafe;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
/// <summary>
/// Modbus Tcp/IP
/// </summary>
public class TestModBus : MonoBehaviour
{
    [Header("设备ID")]
    public byte deviceId;
    [Header("读取起始位置")]
    public ushort readStart;
    [Header("读取的长度")]
    public ushort readLength;
    [Header("写入的起始位置")]
    public ushort writeStart;
    [Header("写入的数据")]
    public ushort[] udata = new ushort[] { 100 };
    public bool[] coils;
    [Header("区域类型")]
    public ModbusPointType modbusPointType;

    public ModbusMaster modbusIpMaster;
    public TcpClient tcpClient;
    [Header("连接IP")]
    IPAddress address = new IPAddress(new byte[] { 127, 0, 0, 1 });
    [Header("连接端口")]
    public int port = 502;

    // Start is called before the first frame update
    void Start()
    {
        if (Connect(address.ToString(), port))
        {
            Debug.Log("连接成功");
        }
        else
        {
            Debug.Log("连接失败");
        }
    }
    public bool Connect(string ip, int port)
    {
        try
        {
            tcpClient = new TcpClient(ip, port);
            tcpClient.SendTimeout = 1;
            modbusIpMaster = ModbusIpMaster.CreateIp(tcpClient);
            return true;
        }
        catch (Exception ex)
        {
            if (tcpClient!=null)
            {
                tcpClient.Close();
            }

            Debug.LogError(ex.Message);
            return false;
        }
    }

    private void OnDestroy()
    {
        if (tcpClient!=null)
        {
            tcpClient.Close();
        }
    }
    

    /// 10进制转16进制 
    private byte GetHex(string msg)
    {
        byte hex = Convert.ToByte(msg);
        return hex;
    }
    ///16进制转10进制 
    public int GetDex(string msg)
    {
        int res = Convert.ToInt32(msg, 16);
        return res;
    }
    //退出的时候关闭连接
    private void OnApplicationQuit()
    {
        if (tcpClient!=null)
        {
            tcpClient.Close();
        }
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            WriteData(modbusPointType);
            //WriteMultipleRegisters(设备地址,寄存器起始地址, 要写入的值)  
            //modbusIpMaster.WriteMultipleRegisters(0x02, star, udata);
        }
        if (Input.GetKeyDown(KeyCode.R))
        {
            ReadData(modbusPointType);
            //ReadHoldingRegisters(设备地址, 寄存器起始地址, 读取数量);  读取多个寄存器
            //ushort[] msg = modbusIpMaster.ReadHoldingRegisters(0x01, 1, 0x06);

        }
    }
    /// <summary>
    /// (设备地址,寄存器起始地址, 要写入的值) 
    /// </summary>
    /// <param name="type"></param>
    private void WriteData(ModbusPointType type)
    {
        switch (type)
        {
            case ModbusPointType.Coil:
                modbusIpMaster.WriteMultipleCoils(deviceId, writeStart, coils);
                for (int i = 0; i < coils.Length; i++)
                {
                    Debug.LogFormat("Coil, {0},写入数据={1}", i, coils[i]);
                }
                break;
            case ModbusPointType.HoldRegister:
                modbusIpMaster.WriteMultipleRegisters(deviceId, writeStart, udata);
                for (int i = 0; i < udata.Length; i++)
                {
                    Debug.LogFormat("HoldRegister, {0},写入数据={1}", i, udata[i]);
                }
                break;
            default:
                break;
        }
    }
    /// <summary>
    /// (设备地址, 寄存器起始地址, 读取数量)
    /// </summary>
    /// <param name="type"></param>
    private void ReadData(ModbusPointType type)
    {
        bool[] msgBool;
        ushort[] msgShort;
        switch (type)
        {
            case ModbusPointType.Coil:
                msgBool = modbusIpMaster.ReadCoils(deviceId, readStart, readLength);
                for (int i = 0; i < msgBool.Length; i++)
                {
                    Debug.LogFormat("Coil, {0},接收到的数据={1}", i,msgBool[i]);
                }
                return;
            case ModbusPointType.Input:
                msgBool = modbusIpMaster.ReadInputs(deviceId, readStart, readLength);
                for (int i = 0; i < msgBool.Length; i++)
                {
                    Debug.LogFormat("Input, {0},接收到的数据={1}", i, msgBool[i]);
                }
                break;
            case ModbusPointType.InputRegister:
                msgShort = modbusIpMaster.ReadInputRegisters(deviceId, readStart, readLength);
                for (int i = 0; i < msgShort.Length; i++)
                {
                    Debug.LogFormat("InputRegister, {0},接收到的数据={1}", i, msgShort[i]);
                }
                break;
            case ModbusPointType.HoldRegister:
                msgShort = modbusIpMaster.ReadHoldingRegisters(deviceId, readStart, readLength);
                for (int i = 0; i < msgShort.Length; i++)
                {
                    Debug.LogFormat("HoldRegister, {0},接收到的数据={1}", i, msgShort[i]);
                }
                break;
            default:
                break;
        }
    }
}

public class IPTest
{
    public string ip;
}

public enum ModbusPointType
{
    Coil,//线圈  发送的二进制格式 可读写
    Input,//离散量输入 发送的二进制格式 只读
    InputRegister,//输入寄存器 发送的ushort格式 只读
    HoldRegister//保持寄存器  发送的ushort格式 可读写
}


二、连接创建。
请添加图片描述
1.创建连接,上方菜单栏点击连接设置,选择Modbus链接,其他的猜测是串口通信测试,没做具体研究。
2.大概百度学习了下,我理解的modbus是通过TCP链接使用的一种通信协议。
3.代码中直接使用的SocketTCP相关的代码创建的链接,只不过我之前使用的都是私有协议,自己定义消息协议,消息头、消息体之类的,modbus是大厂制定的一种通用消息协议,被沿用至今。
请添加图片描述
三、四种Point Type,代码中已经注释写明。
1.个人理解是四种数据类型,两个都可读,两个可写,可传输的值不同,适配不同的使用需求。
2.经过测试,向Coil中写入数据,再从Input中可读取到上一步写入的数据。
3.以下是对实际应用猜测,也是学习中不太确定的地方,希望有专业人士指导。
理解实际应用中比如报警状态识别功能,由硬件设备向Coil中写入报警状态,然后显示层可以从Input中读取对应的位置,这样避免显示层对报警状态做出修改,只有硬件本身可以设置报警状态,所以采用二进制的数据格式就可以了。
HoldRegister可以存储更多的数据,可用来记录复杂的操作,比如操作流程,或者可编程式的运行规则,同样是HoldRegister写入后,InputRegister提供了只读的访问方法,可以访问到HoldRegister写入的数据。
请添加图片描述
四、数据发送读取。
代码中已经封装读写功能,基本思路就是选择设备id,start起始位置,然后对应设置写入的数值,数值长度不能超过测试软件设置的数据结构的count大小。这个就类似socketTCP中拼协议,从索引第几位开始,写入多长的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1981820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理 —— 指令流水线影响因素分类

计算机组成原理 —— 指令流水线影响因素分类 结构冒险结构冒险的原因 数据冒险&#xff08;同步&#xff09;数据旁路的原理数据旁路的类型数据旁路的例子 控制冒险控制冒险的类型控制冒险的例子解决控制冒险的方法示例分析分支预测的策略 超标量和超流水超标量&#xff08;Su…

关于计算机的思考

本文是《Python入门经典以解决计算问题为导向的Python编程实践》一书中第一部分“关于计算机的思考”的笔记&#xff0c;后附上思维导图。 关于计算机的思考 一、为什么要研究计算机科学1、重要性2、“计算机科学”更强调计算而不是编程3、从”通过编程解决问题“的思路出发&a…

RPC通信的简单流程

远程调用者假设需要调用Login方法&#xff0c;将调用的信息通过muduo库&#xff0c;同时进行了序列化和反序列化&#xff0c;发送到Rpcprovider上&#xff0c;RpcProvider通过对象和方法表来确定需要调用哪个服务对象的哪个方法。 UserRpcServiceRpc和UseRpcServiceRpcStub是继…

去中心化社交:探讨Facebook在区块链平台上的实践

随着区块链技术的崛起&#xff0c;社交平台也面临着前所未有的变革。作为全球最大的社交平台之一&#xff0c;Facebook&#xff08;现名Meta Platforms&#xff09;正在积极探索如何将区块链技术融入其平台&#xff0c;以引领去中心化社交的新时代。本文将从不同角度探讨Facebo…

leaflet.motion台风路径动画绘制

在气象领域中&#xff0c;对台风的准确可视化呈现对于灾害预警和防范具有重要意义。本文将深入探讨一段使用 JavaScript 实现台风可视化功能的代码。原本只是简单的绘制台风的路径&#xff0c;但是后面的需求要求显示台风各个历史节点的动画绘制&#xff0c;于是难度增加了&…

《安全历史第4讲——从古代驿站体系看软件安全管控》

在古代&#xff0c;车、马都很慢&#xff0c;信息传递很不顺畅&#xff0c;中央的政令又是如何传达至地方的呢&#xff1f;实际上&#xff0c;很多朝代都有专门的驿站制度&#xff0c;可以保障全国各地的信息传递&#xff0c;对于维护统治和稳定有着关键作用。 若将国家比作一个…

OZON刚需产品哪些好卖,OZON刚需热卖产品

OZON平台上的刚需热卖产品涵盖了多个领域&#xff0c;这些产品通常能够满足消费者的基本需求或提升生活品质。以下是一些在OZON平台上表现良好的刚需热卖产品类别及其特点&#xff01; OZON刚需热卖产品地址&#xff1a;D。DDqbt。COm/74rDTop1 防蚊修复网 Скотч сет…

二次注入(2018网鼎杯comment)

一、2018网鼎杯comment 该题主要考察二次注入 1.二次注入概念&#xff1a; 攻击者构造恶意的数据并存储在数据库后&#xff0c;恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理&#xff0c;但在恶意数据插入…

【LeetCode Cookbook(C++ 描述)】一刷二叉树之递归遍历(DFS)(上)

目录 二叉树的实现LeetCode #144&#xff1a;Binary Tree Preorder Traversal 二叉树的前序遍历递归解法「遍历」思路「分而治之」思路更多例子&#xff1a;求二叉树最大深度 迭代解法Morris 遍历 LeetCode #94&#xff1a;Binary Tree Inorder Traversal 二叉树的中序遍历迭代…

亲民且友好的Top期刊,最快46天录用!

本期小编解析一本超亲民超友好的Top期刊&#xff0c;发文量大&#xff0c;编辑处理速度极快&#xff08;近期案例46天录用&#xff09;&#xff0c;毕业有高分区发文要求的小伙伴&#xff0c;赶紧码住这一本神刊&#xff01; 期刊简介 Knowledge-Based Systems (KBS) 出版社 …

AI智能测评应用平台项目分享

大家好&#xff0c;我是程序媛雪儿&#xff0c;今天咱们聊个我新学的项目&#xff0c;AI智能评测应用平台系统。 咱们先了解一下这个系统是干嘛的。 一、业务分析 大致业务流程是应用制作者在创建应用页面填写应用信息&#xff0c;依次添加题目和评分规则生成测评应用&#xff…

信息学奥赛初赛天天练-56-CSP-J2019完善程序2-双关键字排序、计数排序、前缀和、前缀自增、后缀自增、数组下标自增

PDF文档公众号回复关键字:20240805 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 计数排序 计数排序是一个广泛使用的排序方法。下面的程序使用双关键字计数排序&#xff0c;将 n 对 10000以内的整数&#xff0c;从小到大排序。 例如有三对整数 (3,4)、(2,…

标准IO及相关练习

标准IO 能够将指定的数据写入指定的文件中的操作&#xff08;通过文件指针去访问指定的文件&#xff1a;FILE*&#xff09;&#xff0c;标注IO只提供写入或者读取操作&#xff0c;不提供删除文件中的内容&#xff0c;想要删除文件&#xff0c;则需要自己写逻辑来实现。 文件指…

【LeetCode Cookbook(C++ 描述)】一刷哈希表(Hash Table)(下)

目录 LeetCode #349&#xff1a;Intersection of Two Arrays 两个数组的交集LeetCode #383&#xff1a;Ransom Note 赎金信LeetCode #454&#xff1a;4Sum II - 四数相加 II 本系列文章仅是 GitHub 大神 halfrost 的刷题笔记 《LeetCode Cookbook》的提纲以及示例、题集的 C转化…

办公楼子母钟系统,不止显示时间,还可以做临时告示牌

在现代办公环境中&#xff0c;时间管理对于提高工作效率至关重要。传统的时钟往往只能提供最基本的时间显示功能&#xff0c;而在快节奏的办公楼里&#xff0c;一个既能准确显示时间又能发布紧急通知的系统显得尤为必要。本文将介绍办公楼子母钟系统的独特优势及其在不同场景中…

TOOL使用

一、代码生成器 1.页面代码生成&#xff08;前端&#xff09; 生成后会在前端&#xff08;pc&#xff09;代码中看得到代码&#xff0c;可在此做二次开发&#xff1a; 代码生成器中新建不同模块&#xff0c;对应着modules文件夹下文件夹—>生成代码时&#xff0c;选择对应…

50etf期权怎么可以买跌做空吗?

50ETF期权可以做买方也可以做卖方&#xff0c;并且50ETF期权还能够买涨买跌双向交易&#xff0c;50ETF期权可以看涨期权和看跌期权&#xff0c;所以50ETF期权是可以买跌做空的&#xff0c;并且50ETF期权是很适合进行做空操作的&#xff0c;下文为大家介绍50etf期权怎么可以买跌…

如何将.bin文件,hex方式查看里面数据。以自己需要的任何长度来分割

liunux环境编译命令&#xff1a; gcc test.cpp -o testtest.cpp 文件&#xff1a; instring 为需要被分割的文件&#xff1a; outstring 为分割后的文件&#xff1a; #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.…

NSF共享目录未授权访问

NSF共享目录未授权访问 Network File System(NFS)&#xff0c;是由SUN公司研制的UNIX表示层协议(pressentation layer protocol)&#xff0c;能使使用者访问网络上别处的文件就像在使用自己的计算机一样。服务器在启用nfs服务以后&#xff0c;由于fs服务未限制对外访问&#x…

同步时钟系统,防水效果出色,无惧户外雨天环境

在我们的日常生活和工作中&#xff0c;时钟是不可或缺的存在。然而&#xff0c;传统时钟在使用过程中逐渐暴露出一些问题。 传统时钟通常依靠机械结构或简单的电子元件来保持时间的准确性&#xff0c;这使得它们容易受到外界因素的干扰。例如&#xff0c;温度的变化可能导致机芯…