modbus协议及modbus TCP协议

一、Modbus协议
  • 1.起源

Modbus由Modicon公司于1979年开发,是一种工业现场总线协议标准

Modbus通信协议具有多个变种,其中有支持串口,以太网多个版本,其中最著名的是Modbus RTU(通信效率最高,基于串口)、Modbus ASCII和Modbus TCP(基于以太网)三种

其中Modbus TCP是在施耐德收购Modicon后1997年发布的。

2.分类

1)Modbus RTU

运行在串口上的协议,采用二进制表现形式以及紧凑的数据结构,通信效率较高,应用比较广泛

2)Modbus ASCII

运行在串口上的协议,采用ASCII码进行传输,并且每个字节的开始和结束都有特殊字符作为标志,传输效率远远低于Modbus RTU,一般只有通讯量比较少时才会考虑它。

3)Modbus TCP

运行在以太网上的协议

3.优势:

免费、简单、容易使用

4.应用场景:

Modbus协议是现在国内工业领域应用最多的协议,不只PLC设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备

二、Modbus tcp协议

1.特点

1)采用主从问答式通信

(一个主机可以对应多个从机,可以发出请求采集数据,发出请求控制设备)

2)Modbus TCP是应用层协议,基于传输层的TCP进行通信的

3)Modbus TCP端口号默认502

2.组成

ModbusTcp协议包含三部分:报文头、功能码、数据        

报文头7个字节,功能码1个字节,Modbus TCP/IP协议最大数据帧长度为260字节,最大252,(1 byte = 8 bit)

1)报文头

包含一个7字节报文头

事物处理标识符:没有限制,主机按照啥发,从机按照什么回

协议标识符:为啥是4个0?写一个0行不行?每一位都是16进制数 一位十六进制由4位2进制组成,8位2进制为一个字节

长度:

单元标识符:从机id

注意:报文头包含内容个数顺序均不可调换

2)寄存器

Modbus TCP通过寄存器的方式存储数据。

一共有四种类型的寄存器,分别是:离散量输入、线圈、输入寄存器、保持寄存器

离散量和线圈其实就是位寄存器(每个寄存器数据占1字节),工业上主要用于控制IO设备输入和保持寄存器是字寄存器(每个寄存器数据占2个字节),工业上主要用于存储工业设备的值

1) 离散量和线圈其实就是位寄存器(每个寄存器数据占1字节),工业上主要用于控制IO设备

线圈寄存器,类比为开关量,每一个bit都对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器支持读也支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。

离散输入寄存器离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。比如我读取外部按键的按下还是松开。

2) 输入和保持寄存器是字寄存器(每个寄存器数据占2个字节),工业上主要用于存储工业设备的值

保持寄存器,这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。比如我我设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写

输入寄存器,这个和保持寄存器类似,但是也是只支持读而不能写。一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值 

3)功能码(16进制)

寄存器PLC地址和寄存器的对应关系:

00001-09999 :线圈

10001-19999:离散量输入

30001-39999:输入寄存器

40001-49999:保持寄存器

点亮一个灯:05

读温湿度:04 03

具体协议分析:

实例分享 | ModbusTCP报文详解

4)总结

读数据:

主机--》从机:

报文头--功能码--起始地址--数量

从机--》主机:

报文头(长度可能发生变化)--功能码(不变)--字节计数--数据

在读数据和写单个的时候,字节长度都是0x06( 一个字节的单元标识符,一个字节的功能码,两个字节的地址,两个字节的数据)

写数据:

写单个:

主机--》从机:

报文头--功能码--地址--数据/断通标志(保持寄存器:数据:线圈:断通标志)

从机--》主机:

原文返回

写多个:

主机--》从机:

报文头----功能码----起始地址----数量----字节计数----数据

从机--》主机:  

原文返回

5)练习

练习一

主机询问数据流

00 03 00 00 00 06 01 03 00 63 00 02

00 00:事务处理标识符 

00 00:协议标识符

00 06 :字节 长度

03:功能码(保持寄存器)

0063:起始地址:6*16+3=99,40100

0002:寄存器的数量  40100-40101

00 03 00 00 00 07 01 03 04 05 83 00 76

00 00:事务处理标识符

00 00:协议标识符

