Modbus_tcp

news/2024/9/18 21:06:22 标签: tcp/ip, 网络, 网络协议

目录

一:modbus起源

1.起源

2.  分类:

3.  优势:

4.  应用场景:

5.ModbusTCP特点(掌握):

二、  ModbusTCP的协议

1.  报文头

2.  寄存器

1. 线圈(Coils)

2. 离散量输入(Discrete Inputs)

3. 输入寄存器(Input Registers)

总结

3.功能码

01功能码分析

05功能码分析

0F功能码分析

练习:封装函数实现03,05功能码的作用


一: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,一般只有通讯量比较少时才会考虑它。

注:在ASCII模式下,每个8位的字节被拆分成两个ASCII字符进行发送,比如十六进制0xAF(1010 1111),会被分解成ASCII字符“A”(0100 0001)和”F”(0100 0110)进行发送,其发送量显然比RTU增加一倍。

3)Modbus TCP

运行在以太网上的协议

3.  优势:

免费、简单、容易使用

4.  应用场景:

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

5.ModbusTCP特点(掌握):

1)采用主从问答式通信

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

注:更好的理解网络模型的分层特点:

各层之间独立,每一层不需要知道下一层如何实现

当任何一层发生变化时,只要层间接口关系保持不变,则这层以上或以下层不受影响。

3)Modbus TCP端口号默认502

二、  ModbusTCP的协议

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

MBAP:Modbus Application Protocol (modbus报文头)

PDU:Protocol Data Unit(协议数据单元)

Modbus TCP/IP协议最大数据帧长度为260字节

1.  报文头

包含7个字节

2.  寄存器

1. 线圈(Coils)

  • 定义:线圈在Modbus协议中通常被类比为开关量,每一个bit都对应一个信号的开关状态。它主要用于控制IO设备的开关状态,如继电器、阀门等。
  • 访问类型:可读可写。通过发送特定的功能码(如01H、05H、0FH),可以读取或修改线圈的状态。
  • 应用场景:用于控制外部设备的开/关状态,如控制灯的亮灭、电机的启停等。

2. 离散量输入(Discrete Inputs)

  • 定义:离散量输入寄存器相当于线圈寄存器的只读模式,每个bit表示一个开关量,但只能读取输入的开关信号,不能修改。
  • 访问类型:只读。通过发送功能码02H,可以读取离散量输入寄存器的状态。
  • 应用场景:用于读取外部设备的状态,如按钮是否被按下、开关是否处于打开状态等。

3. 输入寄存器(Input Registers)

  • 定义:输入寄存器与保持寄存器类似,但它是只读的。每个输入寄存器占据两个byte的空间,可以存储16位的数据。
  • 访问类型:只读。通过发送功能码04H,可以读取输入寄存器的值。
  • 应用场景:用于读取工业设备的模拟量输入值,如温度、压力、流量等传感器的读数。

4. 保持寄存器(Holding Registers)

  • 定义:保持寄存器是Modbus协议中最重要的数据类型之一,它既可以读取也可以修改。每个保持寄存器同样占据2个byte的空间,可以存储16位的数据。
  • 访问类型:可读可写。通过发送功能码03H、06H或10H,可以读取或修改保持寄存器的值。
  • 应用场景:用于存储和修改设备的设定值、状态值等,如设置温度控制器的目标温度、读取设备的运行时间等。

总结

数据类型定义访问类型功能码应用场景
线圈开关量,每个bit对应一个信号的开关状态可读可写01H, 05H, 0FH控制外部设备的开/关状态
离散量输入类似线圈的只读模式,每个bit表示一个开关量只读02H读取外部设备的状态
输入寄存器类似保持寄存器的只读模式,每个寄存器占两个byte只读04H读取工业设备的模拟量输入值
保持寄存器既可以读取也可以修改,每个寄存器占两个byte可读可写03H, 06H, 10H存储和修改设备的设定值、状态值等

3.功能码

01功能码分析

05功能码分析

0F功能码分析

