Modbus Slave学习笔记(二)

简介: Modbus Slave学习笔记

3.4差错检验

1.ASCII 模式

在 ASCII 模式中,报文包含一个错误校验字段。该字段由两个字符组成,其值基于对全部报文内容执行的纵向冗余校验(Longitudinal Redundancy Check, LRC)计算的结果而来,计算对象不包括起始的冒号(;)和回车换行符号(CRLF)。

2.RTU模式

在 RTU 模式中,报文同样包含一个错误校验字段。与 ASCII 模式不同的是,该字段由 16 个比特位共两个字节组成。其值基于对全部报文内容执行的循环冗

余校验(Cyclical Redundancy Check,CRC)计算的结果而来,计算对象包括校验域之前的所有字节。


3.4.1 LRC校验

(1)对消息帧中的全部字节相加(不包括起始";“和结束符"CR-LF”),并把结果送入 8 位数据区,舍弃进位。

(2)由 0xFF(即全 1)减去最终的数据值,产生 1的补码(即二进制反码)。


(3)加"1"产生二进制补码。


3.4.2 CRC校验

(1)预置一个值为 0xFFFF 的 16 位寄存器,此寄存器为 CRC寄存器。

(2)把第 1 个 8 位二进制数据(即通信消息帧的第 1 个字节)与 16 位的 CRC寄存器的相异或,异或的结果仍存放于该 CRC 寄存器中。

(3)把 CRC寄存器的内容右移一位,用 0 填补最高位,并检测移出位是 0 还是1。

(4)如果移出位为零,则重复步骤(3)(再次右移一位);如果移出位为 1,则CRC 寄存器与0xA001 进行异或。

(5)重复步骤(3)和(4),直到右移 8 次,这样整个 8 位数据全部进行了处理。(6)重复步骤(2)~(5),进行通信消息帧下一个字节的处理。

(7)将该通信消息帧所有字节按上述步骤计算完成后,得到的 16 位 CRC 寄存器的高、低字节进行交换。即发送时首先添加低位字节,然后添加高位字节。

(8)最后得到的 CRC 寄存器内容即为 CRC 校验码。


第四章 功能码

简而言之,Modbus 功能码占用一个字节,取值范围是 1~127 。之所以 127以上不能使用,是因为 Modbus 规定当出现异常时,功能码士0x80(十进制 128)代表异常状态,因此 129(1+128)~255(127+128)的取值代表异常码。

Modbus 标准协议中规定了有 3 类 Modbus 功能码,分别是∶


1.公共功能码

(1)被明确定义的功能码;


(2)保证唯一性;

(3)由 Modbus 协会确认,并提供公开的文档;


(4)可进行一致性测试;

(5)包括协议定义的功能码和保留将来使用的功能码。


2.用户自定义功能码

(1)有两个用户自定义功能码区域,分别是65~72 和 100~110;

(2)用户自定义,不保证唯一性。


3.保留功能码

保留功能码是因为历史遗留原因,某些公司的传统产品上现行使用的功能码不作为公共使用。

a7a436fd5ef2d98a2b59da672bde35b9_20210406144244513.png

f850a53e9e051eb3cce082bb60f70d6a_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc2NDk3NA==,size_16,color_FFFFFF,t_70.png

功能码可分为位操作和字操作两类。位操作的最小单位为一位(bit),字操作的最小单位为两个字节。

● 位操作指令;读线圈状态功能码 01,读(离散)输入状态功能码 02,写单个线圈功能码 06 和写多个线圈功能码 15。

●字操作指令∶读保持寄存器功能码 03,读输入寄存器功能码 04,写单个保持寄存器功能码 06,写多个保持寄存器功能码 16。

4.1 01 (0x01)读线圈应用方法

读线圈01 (0x01)



请求



功能码

1字节 0x01
起始地址 2字节 0x0000至0xFFFF
线圈数量 2字节 1至2000(0x7D0)
响应



功能码 1字节 0x01
字节计数 1字节

N

线圈状态 n字节 n = N或N + 1
N = 寄存器数量/8,余数不等0,那么N = N + 1



错误



功能码 1字节 功能码 + 0x80
异常码 1字节 01或02或03或04

4.2 03 (0x03)读保持寄存器应用方法

请求



功能码

1个字节 0x03
起始地址 2个字节 0x0000 to 0xFFFF
寄存器数量 2个字节 1 to 125 (0x7D)




响应



功能码

1个字节 0x03
字节数 1个字节 2 x N*
寄存器值 N* x 2个字节





错误



差错码 1个字节 0x83
异常码 1个字节 01或02或03或04

4.3 06 (0x06)写单个寄存器应用方法