00 07:字节长度

03:功能码

04:字节计数

0583:40100寄存器的数据

0076:40101寄存器的数据

练习2

1.读传感器数据,读1个寄存器数据,写出主从数据收发协议。

00 00 00 00  00 06 01 03 00 60 00 01

00 00 00 00  00 05 01 03 02 00 62

  1. 写出控制IO设备开关的协议数据,操作1个线圈,置1。

线圈单个置零:0000 置一:FF00

00 00 00 00  00 06 01 05 00 60 FF 00

00 00 00 00  00 06 01 05 00 60 FF 00

  • 工具安装
    1. Modbus Salve/Poll

1)安装过程:软件默认安装

2)破解:点击connection-》connect,输入序列号(序列号在SN.txt)

3)使用

从机:

先设置,先打开salve端,

再连接:点击connection-》connect

主机:

    1. 网络调试助手

    1. Wireshark

捕获器选择:

windows如果连接有线网络,选择本地连接/以太网

     如果连接无线网络,选择WLAN

如果只是在本机上的通信,选择NPCAP Loopback apdater

或Adapter for loopback traffic capture

过滤条件:

过滤端口:tcp.port==502

过滤IP:ip.addr == 192.168.3.11(windows 的ip)

  1. 练习

在虚拟机写程序实现poll端功能,编写客户端实现和Slave通信。

发送:发送Modbus TCP协议   03功能码

发送:uint8_t data[12]={0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x03,0x00,0x00,0x00,0x02};

接收:recv