练习:封装函数实现03,05功能码的作用

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
void read_registers(uint8_t *p, uint16_t addr, uint16_t num, uint8_t *dest, int sockfd)
{
    p[8] = addr >> 8;
    p[9] = addr;
    p[10] = num >> 8;
    p[11] = num;
    send(sockfd, p, 12, 0);
    int ret = recv(sockfd, dest, 24, 0);
    if (ret < 0)
    {
        perror("recv err");
        close(sockfd);
        return;
    }
    else
    {
        for (int i = 0; i < ret; i++)
            printf("%02x ", dest[i]);
    }
    printf("\n");
}
void write_coil(uint8_t *p, uint16_t addr, int op, uint8_t *dest, int sockfd)
{
    p[8] = addr >> 8;
    p[9] = addr;
    p[11] = 0;
    if (op == 1)
    {
        p[10] = 0xFF;
    }
    else
    {
        p[10] = 0;
    }
    send(sockfd, p, 12, 0);
    int ret = recv(sockfd, dest, 24, 0);
    if (ret < 0)
    {
        perror("recv err");
        close(sockfd);
        return;
    }
    else
    {
        for (int i = 0; i < ret; i++)
            printf("%02x ", dest[i]);
    }
    printf("\n");
}
int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    // 1.创建套接字(socket)------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd);
    // 2.指定(服务器)网络信息--------》有对方的号码
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(502);
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    // 3.连接(connect)-------------------》拨打电话
    if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("connect err");
        return -1;
    }
    printf("connect okk\n");
    uint8_t data_reg[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03};
    uint8_t data_reg1[24] = {};
    uint16_t first;
    int num;
    printf("请输入读取保持寄存器起始地址:");
    scanf("%hx", &first);
    printf("请输入要查询的寄存器个数:");
    scanf("%d", &num);
    read_registers(data_reg, first, num, data_reg1, sockfd);
    uint8_t data_coil[12] = {0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x05};
    uint8_t data_coil1[24] = {};
    printf("请输入写入线圈起始地址:");
    scanf("%hx", &first);
    printf("请选择设置通断状态:");
    scanf("%d", &num);
    write_coil(data_coil, first, num, data_coil1, sockfd);
    close(sockfd);
    return 0;
}

http://www.niftyadmin.cn/n/5664525.html

相关文章

python生成器原理

#2-使用生成器生成斐波那契数列&#xff08;无限序列&#xff09; def fibonacci(): a, b 0, 1 while True: yield a a, b b, a b gen fibonacci() for _ in range(10): print(next(gen),end,) #第一次next后&#xff0c;执行fibonacci函数&#xff0c;到yield a处停止&a…

Python编码系列—Python组合模式:构建灵活的对象组合

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

SHL笔试测评系统题库考什么?如何通过综合测评|附性格测试104道

嘿&#xff0c;各位求职小伙伴们&#xff01;我是职小豚&#xff0c;今天就来带大家深入了解神秘又充满挑战的 SHL 笔试测评系统。 一、SHL 人才测评系统介绍 SHL 呀&#xff0c;那可是人才测评领域的超级大明星&#xff01;就像一个智慧的魔法师&#xff0c;用各种神奇的题目…

Kubernetes从零到精通(12-Ingress、Gateway API)

Ingress和Gateway API都是Kubernetes中用于管理外部访问集群服务的机制&#xff0c;但它们有不同的设计理念和适用场景。它们的基本原理是通过配置规则&#xff0c;将来自外部的网络流量路由到Kubernetes集群内部的服务上。 Ingress/Gateway API和Service Ingress/Gateway API…

linux-网络管理-防火墙配置

Linux 网络管理&#xff1a;防火墙配置 1. 防火墙概述 防火墙是保护计算机系统和网络免受未经授权访问和网络攻击的安全机制。Linux 系统中&#xff0c;防火墙通过控制进入和离开网络的数据包&#xff0c;实现网络流量的过滤和管理。 Linux 上的防火墙配置工具有多种&#x…

【每日刷题】Day124

【每日刷题】Day124 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. LCR 079. 子集 - 力扣&#xff08;LeetCode&#xff09; 2. 1863. 找出所有子集的异或总和再求和 …

笔试强训day15

平方数 牛妹是一个喜欢完全平方数的女孩子。 牛妹每次看到一个数 x&#xff0c;都想求出离 x 最近的完全平方数 y。 每次手算太麻烦&#xff0c;所以牛妹希望你能写个程序帮她解决这个问题。 形式化地讲&#xff0c;你需要求出一个正整数 y&#xff0c;满足 y 可以表示成 a2a^…

Linux定时启动jar应用shell脚本分享

1、如何精确找到jar应用进程 # 以 dist-app-manage.jar 为例 [rootlocalhost dist-app-manage-8083]# ps -ef|grep dist-app-manage.jar root 5134 5033 0 21:24 pts/0 00:00:00 grep --colorauto dist-app-manage.jar root 21766 1 1 Sep02 ? …