4.4 15 (0x0F) 写多个线圈应用方法

4.5 16 (0x10) 写多个寄存器应用方法

第五章 libmobus库

libmodbus 是一个免费的跨平台的支持 RTU和 TCP 的 Modbus 库,遵循LGPLv2.1+ 协议。libmodbus 支持 Linux、Mac OS X、FreeBSD、QNX 和

Windows 等操作系统。libmodbus 可以向符合 Modbus 协议的设备发送和接收数据,并支持通过串口或者 TCP 网络进行连接。

3e5896fadef985d6b80b47d628343dca_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc2NDk3NA==,size_16,color_FFFFFF,t_70.png

libmodbus库与应用程序的基本关系。

15499562ad75c635f0f920823590937e_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc2NDk3NA==,size_16,color_FFFFFF,t_70.png

第六章 libmodbus源码解析

第七章 RTU Slave开发

RTU-Slave的代码流程:

1.初始化并生成modbus_t 结构体;

2.设置从机端的ID;

3.起点调试模式;

4.建立modbus连接;

5.modbus_mapping_new()初始化寄存器,返回一个modbus_mapping_t 指针;

6.调用modbus_receive()函数判断串口的接收数据,负责接收和分析;

7.调用modbus_reply()函数,对接收到的请求指示发送响应(回复);

8.释放modbus_mapping_t 结构体;

9.关闭modbus连接;

10.释放modbus_t 结构体。

27eb1fe50ee56cb925221a92a77e9a26_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc2NDk3NA==,size_16,color_FFFFFF,t_70.png

(1) 初始化


ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1); //创建一个RTU类型的容器,即创建一个COM口为C0M4 波特率9600bit/s


MODBUS_API modbus_t* modbus_new_rtu(const char *device, int baud, char parity,  int data_bit, int stop_bit);


设置从机地址

/* Define the slave number */
int modbus_set_slave(modbus_t *ctx, int slave)
{
    if (ctx == NULL) {
        errno = EINVAL;
        return -1;
    }
    return ctx->backend->set_slave(ctx, slave);
}
int modbus_get_slave(modbus_t *ctx)
{
    if (ctx == NULL) {
        errno = EINVAL;
        return -1;
    }
    return ctx->slave;
}

(2) 建立连接

int modbus_connect(modbus_t *ctx)
{
    if (ctx == NULL) {
        errno = EINVAL;
        return -1;
    }
    return ctx->backend->connect(ctx);
}

(3)申请内存块用作4种寄存器数据存放

mb_mapping = modbus_mapping_new(500, 500, 500, 500);

(4)循环查询和响应

  for (;;)
  {
    //MODBUS_TCP_MAX_ADU_LENGTH,RTU帧格式最大数据字符数
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
    int rc;
    rc = modbus_receive(ctx, query);
    if (rc >= 0)
    {
      /*rc is the query size*/
      modbus_reply(ctx, query, rc, mb_mapping);
    }
    else
    {
      //connection closed by the client or error
      printf("Connection Closed\n");
    }
  }

(5)释放结构体,关闭连接

  modbus_mapping_free(mb_mapping);
  modbus_close(ctx);
  modbus_free(ctx);


/

相关文章
|
5月前
【MODBUS】libmodbus库从Modbus从站读取值
【MODBUS】libmodbus库从Modbus从站读取值
140 0
|
传感器 Linux
在Linux中使用libmodbus库进行Modbus RTU主从机通信
Modbus RTU是一种常见的工业通信协议,用于在自动化系统中传输数据。libmodbus是一个流行的C库,用于在Linux系统上实现Modbus通信。本文将介绍如何使用libmodbus库在Linux上创建Modbus RTU主从机通信的示例代码。
3244 0
|
传感器 数据采集 JSON
RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
682 0
RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
|
2月前
在Modbus RTU中同时进行读取和写入操作
在Modbus RTU中同时进行读取和写入操作
22 0
|
4月前
|
机器学习/深度学习 人工智能 分布式计算
主从模式(Master-Slave Architecture)
主从模式(Master-Slave Architecture)
107 0
|
5月前
|
传感器 监控
【MODBUS】Modbus 主从模式的部署方式
【MODBUS】Modbus 主从模式的部署方式
135 1
|
5月前
|
网络协议 C语言
【MODBUS】libmodbus库写一个Modbus TCP客户端
【MODBUS】libmodbus库写一个Modbus TCP客户端
199 1
|
5月前
|
存储 监控 网络协议
【MODBUS】Modbus协议入门简介
【MODBUS】Modbus协议入门简介
116 1
|
监控 网络协议 网络架构
Modbus Slave学习笔记(一)
Modbus Slave学习笔记