#include <stdio.h>
#include <stdlib.h> // atoi
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    uint8_t data[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
                        0x01, 0x03, 0x00, 0x00, 0x00, 0x03};
    uint8_t buf[32] = {0};
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }

    //2.填充结构体
    struct sockaddr_in caddr;
    caddr.sin_family = AF_INET;
    caddr.sin_port = htons(502);
    caddr.sin_addr.s_addr = inet_addr(argv[1]);
    //3.链接
    if (connect(sockfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
    {
        perror("connect err");
        return -1;
    }
    //4.发送
    send(sockfd, data, sizeof(data), 0);
    //5.接收
    recv(sockfd, buf, sizeof(buf), 0);
    for (int i = 0; i < buf[8]; i++)
        printf("%#x ", buf[9+i]);
    putchar(10);
    //6.关闭
    close(sockfd);
    return 0;
}

作业:

  1. 复习今天内容
  2. 完成05功能码  ,写一个线圈
  3. 封装函数。。

/*客户端创建代码 */
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int sockfd;
uint8_t buf[32];
void writecoil(uint8_t *p, int addr, int num)
{
    p[7] = 0x05;
    p[8] = addr >> 8;   //寄存器高位
    p[9] = addr & 0xff; //寄存器低位
    if (num == 1)
    {
        p[10] = 0xff; //置1
    }
    else if (num == 0)
    {
        p[10] = 0x00; //置0
    }
    p[11] = 0x00;
    for (int j = 0; j < 12; j++)
    {
        printf("%#x ", *(p+j));
    }
    send(sockfd, p, 12, 0);
    recv(sockfd, buf, sizeof(buf), 0);
    for (int i = 0; i < 12; i++)
    {
        printf("%#x ", buf[i]);
    }
    putchar(10);
}
void readregster(uint8_t *p, int addr, int num)
{
    p[7] = 0x03;
    p[8] = addr >> 8;   //寄存器高位
    p[9] = addr & 0xff; //寄存器低位
    p[10] = num >> 8;   //数量高位
    p[11] = num & 0xff; //数量低位
    for (int j = 0; j < 12; j++)
    {
        printf("%#x ", *(p + j));
    }
    putchar(10);
    send(sockfd, p, 12, 0);
    recv(sockfd, buf, sizeof(buf), 0);

    for (int i = 0; i < buf[8]; i++)
    {
        printf("%#x ", buf[9 + i]);
    }
    putchar(10);
}
void set_selve_id(uint8_t *p)
{
    p[6] = 0x01;
}
int main(int argc, char const *argv[])
{
    if (argc < 3)
    {
        printf("input err\n");
        return -1;
    }
    //创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    //填充结构体
    struct sockaddr_in caddr;
    caddr.sin_family = AF_INET;
    caddr.sin_port = htons(atoi(argv[2]));
    caddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t len = sizeof(caddr);
    //链接
    if (connect(sockfd, (struct sockaddr *)&caddr, len) < 0)
    {
        perror("connect err.");
        return -1;
    }
    // uint8_t data[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00, 0x07, 0xFF, 0x00};
    // uint8_t data1[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x03};
    uint8_t data[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06};
    int th = sizeof(data);
    int addr = 0x0101;
    int num = 0x0000;
    set_selve_id(data);
    // readregster(data, 0, 2);
    writecoil(data, 6, 1);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【鸿蒙生态千帆起】HarmonyOS 系统级地图与位置服务,赋能广大开发者

在"与 HarmonyOS 同行&#xff0c;开放生态&#xff0c;共赢未来"为主题的 HUAWEI Developer Day&#xff08;简称 HDD&#xff09;沙龙中&#xff0c;Petal Maps 为开发者们带来了在 HarmonyOS 下地图领域的最新技术探索与实践成果。 得益于 HarmonyOS 一次开发多端…

[点云分割] 欧式距离分割

效果&#xff1a; 代码&#xff1a; #include <iostream> #include <chrono>#include <pcl/ModelCoefficients.h> // 模型系数的定义 #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> // 各种点云数据类型 #include <pcl/sample_c…

探讨大型公共建筑能耗监测与信息管理系统研究及应用

安科瑞 华楠 摘要&#xff1a;文章通过阐述大型公共建筑能耗现状&#xff0c;突出大型公共建筑实施节能监管的必要性&#xff0c;并在系统总结运用技术手段实施建筑能耗监测的基础上&#xff0c;介绍了江苏省建筑能耗监测系统研究过程中的技术创新和应用情况。 关键词&#x…

新手做抖店,这6点建议一定要收好,能让你不亏钱!

我是电商珠珠 我呢&#xff0c;目前身居郑州。 电商这个行业也做了5年多了&#xff0c;抖店从20年开始做&#xff0c;到现在也已经快3年了。 其实&#xff0c;我做抖店期间呢&#xff0c;踩过很多坑&#xff0c;所以今天就把我所踩过的坑&#xff0c;给做抖店的新手总结了6点…

opencv-图像对比度增强

对比度增强&#xff0c;即将图片的灰度范围拉宽&#xff0c;如图片灰度分布范围在[50,150]之间&#xff0c;将其范围拉升到[0,256]之间。这里介绍下 线性变换&#xff0c;直方图正规化&#xff0c;伽马变换&#xff0c;全局直方图均衡化&#xff0c;限制对比度自适应直方图均衡…

SSM客户管理系统CRM开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 客户管理系统CRM是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

left join查询耗时太慢,添加索引解决问题

背景 因为最近自己用的小app越用感觉加载越慢&#xff0c;以为是自己app开发逻辑出现问题了&#xff0c;结果才发现是自己很早以前的代码用到的是left join多表联查&#xff0c;以前因为数据少&#xff0c;所以没有感觉&#xff0c;现在数据量稍微一大&#xff0c;耗时就非常严…

git命令 cherry-pick

参考&#xff1a;https://blog.csdn.net/weixin_42585386/article/details/128256149 https://blog.csdn.net/weixin_44799217/article/details/128279250 merge和cherry-pick的区别&#xff1a; merge&#xff1a;是把某一个代码分支完全合并到当前的代码分支。完全合并的意…

redis的性能管理及集群架构(主从复制、哨兵模式)

一、redis的性能管理 1、内存指标info memory 内存指标&#xff08;重要&#xff09; used_memory:853736 数据占用的内存 used_memory_rss:10551296 redis向操作系统申请的内存 used_memory_peak:853736 redis使用内存的峰值 注&#xff1a;单位&#xff1a;字节 系…

向日葵x华测导航:远程控制如何助力导航测绘设备运维

导航测绘在各个领域均在发挥积极作用&#xff0c;其中RTK载波相位差分技术是导航测绘领域所常用的主流技术&#xff0c;该技术基于卫星定位系统的基础定位数据&#xff0c;可以实现在野外实时获取厘米级精度的定位数据&#xff0c;一定程度上省去了事后解算的麻烦。相应的&…

macos端文件夹快速访问工具 Default Folder X 最新for mac

Default Folder X 是一款实用的工具&#xff0c;提供了许多增强功能和快捷方式&#xff0c;使用户能够更高效地浏览和管理文件。它的快速导航、增强的文件对话框、自定义设置和快捷键等功能&#xff0c;可以大大提升用户的工作效率和文件管理体验。 快速导航和访问&#xff1a;…

steam游戏找不到steam_api64.dll,分享三个有效的解决方法

在现代科技发展的时代&#xff0c;游戏已经成为了许多人生活中不可或缺的一部分。而Steam作为全球最大的数字发行平台之一&#xff0c;拥有着庞大的游戏库和活跃的用户群体。然而&#xff0c;在使用Steam时&#xff0c;有些用户可能会遇到Steam_api64.dll丢失的问题&#xff0c…

QT mysql 数据库线程池 与数据库操作封装

最近事情比较多很久没有写学习笔记了&#xff0c;数据库线程池&#xff0c; 数据库封装&#xff0c;虽说数据库操作有很多不需要写sql 的&#xff0c;ORM 封装的方式去操作数据库。但是从业这些年一直是自己动手写sql &#xff0c;还是改不了这个习惯。不说了直接上代码。 数据…

想打造私域流量帝国?先解决这4个难题!

一、谁是你的目标用户 1. 清晰界定目标用户&#xff1a;确定你的产品或服务主要面向的用户群体&#xff0c;如年龄段、性别、职业等特征。 2. 确定最有购买力的用户群体&#xff1a;分析哪个用户群体在购买你的产品或服务时更容易乐于支付&#xff0c;并将其作为重点关注对象。…

skywalking中gateway的拓扑图没有出现

背景&#xff1a; 刚开始的时候gateway没有出现&#xff0c;后来百度说添加插件的jar包&#xff0c; apm-spring-cloud-gateway-2.1.x-plugin-8.15.0.jar apm-spring-webflux-5.x-plugin-8.15.0.jar 然后解决了gateway节点出来了&#xff0c; 但是&#xff1a;拓扑图却是User指…

我们对凌鲨的一次重构

在10月我们对凌鲨进行了一次重构&#xff0c;把所有鸡肋的功能都删除了。 新版本界面 老版本界面 我们干掉的功能 移除沟通频道功能 沟通频道类似slack功能&#xff0c;用于团队沟通。由于国内有大量的沟通软件&#xff0c;比如企业微信&#xff0c;飞书&#xff0c;钉钉等。…

用HALCON标定助手对相机进行标定

任务要求&#xff1a; 已知相机镜头焦距f为8mm&#xff0c;相机单个CCD像素在水平和竖直两个方向上的尺寸均为3.75微米&#xff0c;相机为普通透光镜头和面阵相机&#xff0c;对相机进行标定&#xff0c;测量相机的内外参数。 操作步骤&#xff1a; 1. 在HALCON中运行gen_ca…

实时数据备份实践inotify和rsync联动

目录 一、实时数据备份 1.实时数据备份 2.定时任务周期性的数据备份 3.实时数据备份 4.Inotify机制 二、实践 1.实时复制环境准备 2.实时复制概念 3.InofityRsync实施复制实战 4.配置好rsync守护进程 5.检查linux是否支持inotify 6.安装inotyify--tools 7.inotify…

易点易动设备管理系统:提升企业设备巡检效率的最佳选择

在现代企业运营中&#xff0c;设备管理扮演着至关重要的角色。设备巡检旨在确保设备的正常运行和及时维护&#xff0c;以确保生产线的顺畅运行和业务的高效执行。然而&#xff0c;传统的设备巡检方法常常效率低下、耗时费力。针对这一问题&#xff0c;易点易动设备管理系统应运…

window文件夹下python脚本实现批量删除无法预览的图片

你是否遇到过下载的图片会发现有些图片会无法预览情况&#xff1f; 有几种原因可能导致一些图片在预览时无法正常显示&#xff1a; 损坏的图片文件&#xff1a; 图片文件可能损坏或者部分损坏&#xff0c;导致无法被正常解析和预览。这种情况可能是因为文件在传输过程中损坏、…