精华内容
下载资源
问答
  • MODBUS TCP

    2020-10-30 16:21:41
    三菱电机Q系列PLC MODBUS TCP通信程序 QJ71E71-100 与电子枰通信样例程序(协议宏块)
  • modbus TCP

    2018-05-30 22:31:41
    modbus TCP 工具,分为TCP服务器通讯V1.2 TCP客户端通讯V1.2
  • modbus tcp

    2018-01-10 13:07:44
    基于linux 操作系统 modbus tcp 测试源码。基于tcpmodbus
  • Modbus TCP

    2020-12-02 14:48:15
    <div><p>How to implement Modbus TCP protocol using modbus-serial? Its has modbus over tcp, etc.</p><p>该提问来源于开源项目:yaacov/node-modbus-serial</p></div>
  • 三菱FX5U实现ModbusTCP通讯,ModbusTCP从站和ModbusTCP主站,对FX5U进行配置,实现ModbusTCP的数据交换
  • Modbus Tcp

    千次阅读 2019-06-27 12:38:25
    Modbus数据帧 MBAP报文头 MBAP为报文头,长度为7字节 ...00 00表示ModbusTCP协议 长度 2字节 表示接下来的数据长度,单位为字节 单元表示符 1字节 串行链路或其它总线上连接的远程从站地址 帧结构PDU PD...

    Modbus数据帧

    在这里插入图片描述

    MBAP报文头

    MBAP为报文头,长度为7字节

    长度 描述
    事务处理标识符 2字节 可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文
    协议标识符 2字节 00 00表示ModbusTCP协议
    长度 2字节 表示接下来的数据长度,单位为字节
    单元表示符 1字节 串行链路或其它总线上连接的远程从站地址

    帧结构PDU

    PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。

    功能码

    modbus的操作对象有四种:线圈、离散输入、输入寄存器、保持寄存器。

    线圈:PLC的输出位,开关量,在MODBUS中可读可写
    离散量:PLC的输入位,开关量,在MODBUS中只读
    输入寄存器:PLC中只能从模拟量输入端改变的寄存器,在MODBUS中只读
    保持寄存器:PLC中用于输出模拟量信号的寄存器,在MODBUS中可读可写
    根据对象的不同,modbus的功能码有:

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

    示例

    读取从站保持寄存器40001-40024的值

    查询命令:
    0, 30, 0, 0, 0, 6, 6, 3, 0, 1, 0, 24

    0, 30, 事务处理标识符 2字节
    0, 0, 协议标识符 2字节
    0, 6, 长度 2字节
    6, 从站地址 1字节
    3, 功能码 1字节 0x03:读保持寄存器
    0, 1, 起始地址,高位在前 2字节
    0, 24 读寄存器数量 高位在前 2字节

    响应命令:
    0, 30, 0, 0, 0, 51, 6, 3, 48, 144, 194, 252, 65, 89, 114, 59, 66, 187, 187, 121, 66, 123, 148, 153, 66, 205, 12, 177, 66, 7, 250, 192, 66, 205, 204, 199, 66, 79, 219, 196, 66, 20, 110, 184, 66, 113, 189, 163, 66, 92, 207, 136, 66, 167, 141, 84, 66

    展开全文
  • 初识Modbus TCP/IP-C#编写Modbus TCP客户端程序 配合相关博文 http://blog.csdn.net/thebestleo/article/details/52331976 学习
  • Modbus TCp

    2020-12-08 21:10:55
    <div><p>Hi, <p>can you show to me how to use your Modbus TCC module on web site? </p><p>该提问来源于开源项目:Cloud-Automation/node-modbus</p></div>
  • FX5U 与 FX5U Modbus TCP 协议通讯。(通讯协议支持功能) 参考手册:FX5U 用户手册(Modbus 通讯篇) 测试样例思路:主站读取从站 Y0-Y7 的状态到以 D17 开始的数 据寄存器中(此例为 D17),主站读从站 D0,D1,D2...

    FX5U 与 FX5U Modbus TCP 协议通讯。(通讯协议支持功能) 参考手册:FX5U 用户手册(Modbus 通讯篇)

    测试样例思路:主站读取从站 Y0-Y7 的状态到以 D17 开始的数
    据寄存器中(此例为 D17),主站读从站 D0,D1,D2,D3,D4,D5 ,D6,D7 的值放到 D42-D49 中,为 1,2,3,4,5,6,7,8。

    一 主站设定:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    打开端口
    在这里插入图片描述
    第一协议设定
    在这里插入图片描述
    第二协议设定
    在这里插入图片描述
    通讯读出
    在这里插入图片描述
    二 从站设定:
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 根据上面的思路很容易理解,在modbus报文前,加上表的MBAP报文头,再去掉modbus 报文中的CRC校验就可以形成modbus TCP的报文,那么modbus报文格式是什么样的呢? modbus报文时根据不同的功能码,报文格式的形式是...

    首先我要说明一下,本人新手一枚,本文仅为同样热爱学习的同学提供参考,有不

    对的地方还请大家热心指出,本文只起到一个抛砖引玉的作用,希望看到本文的同学可

    以从中学习到少许知识,也希望可以跟各位读者成为朋友,多多交流,使学习不再孤单

    寂寞。

     

    由于本文太长,顾分为两部分,第二部分连接

    初识Modbus TCP/IP-------------C#编写Modbus TCP客户端程序(二)

     

    http://blog.csdn.net/thebestleo/article/details/52331976

     

    废话少说,我们直接上干的,学习知识,第一个是收集和查阅资料,这个是必须的。

     

    1、Modbus官方网站:http://www.modbus.org/

    2、Modbus协议规范英文原版:

       http://download.csdn.net/download/thebestleo/9609480

    3、Modbus协议规范中文版:

       http://download.csdn.net/download/thebestleo/9609620

    4、Modbus通讯的TCP实现指南:

       http://download.csdn.net/download/thebestleo/9609646  

    5、Modbu TCP服务器测试工具:

       http://download.csdn.net/download/thebestleo/9609665

    6、Modbu TCP客户端测试工具:

       http://download.csdn.net/download/thebestleo/9609676

    7、网络数据分析软件Wireshark:

       http://download.csdn.net/download/thebestleo/9613131

    8、文章中Modbus Slave的设置文件,打包下载一下,便于你的测试

       http://download.csdn.net/detail/thebestleo/9614679

    9、本文最终所写成的C#的Modbus TCP客户端程序

         http://download.csdn.net/download/thebestleo/9614682

     

    下面传一张modbus官网上的一张图片,是一个Modbus TCP的工具包,跟我上面给出的类似

     

    
     
        看见没,上述资料价值500美元,好了,我的工作到此结束,剩下的不给钱不说了大笑
     
        开个玩笑,我们继续。说实话,上述的资料我也没有特别仔细的看过,
     
       (等找个时间好好看看)
     
        这里我只是简单的理解一下Modbus TCP/IP协议的内容,就是去掉了modbus协议
     
    本身的CRC校验,增加了MBAP 报文头。(这里只是简单的理解,深入之后可能会有更
     
    多的东西需要学习,但为了可以快速入门,我们先按照这个思路往下走)。
     
    我们首先来看一下,MBAP 报文头都包括了哪些信息和内容
     
     
     
    事务元标识符(2个字节):用于事务处理配对。在响应中,MODBUS服务器复制请求的事务处理标识符。
     
    这里在以太网传输中存在一个问题,就是先发后至,我们可以利用这个事务处理
     
    标识符做一个TCP序列号,来防止这种情况所造成的数据收发错乱(这里我们先不
     
    讨论这种情况,这个事务处理标识符我们统一使用0x00,0x01)
     
    协议标识符(2个字节):modbus协议标识符为0x00,0x00
     
    长度(2个字节):长度域是下一个域的字节数,包括单元标识符和数据域。
     
    单元标识符(1个字节):这个好像是个站号,文档中的说明没怎么看懂,有明白的
     
    可以留言告诉我。
     
    根据上面的思路很容易理解,在modbus报文前,加上表的MBAP报文头,再去掉modbus
     
    报文中的CRC校验就可以形成modbus TCP的报文,那么modbus报文格式是什么样的呢?
     
    modbus报文时根据不同的功能码,报文格式的形式是不同的,下面我们具体用一个C#
     
    的例程来说明一下Modbus TCP报文的数据组成和传输方法。(这里很多同学会说,我
     
    对modbus不了解,对C#更是知道的更少了,不要紧,只要你有一点C语言和串口通信的
     
    基础,其他的你尽管抄袭过来,日后慢慢的消化理解,很多老师在教育学生的时候总是
     
    鼓励什么独立思考,严禁抄袭什么的,再我看来抄别人的并没有什么错,学习吗,就是
     
    站在前人的肩膀上看世界,很多东西你没有那个时间去研究,还有很多东西即使你有那
     
    个时间你也研究不出来,老师上课教的是啥,不都是抄袭前人的科研成果吗,要是什么
     
    都需要自己研究,还用老师教什么。)
     
    所以我在这里以一种开放的态度,撰写了本文,希望大家能相互学习进步。
     
    言归正传,我们来用C#写一个Modbus TCP的客户端程序,并使用Modbus Slave
     
    这个软件对程序的功能进行测试
     
    1、首先,作为客户端程序,我们要先针对服务器IP和端口建立一个连接,IP地址根据
     
       Modbus Slave,所在电脑的IP来确定,Modbus TCP的端口号是众所周知的502
     
     (为了保持程序的完整性,我把第一步的整个程序都贴出来,避免造成歧义。)
     
    using System;
    using System.Windows.Forms;
    using System.Net.Sockets;
    using System.Threading;
    using System.Net;
    
    namespace Modbus_TCP_Client
    {
        public partial class Form1 : Form
        {
            public Socket newclient;
            public bool Connected;
            public Thread myThread;
            public delegate void MyInvoke(string str);
            public Form1()
            {
                InitializeComponent();
            }
    
            private void exit_Click(object sender, EventArgs e)
            {
                Application.Exit();
            }
    
            public void Connect()
            {
                byte[] data = new byte[1024];
    
                string ipadd = serverIP.Text.Trim();//将服务器IP地址存放在字符串 ipadd中
                int port = Convert.ToInt32(serverPort.Text.Trim());//将端口号强制为32位整型,存放在port中
    
                //创建一个套接字 
    
                IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd), port);
                newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    
                //将套接字与远程服务器地址相连
                try
                {
                    newclient.Connect(ie);
                    connect.Enabled = false;//使连接按钮变成虚的,无法点击
                    Connected = true;
    
                }
                catch (SocketException e)
                {
                    MessageBox.Show("连接服务器失败  " + e.Message);
                    return;
                }
    
                ThreadStart myThreaddelegate = new ThreadStart(ReceiveMsg);
                myThread = new Thread(myThreaddelegate);
                myThread.Start();
                tmSend.Enabled = true;//增加定时发送需要将此功能打开
    
            }
    
            private void connect_Click_1(object sender, EventArgs e)
            {
                Connect();
            }
        }
    }
    

     

    2、为了避免连接服务器发生超时掉线,我们这里做一个定时发送的函数,保证
     
       在掉线时间范围内连续向服务器发送数据,注意,需要在连接函数中增加
     
       timersend.Enabled = true;,在连接服务器的同时来触发定时发送。
     
    private void timersend_Tick(object sender, EventArgs e)
    {
           int isecond = 5000;//以毫秒为单位
           timersend.Interval = isecond;//5秒触发一次
           byte[] data = new byte[] { 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01 };
           newclient.Send(data);
    }

     
     
    通过上面的两步,一个Modbus TCP的客户端连接已经建立起来了,下面我们就来分析
     
    Modbus TCP协议的具体内容与实现方式了。
     
    3、我们根据Modbus协议规范中文版中的内容,来写几个功能码的程序。
     
       我们直接用实例来说明:
     
     
    1)、01(0x01)功能码--------读线圈
     
    请求与响应格式
     
     
     
    这是一个请求读离散量输出20-38 的实例:
     
     
     
    由上图可以,我们来编程发送数据(这里需要注意一下,上述图片是
     
    从modbus协议文档上截取的,起始地址要根据你的服务器来具体分析,
     
    有的是从0开始的,有的是从1开始,所以起始地址应该是14)
     
    0x00,0x01,0x00,0x00,0x00,0x06,0x01,0x01,0x00,0x14,0x00,0x13
     
    private void send01_Click(object sender, EventArgs e)
    {
        byte[] data = new byte[] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00, 0x14, 0x00, 0x13;
        newclient.Send(data);
    }

     
     
    接收数据为:
     
    0x00,0x01,0x00,0x00,0x00,0x06,0x01,0x01,0x03,0xCD,0x6B,0x05
     
    这里还需要做一个接收函数和现实接收数据的文本框
     
    public void ReceiveMsg()
            {
                while (true)
                {
                    byte[] data = new byte[1024];//定义数据接收数组
                    newclient.Receive(data);//接收数据到data数组
                    int length = data[5];//读取数据长度
                    Byte[] datashow = new byte[length + 6];//定义所要显示的接收的数据的长度
                    for (int i = 0; i <= length + 5; i++)//将要显示的数据存放到数组datashow中
                        datashow[i] = data[i];
                    string stringdata = BitConverter.ToString(datashow);//把数组转换成16进制字符串
                    if (data[7] == 0x01) { showMsg01(stringdata + "\r\n"); };
                    if (data[7] == 0x02) { showMsg02(stringdata + "\r\n"); };
                    if (data[7] == 0x03) { showMsg03(stringdata + "\r\n"); };
                    if (data[7] == 0x05) { showMsg05(stringdata + "\r\n"); };
                    if (data[7] == 0x06) { showMsg06(stringdata + "\r\n"); };
                    if (data[7] == 0x0F) { showMsg0F(stringdata + "\r\n"); };
                    if (data[7] == 0x10) { showMsg10(stringdata + "\r\n"); };
                }
            }

     
    public void showMsg01(string msg)
    {
    
        //在线程里以安全方式调用控件
        if (receiveMsg01.InvokeRequired)
        {
            MyInvoke _myinvoke = new MyInvoke(showMsg01);
            receiveMsg01.Invoke(_myinvoke, new object[] { msg });
        }
        else
         {
            receiveMsg01.AppendText(msg);
         }
    
    }

     
    下面我来介绍1个测试工具,modbus slave,打开软件,点击Connection来建立一个
     
    modbus tcp服务器,如下图所示
     
     
    下面我们再来设置一下该软件,这里我们首先测试的是0x01功能码,所以我们点击Setup,设置如下图
     
     
     
     
    我们0x01功能码的例子是一个请求读离散量输出20-38,这里注意一下分析,
     
    0xCD是27-20,0x6B是35-28,0x05是43-36,这里从39到43用0来补齐
     
    下面我们在Modbus Slave中填写数据,如图所示
     
     
     
     
     
     
    下面,我们运行我们用C#编写的软件,并打开Wireshark来截取封包进行分析,
     
    截取封包如下图
     
    Modbus TCP请求
     
     
     
    Modbus TCP相应:
     
     
     
    再看一下我们软件接收到的数据
     
     
     
    2)、02(0x02)功能码--------读离散量输入
     
    请求与应答PDU
     
     
    这是一个请求读取离散量输入197-218 的实例:
     
     
     
    发送数据为:
     
    0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x00, 0xC5, 0x00, 0x16
     
    程序如下:
     
    private void send02_Click(object sender, EventArgs e)
    {
        byte[] data = new byte[] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x00, 0xC5, 0x00, 0x16 };
        newclient.Send(data);
    }

     
    接收数据为:
     
    0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0xAC, 0xDB, 0x35
     
    程序如下:
     
    public void showMsg02(string msg)
    {
    
        //在线程里以安全方式调用控件
        if (receive0x01.InvokeRequired)
        {
            MyInvoke _myinvoke = new MyInvoke(showMsg02);
            receive0x02.Invoke(_myinvoke, new object[] { msg });
        }
        else
        {
            receive0x02.AppendText(msg);
        }
    
    }
     
    我们再来看一下Modbus Slave设置
     
     
     
     
     
    我们再看一下Wireshark截取封包
     
    Modbus TCP请求
     
     
    Modbus TCP响应
     
     
     
    我们的软件所收到的数据
     
    展开全文
  • ModbusTCP Master是一款用于modbus tcp测试的软件,选择要测试的IP地址端口及测试功能码,可定义监测起始地址、监测地址长度,实时显示发送日志与日志,内附测试记录图。
  • 西门子_Generating the Parameters for the Modbus TCP Communication using the Modbus TCP Wizardpdf,
  • 本库连接 modbus tcp 协议的各种设备,比如 plc ,本人在项目中经常跟plc 打交道 modbus 库 dll 使得 c++ c#都能够进行调用使用。
  • modbus TCP 协议 modbus TCP 协议使用TCP 协议发送和接收modbus 消息。modbus TCP 消息结构如下,在modbus 消息的前面,添加了6个字节的头: Transaction Id Protocol Length Unit Address Message ...

    modbus TCP 协议

    modbus TCP 协议使用TCP 协议发送和接收modbus 消息。modbus TCP 消息结构如下,在modbus 消息的前面,添加了6个字节的头:

    Transaction Id Protocol Length Unit Address Message
    2 Bytes 2 Bytes 2 Bytes 1 Byte N Bytes

    Transaction Id :是本次交互的ID

    protocol :为0 表示modbusTCP 协议。

    length :后面的字节数

    unit Address 是设备地址

    message 是modbus PDU

    Modbus PDU

    Modbus Read Coils (01)

    请求

    Offset Length Description Values
    0 Byte Function Code 01
    2 Word First coil address 0000h - FFFFh
    4 Word Coil count 0001 - 07D0h

    响应

    Offset Length Description Values
    0 Byte Function Code 01
    1 Byte Byte Count (CoilCount + 7) / 8
    2 N Bytes Coil data ...

    Modbus Read Discrete Inputs (02)

    请求

    Offset Length Description Values
    0 Byte Function Code 02
    2 Word First input address 0000h - FFFFh
    4 Word Input count 0001 - 07D0h

    响应

    Offset Length Description Values
    0 Byte Function Code 02
    1 Byte Byte Count (InputCount + 7) / 8
    2 N Bytes Input data

    ...

     Modbus Read Holding Registers (03)

    请求

    Offset Length Description Values
    0 Byte Function Code 03
    2 Word First input address 0000h - FFFFh
    4 Word Register count 0001 - 007Dh

     响应

    Offset Length Description Values
    0 Byte Function Code 03
    1 Byte Byte Count RegisterCount * 2
    2 N Bytes Register data ...

     Modbus Read Input Registers (04)

    请求

    Offset Length Description Values
    0 Byte Function Code 04
    2 Word First input address 0000h - FFFFh
    4 Word Register count 0001 - 007Dh

     响应

    Offset Length Description Values
    0 Byte Function Code 04
    1 Byte Byte Count RegisterCount * 2
    2 N Bytes Register data ...

     Modbus Write Single Coil (05)

    请求

    Offset Length Description Values
    0 Byte Function Code 05
    2 Word First coil address 0000h - FFFFh
    4 Word Coil value 0x0000 or 0xFF00

     响应

    Offset Length Description Values
    0 Byte Function Code 05
    2 Word First coil address 0000h - FFFFh
    4 Word Coil value 0x0000 or 0xFF00

     Modbus Write Single Register (06)

    请求

    Offset Length Description Values
    0 Byte Function Code 06
    2 Word First register address 0000h - FFFFh
    4 Word Register value 0000h - FFFFh

    响应

    Offset Length Description Values
    0 Byte Function Code 06
    2 Word First register address 0000h - FFFFh
    4 Word Register value 0000h - FFFFh

    Modbus Write Multiple Registers (16) 

    请求

    Offset Length Description Values
    0 Byte Function Code 10h
    2 Word First register address 0000h - FFFFh
    4 Word Register Count 0000h - 007Bh
    5 Byte Byte Count 0000h - 007Bh
    6 N Words Register values ...

    响应

    Offset Length Description Values
    0 Byte Function Code 10h
    2 Word First register address 0000h - FFFFh
    4 Word Register Count 0000h - 007Bh

     实验项目

    我们编写了Mbed OS/STM32F429 上面的Modbus TCP server  和ubuntu OS 上的modbusTCP client。事实上TCP/IP 的server/client 和modbusTCP的master 和slave 的概念是容易混淆的。TCP的 server相当于modbus的slave.

    Mbed OS/STM32F429 上modbusTCP Slave 的实现

    #include "mbed.h"
    #include "EthernetInterface.h"
    static const char*          mbedIp       = "192.168.31.112";  //IP
    static const char*          mbedMask     = "255.255.255.0";  // Mask
    static const char*          mbedGateway  = "192.168.0.1";    //Gateway
    #define MODBUS_PORT 8888
    ///Function Code
    #define     READ_COILS        0x01
    #define     READ_INPUT_BITS   0x02
    #define     READ_REGS         0x03
    #define     READ_INPUT_REGS   0x04
    #define     WRITE_COIL        0x05
    #define     WRITE_REG         0x06
    #define     WRITE_COILS       0x0F
    #define     WRITE_REGS        0x10
    DigitalOut led(PC_6);
    uint8_t rbuffer[128];
    uint8_t tbuffer[128];
    uint16_t internal_register[512];
    uint8_t coils[8];
    uint16_t msg_id;
    uint8_t slaveid;
    uint8_t func;
    int  modbus_response(uint8_t func,uint16_t address,uint16_t amount ,uint16_t *value);
    int modbus_recieve(int length)
    {   uint16_t address;
        msg_id=(rbuffer[0]<<8)|rbuffer[1];
        slaveid=rbuffer[6];
        func=rbuffer[7];
        address=(rbuffer[8]<<8)|rbuffer[9];
         if(func == WRITE_COIL || func == WRITE_REG) {
             uint16_t value=(rbuffer[10]<<8)|rbuffer[11];
             if (address<16){
             internal_register[address]=value;
             printf("func:%2x address:%4x value:%4x",func ,address,value);
             uint16_t amount=0;
            return  modbus_response(func,address,amount,internal_register);     
                 }
             } else  if(func == WRITE_REGS){
                 uint16_t amount=(rbuffer[10]<<8)|rbuffer[11];
                   printf("func:%2x address:%4x amount:%4x",func ,address,amount);
                 for (int i=0;i<amount;i++){
                     internal_register[address+i]=(rbuffer[13+i*2]<<8)|rbuffer[14+i*2];
                     }
                return   modbus_response(func,address,amount,NULL);   
                 } else  if(func == READ_COILS || func == READ_INPUT_BITS) {
                        uint16_t amount=(rbuffer[10]<<8)|rbuffer[11];
                       printf("func:%2x address:%4x amount:%4x",func ,address,amount);
                     return    modbus_response(func,address,amount,internal_register);   
                     
                 } else if(func == READ_REGS || func == READ_INPUT_REGS) {
                          uint16_t amount=(rbuffer[10]<<8)|rbuffer[11];
                        printf("func:%2x address:%4x amount:%4x",func ,address,amount);  
                        return  modbus_response(func,address,amount,internal_register);    
                   }
             
       return 0;
    }
     
        
    int  modbus_response(uint8_t func,uint16_t address,uint16_t amount ,uint16_t *value){
            tbuffer[0]=(uint8_t) msg_id >> 8u;
            tbuffer[1]=(uint8_t) (msg_id & 0x00FFu);
            tbuffer[2]=0;
            tbuffer[3]=0;
            tbuffer[4]=0;
            tbuffer[6]=(uint8_t) slaveid;
            tbuffer[7] = (uint8_t) func;
            tbuffer[8]=(uint8_t) address>> 8u;
             tbuffer[9]=(uint8_t) (address & 0x00FFu);
        if(func == WRITE_COIL || func == WRITE_REG) {
             tbuffer[5] = 6;
            tbuffer[10] = (uint8_t) (value[0] >> 8u);
            tbuffer[11] = (uint8_t) (value[0] & 0x00FFu);
            return 12;
            } else if(func == WRITE_REGS){
                tbuffer[5] = 6;
            tbuffer[10] = (uint8_t) (amount >> 8u);
            tbuffer[11] = (uint8_t) (amount & 0x00FFu);
                return 12;
            } else if(func == READ_COILS || func == READ_INPUT_BITS) {
            tbuffer[5] = 6;
             uint8_t byte_count=(uint8_t) ((amount+7)/8);
             tbuffer[8]=byte_count;
          for (int i=0;i<byte_count;i++)
             tbuffer[9+i]=coils[i];
            return 9+byte_count;
        } else if(func == READ_REGS||READ_INPUT_REGS){
            tbuffer[5] = (uint8_t) (7 + 2 * amount);
            tbuffer[8] = (uint8_t) (amount*2);
            for(int i = 0; i < amount; i++) {
               tbuffer[9+ 2 * i] = (uint8_t) (value[i] >> 8u);
               tbuffer[10 + 2 * i] = (uint8_t) (value[i] & 0x00FFu);
              
            }
            return (9+amount*2);
        } 
        return 0;
        }
    int main()
    {
       printf("Modbus Server example\n\r");
        
        EthernetInterface eth;
         eth.set_network(mbedIp,mbedMask,mbedGateway);
        eth.connect();   
        printf("The Server IP address is '%s'\n\r", eth.get_ip_address());  
        TCPServer srv(&eth);     
        srv.bind(MODBUS_PORT);   
        srv.listen();   
        while(true){
            TCPSocket client;
            SocketAddress client_addr;
            char *buffer = "Hello TCP client!\r\n";    
            srv.accept(&client, &client_addr);      
            printf("Accepted %s:%d\n\r", client_addr.get_ip_address(), 
                        client_addr.get_port());   
         while(1){
         //   int rlen=srv.recvfrom(NULL,rbuffer, sizeof rbuffer); 
          int rlen =client.recvfrom(&client_addr,rbuffer, sizeof rbuffer); 
            if (rlen>0)
            {
            printf("length:%d\n",rlen);
             int tlen=  modbus_recieve(rlen);    
             if (tlen>0)                               
            client.send(tbuffer, tlen);
            }
        
            }
              
          }
          
        }

    Ubuntu OS 上Client 的实现

    modbusClient.cpp

    #include<stdlib.h>
    #include "modbus.h"
    #include<stdio.h>
    #include<iostream>
    #include<sys/types.h>
    using namespace std;
    int main(int argc, char **argv)
    {
     
        // create a modbus object
        modbus mb = modbus("192.168.31.112", 8888);
        // set slave id
        mb.modbus_set_slave_id(1);
    
        // connect with the server
        if (mb.modbus_connect()){   
        while(1){
        // write single reg                 function 0x06    
          mb.modbus_write_register(0x00,8); 
           // read input registers             function 0x04
        uint16_t read_input_regs[1];
        mb.modbus_read_input_registers(0x00, 1, read_input_regs);
        cout << "read_input_regs:"<<read_input_regs[0]<<endl;
       sleep(1);
        }
         };
     
    }
    

    modbus.h

    //
    // Created by Fanzhe on 5/28/2017.
    //
    
    #ifndef MODBUSPP_MODBUS_H
    #define MODBUSPP_MODBUS_H
    
    #include <cstring>
    #include <iostream>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    
    #define MAX_MSG_LENGTH 260
    
    ///Function Code
    #define     READ_COILS        0x01
    #define     READ_INPUT_BITS   0x02
    #define     READ_REGS         0x03
    #define     READ_INPUT_REGS   0x04
    #define     WRITE_COIL        0x05
    #define     WRITE_REG         0x06
    #define     WRITE_COILS       0x0F
    #define     WRITE_REGS        0x10
    
    ///Exception Codes
    
    #define    EX_ILLEGAL_FUNCTION  0x01 // Function Code not Supported
    #define    EX_ILLEGAL_ADDRESS   0x02 // Output Address not exists
    #define    EX_ILLEGAL_VALUE     0x03 // Output Value not in Range
    #define    EX_SERVER_FAILURE    0x04 // Slave Deive Fails to process request
    #define    EX_ACKNOWLEDGE       0x05 // Service Need Long Time to Execute
    #define    EX_SERVER_BUSY       0x06 // Server Was Unable to Accept MB Request PDU
    #define    EX_NEGATIVE_ACK      0x07
    #define    EX_MEM_PARITY_PROB   0x08
    #define    EX_GATEWAY_PROBLEMP  0x0A // Gateway Path not Available
    #define    EX_GATEWYA_PROBLEMF  0x0B // Target Device Failed to Response
    #define    EX_BAD_DATA          0XFF // Bad Data lenght or Address
    
    #define    BAD_CON              -1
    
    /// Modbus Operator Class
    /**
     * Modbus Operator Class
     * Providing networking support and mobus operation support.
     */
    class modbus {
    private:
        bool _connected{};
        uint16_t PORT{};
        int _socket{};
        uint _msg_id{};
        int _slaveid{};
        std::string HOST;
    
        struct sockaddr_in _server{};
    
    
        inline void modbus_build_request(uint8_t *to_send, uint address, int func) const;
    
        int modbus_read(int address, uint amount, int func);
        int modbus_write(int address, uint amount, int func, const uint16_t *value);
    
        inline ssize_t modbus_send(uint8_t *to_send, int length);
        inline ssize_t modbus_receive(uint8_t *buffer) const;
    
        void modbuserror_handle(const uint8_t *msg, int func);
    
        inline void set_bad_con();
        inline void set_bad_input();
    
    
    public:
        bool err{};
        int err_no{};
        std::string error_msg;
    
    
    
    
        modbus(std::string host, uint16_t port);
        ~modbus();
    
        bool modbus_connect();
        void modbus_close() const;
    
        void modbus_set_slave_id(int id);
    
        int  modbus_read_coils(int address, int amount, bool* buffer);
        int  modbus_read_input_bits(int address, int amount, bool* buffer);
        int  modbus_read_holding_registers(int address, int amount, uint16_t *buffer);
        int  modbus_read_input_registers(int address, int amount, uint16_t *buffer);
    
        int  modbus_write_coil(int address, const bool& to_write);
        int  modbus_write_register(int address, const uint16_t& value);
        int  modbus_write_coils(int address, int amount, const bool *value);
        int  modbus_write_registers(int address, int amount, const uint16_t *value);
    
    
    };
    
    
    /**
     * Main Constructor of Modbus Connector Object
     * @param host IP Address of Host
     * @param port Port for the TCP Connection
     * @return     A Modbus Connector Object
     */
    modbus::modbus(std::string host, uint16_t port=502) {
        HOST = host;
        PORT = port;
        _slaveid = 1;
        _msg_id = 1;
        _connected = false;
        err = false;
        err_no = 0;
        error_msg = "";
    }
    
    
    
    /**
     * Destructor of Modbus Connector Object
     */
    modbus::~modbus(void) = default;
    
    
    /**
     * Modbus Slave ID Setter
     * @param id  ID of the Modbus Server Slave
     */
    void modbus::modbus_set_slave_id(int id) {
        _slaveid = id;
    }
    
    
    
    /**
     * Build up a Modbus/TCP Connection
     * @return   If A Connection Is Successfully Built
     */
    bool modbus::modbus_connect() {
        if(HOST.empty() || PORT == 0) {
            std::cout << "Missing Host and Port" << std::endl;
            return false;
        } else {
            std::cout << "Found Proper Host "<< HOST << " and Port " <<PORT <<std::endl;
        }
    
        _socket = socket(AF_INET, SOCK_STREAM, 0);
        if(_socket == -1) {
            std::cout <<"Error Opening Socket" <<std::endl;
            return false;
        } else {
            std::cout <<"Socket Opened Successfully" << std::endl;
        }
    
        struct timeval timeout{};
        timeout.tv_sec  = 20;  // after 20 seconds connect() will timeout
        timeout.tv_usec = 0;
        setsockopt(_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
        setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    
        _server.sin_family = AF_INET;
        _server.sin_addr.s_addr = inet_addr(HOST.c_str());
        _server.sin_port = htons(PORT);
    
        if (connect(_socket, (struct sockaddr*)&_server, sizeof(_server)) < 0) {
            std::cout<< "Connection Error" << std::endl;
            return false;
        }
    
        std::cout<< "Connected" <<std::endl;
        _connected = true;
        return true;
    }
    
    
    /**
     * Close the Modbus/TCP Connection
     */
    void modbus::modbus_close() const {
        close(_socket);
        std::cout <<"Socket Closed" <<std::endl;
    }
    
    
    /**
     * Modbus Request Builder
     * @param to_send   Message Buffer to Be Sent
     * @param address   Reference Address
     * @param func      Modbus Functional Code
     */
    void modbus::modbus_build_request(uint8_t *to_send, uint address, int func) const {
        to_send[0] = (uint8_t) _msg_id >> 8u;
        to_send[1] = (uint8_t) (_msg_id & 0x00FFu);
        to_send[2] = 0;
        to_send[3] = 0;
        to_send[4] = 0;
        to_send[6] = (uint8_t) _slaveid;
        to_send[7] = (uint8_t) func;
        to_send[8] = (uint8_t) (address >> 8u);
        to_send[9] = (uint8_t) (address & 0x00FFu);
    }
    
    
    /**
     * Write Request Builder and Sender
     * @param address   Reference Address
     * @param amount    Amount of data to be Written
     * @param func      Modbus Functional Code
     * @param value     Data to Be Written
     */
    int modbus::modbus_write(int address, uint amount, int func, const uint16_t *value) {
        int status = 0;
        if(func == WRITE_COIL || func == WRITE_REG) {
            uint8_t to_send[12];
            modbus_build_request(to_send, address, func);
            to_send[5] = 6;
            to_send[10] = (uint8_t) (value[0] >> 8u);
            to_send[11] = (uint8_t) (value[0] & 0x00FFu);
            status = modbus_send(to_send, 12);
        } else if(func == WRITE_REGS){
            uint8_t to_send[13 + 2 * amount];
            modbus_build_request(to_send, address, func);
            to_send[5] = (uint8_t) (7 + 2 * amount);
            to_send[10] = (uint8_t) (amount >> 8u);
            to_send[11] = (uint8_t) (amount & 0x00FFu);
            to_send[12] = (uint8_t) (2 * amount);
            for(int i = 0; i < amount; i++) {
                to_send[13 + 2 * i] = (uint8_t) (value[i] >> 8u);
                to_send[14 + 2 * i] = (uint8_t) (value[i] & 0x00FFu);
            }
            status = modbus_send(to_send, 13 + 2 * amount);
        } else if(func == WRITE_COILS) {
            uint8_t to_send[14 + (amount -1) / 8 ];
            modbus_build_request(to_send, address, func);
            to_send[5] = (uint8_t) (7 + (amount + 7) / 8);
            to_send[10] = (uint8_t) (amount >> 8u);
            to_send[11] = (uint8_t) (amount & 0x00FFu);
            to_send[12] = (uint8_t) ((amount + 7) / 8);
            for(int i = 0; i < (amount+7)/8; i++)
                to_send[13 + i] = 0; // init needed before summing!
            for(int i = 0; i < amount; i++) {
                to_send[13 + i/8] += (uint8_t) (value[i] << (i % 8u));
            }
            status = modbus_send(to_send, 14 + (amount - 1) / 8);
        }
        return status;
    
    }
    
    
    /**
     * Read Request Builder and Sender
     * @param address   Reference Address
     * @param amount    Amount of Data to Read
     * @param func      Modbus Functional Code
     */
    int modbus::modbus_read(int address, uint amount, int func){
        uint8_t to_send[12];
        modbus_build_request(to_send, address, func);
        to_send[5] = 6;
        to_send[10] = (uint8_t) (amount >> 8u);
        to_send[11] = (uint8_t) (amount & 0x00FFu);
        return modbus_send(to_send, 12);
    }
    
    
    /**
     * Read Holding Registers
     * MODBUS FUNCTION 0x03
     * @param address    Reference Address
     * @param amount     Amount of Registers to Read
     * @param buffer     Buffer to Store Data Read from Registers
     */
    int modbus::modbus_read_holding_registers(int address, int amount, uint16_t *buffer) {
        if(_connected) {
            if(amount > 65535 || address > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            modbus_read(address, amount, READ_REGS);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, READ_REGS);
            if(err) return err_no;
            for(uint i = 0; i < amount; i++) {
                buffer[i] = ((uint16_t)to_rec[9u + 2u * i]) << 8u;
                buffer[i] += (uint16_t) to_rec[10u + 2u * i];
            }
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Read Input Registers
     * MODBUS FUNCTION 0x04
     * @param address     Reference Address
     * @param amount      Amount of Registers to Read
     * @param buffer      Buffer to Store Data Read from Registers
     */
    int modbus::modbus_read_input_registers(int address, int amount, uint16_t *buffer) {
        if(_connected){
            if(amount > 65535 || address > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            modbus_read(address, amount, READ_INPUT_REGS);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, READ_INPUT_REGS);
            if(err) return err_no;
            for(uint i = 0; i < amount; i++) {
                buffer[i] = ((uint16_t)to_rec[9u + 2u * i]) << 8u;
                buffer[i] += (uint16_t) to_rec[10u + 2u * i];
            }
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Read Coils
     * MODBUS FUNCTION 0x01
     * @param address     Reference Address
     * @param amount      Amount of Coils to Read
     * @param buffer      Buffer to Store Data Read from Coils
     */
    int modbus::modbus_read_coils(int address, int amount, bool *buffer) {
        if(_connected) {
            if(amount > 2040 || address > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            modbus_read(address, amount, READ_COILS);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, READ_COILS);
            if(err) return err_no;
            for(uint i = 0; i < amount; i++) {
                buffer[i] = (bool) ((to_rec[9u + i / 8u] >> (i % 8u)) & 1u);
            }
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Read Input Bits(Discrete Data)
     * MODBUS FUNCITON 0x02
     * @param address   Reference Address
     * @param amount    Amount of Bits to Read
     * @param buffer    Buffer to store Data Read from Input Bits
     */
    int modbus::modbus_read_input_bits(int address, int amount, bool* buffer) {
        if(_connected) {
            if(amount > 2040 || address > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            modbus_read(address, amount, READ_INPUT_BITS);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            if(err) return err_no;
            for(uint i = 0; i < amount; i++) {
                buffer[i] = (bool) ((to_rec[9u + i / 8u] >> (i % 8u)) & 1u);
            }
            modbuserror_handle(to_rec, READ_INPUT_BITS);
            return 0;
        } else {
            return BAD_CON;
        }
    }
    
    
    /**
     * Write Single Coils
     * MODBUS FUNCTION 0x05
     * @param address    Reference Address
     * @param to_write   Value to be Written to Coil
     */
    int modbus::modbus_write_coil(int address, const bool& to_write) {
        if(_connected) {
            if(address > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            int value = to_write * 0xFF00;
            modbus_write(address, 1, WRITE_COIL, (uint16_t *)&value);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, WRITE_COIL);
            if(err) return err_no;
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Write Single Register
     * FUCTION 0x06
     * @param address   Reference Address
     * @param value     Value to Be Written to Register
     */
    int modbus::modbus_write_register(int address, const uint16_t& value) {
        if(_connected) {
            if(address > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            modbus_write(address, 1, WRITE_REG, &value);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, WRITE_COIL);
            if(err) return err_no;
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Write Multiple Coils
     * MODBUS FUNCTION 0x0F
     * @param address  Reference Address
     * @param amount   Amount of Coils to Write
     * @param value    Values to Be Written to Coils
     */
    int modbus::modbus_write_coils(int address, int amount, const bool *value) {
        if(_connected) {
            if(address > 65535 || amount > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            uint16_t temp[amount];
            for(int i = 0; i < amount; i++) {
                temp[i] = (uint16_t)value[i];
            }
            modbus_write(address, amount, WRITE_COILS, temp);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, WRITE_COILS);
            if(err) return err_no;
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Write Multiple Registers
     * MODBUS FUNCION 0x10
     * @param address Reference Address
     * @param amount  Amount of Value to Write
     * @param value   Values to Be Written to the Registers
     */
    int modbus::modbus_write_registers(int address, int amount, const uint16_t *value) {
        if(_connected) {
            if(address > 65535 || amount > 65535) {
                set_bad_input();
                return EX_BAD_DATA;
            }
            modbus_write(address, amount, WRITE_REGS, value);
            uint8_t to_rec[MAX_MSG_LENGTH];
            ssize_t k = modbus_receive(to_rec);
            if (k == -1) {
                set_bad_con();
                return BAD_CON;
            }
            modbuserror_handle(to_rec, WRITE_REGS);
            if(err) return err_no;
            return 0;
        } else {
            set_bad_con();
            return BAD_CON;
        }
    }
    
    
    /**
     * Data Sender
     * @param to_send Request to Be Sent to Server
     * @param length  Length of the Request
     * @return        Size of the request
     */
    ssize_t modbus::modbus_send(uint8_t *to_send, int length) {
        _msg_id++;
        return send(_socket, to_send, (size_t)length, 0);
    }
    
    
    /**
     * Data Receiver
     * @param buffer Buffer to Store the Data Retrieved
     * @return       Size of Incoming Data
     */
    ssize_t modbus::modbus_receive(uint8_t *buffer) const {
        return recv(_socket, (char *) buffer, 1024, 0);
    }
    
    void modbus::set_bad_con() {
        err = true;
        error_msg = "BAD CONNECTION";
    }
    
    
    void modbus::set_bad_input() {
        err = true;
        error_msg = "BAD FUNCTION INPUT";
    }
    
    /**
     * Error Code Handler
     * @param msg   Message Received from the Server
     * @param func  Modbus Functional Code
     */
    void modbus::modbuserror_handle(const uint8_t *msg, int func) {
        if(msg[7] == func + 0x80) {
            err = true;
            switch(msg[8]){
                case EX_ILLEGAL_FUNCTION:
                    error_msg = "1 Illegal Function";
                    break;
                case EX_ILLEGAL_ADDRESS:
                    error_msg = "2 Illegal Address";
                    break;
                case EX_ILLEGAL_VALUE:
                    error_msg = "3 Illegal Value";
                    break;
                case EX_SERVER_FAILURE:
                    error_msg = "4 Server Failure";
                    break;
                case EX_ACKNOWLEDGE:
                    error_msg = "5 Acknowledge";
                    break;
                case EX_SERVER_BUSY:
                    error_msg = "6 Server Busy";
                    break;
                case EX_NEGATIVE_ACK:
                    error_msg = "7 Negative Acknowledge";
                    break;
                case EX_MEM_PARITY_PROB:
                    error_msg = "8 Memory Parity Problem";
                    break;
                case EX_GATEWAY_PROBLEMP:
                    error_msg = "10 Gateway Path Unavailable";
                    break;
                case EX_GATEWYA_PROBLEMF:
                    error_msg = "11 Gateway Target Device Failed to Respond";
                    break;
                default:
                    error_msg = "UNK";
                    break;
            }
        }
        err = false;
        error_msg = "NO ERR";
    }
    
    #endif //MODBUSPP_MODBUS_H
    

     

    展开全文
  • ModbusTCP

    2019-04-26 17:49:21
    https://download.csdn.net/download/thebestleo/9614682
  • 前言:但是上面的两篇文章是已经封装好的API,只要调用就可以实现功能了,对于想了解modbus tcp的原理的人可能就不适合了,最近有不少网友的想要了解这个协议,所以在这里再写一篇介绍Modbus tcp的文章,不过这篇...
  • 由于感觉上一次写的篇幅过长,所以新开一贴,继续介绍Modbus TCP/IP的初步认识, 书接上回 3)、03(0x03)功能码--------读保持寄存器 请求与响应格式 这是一个请求读寄存器108-110 的实例: 发送...
  • S7-1200 Modbus TCP 通信指令块STEP 7 V13 SP1 软件版本中的Modbus TCP库指令目前最新的版本已升至V4.0,该版本的使用需要具备以下两个条件:1. 软件版本: STEP 7 V13 SP1及其以上2. 固件版本: S7-1200 CPU 的固件...
  • 1 Modbus TCP通讯概述MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列讯协议的派生产品,显而易见,它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用...
  • ModBusTCP 和 ModBusRtu

    2020-10-11 00:42:55
    找了好多ModBus 的资源,只有这个可以真的用起来了。包含了ModBusTCP 和 ModBusRtu 两个部分。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,814
精华内容 1,125
关键字:

modbustcp