ModbusRTU协议帧详解

  • 一.协议帧表格
  • 二.读取发送帧和返回帧格式
  • 三.写数据发送帧和返回帧格式
  • 0x10(16功能码,写多个寄存器)写数据格式
  • 0x06(06功能码,写单个寄存器)写数据格式
  • 0x05(05功能码,写开关位)写数据格式
  • 四.功能码定义
  • 五.注意事项,必看
  • 六.CRC校验计算C/C++
  • 七.字节和浮点型相互转换C/C++
  • 八.Qt实现modbusRTU/TCP主站demo


一.协议帧表格

modbus java 组帧 解析 modbus数据帧的结构_串口通信

二.读取发送帧和返回帧格式

读取帧格式:

地址

功能码

起始地址高字节

起始地址低字节

读取寄存个数高字节

读取寄存个数低字节

CRC低字节

CRC高字节

读取帧格式:

0X01

0x03

0x00

0x00

0x00

0x02

xx

xx

返回帧格式:

地址

功能码

数据长度(读取寄存器个数乘以2)

数据部分

CRC低字节

CRC高字节

返回帧格式:

0X01

0x03

0x04

xxxxx

xx

xx

三.写数据发送帧和返回帧格式

0x10(16功能码,写多个寄存器)写数据格式

写入帧格式:

地址

功能码

起始地址高字节

起始地址低字节

写入寄存个数高字节

写入寄存个数低字节

写入数据长度

写入数据

CRC低字节

CRC高字节

写入帧格式:

0X01

0x10

0x00

0x00

0x00

0x02

0x04

xxxx

xx

xx

返回帧格式:

地址

功能码

起始地址高字节

起始地址低字节

写入寄存个数高字节

写入寄存个数低字节

CRC低字节

CRC高字节

返回帧格式:

0X01

0x10

0x00

0x00

0x00

0x02

xx

xx

0x06(06功能码,写单个寄存器)写数据格式

写入帧格式:

地址

功能码

起始地址高字节

起始地址低字节

写入数据高字节

写入数据低字节

CRC低字节

CRC高字节

写入帧格式:

0X01

0x06

0x00

0x00

xx

xx

xx

xx

返回格式个写入格式一致

返回帧格式:

地址

功能码

起始地址高字节

起始地址低字节

写入数据高字节

写入数据低字节

CRC低字节

CRC高字节

返回帧格式:

0X01

0x06

0x00

0x00

xx

xx

xx

xx

0x05(05功能码,写开关位)写数据格式

写入帧格式:

地址

功能码

起始地址高字节

起始地址低字节

写入数据高字节

写入数据低字节

CRC低字节

CRC高字节

写入帧格式(置1):

0X01

0x05

0x00

0x00

0xFF

0x00

xx

xx

写入帧格式(置0):

0X01

0x05

0x00

0x00

0x00

0x00

xx

xx

返回格式个写入格式一致

写入帧格式:

地址

功能码

起始地址高字节

起始地址低字节

写入数据高字节

写入数据低字节

CRC低字节

CRC高字节

返回帧格式(置1):

0X01

0x05

0x00

0x00

0xFF

0x00

xx

xx

返回帧格式(置0):

0X01

0x05

0x00

0x00

0x00

0x00

xx

xx

四.功能码定义

功能码

描述

0x01

读取开关量输出,可读写(开关量读取是按位读取的(不是按寄存数目读取的),所以返回的字节数目并不是读取的寄存器个数乘以2,是读取的开关量个数除以8的商值加1(加不加1看余数是不是0,余数非零就加1)),可以被05和0F(15)功能码写

0x02

读取开关量输入,只读(开关量读取是按位读取的(不是按寄存数目读取的),所以返回的字节数目并不是读取的寄存器个数乘以2,是读取的开关量个数除以8的商值加1(加不加1看余数是不是0,余数非零就加1))

0x03

读取数值量,定义上能被03的读取的可以被06和10写

0x04

读取数值量,定义只能读不能写,实际需要根据实际情况来(如果开放可以被06和10写)

0x05

写开关量,只对01可以读取的数据写

0x06

写单个寄存,对能被03功能码读取的寄存器进行写数据操作

0x10

写多个寄存器,对能被03功能码读取的寄存器进行写数据操作

五.注意事项,必看

1.一个寄存器等于两个字节
2.(01和02功能码)开关量读取是按位读取的(不是按寄存数目读取的),所以返回的字节数目并不是读取的寄存器个数乘以2,是读取的开关量个数除以8的商值加1(加不加1看余数是不是0,余数非零就加1),比如读取7个开关量,返回数据长度就是(7/8),商是0余数是1,所以数据部分返回1个字节的长度,比如读取10个开关量,返回数据长度就是(10/8),商是1余数是2,所以数据部分返回2个字节的长度

六.CRC校验计算C/C++

xxx.h

unsigned short int CheckCRC_16(const  unsigned char* data,const unsigned int sIndex=0,const unsigned int length=0);

xxx.c

unsigned short int CheckCRC_16(const unsigned char *data, const unsigned int sIndex, const unsigned int length)
{
    unsigned int CRCreg=0xFFFF;
    int len=length+sIndex;
    for(int i=sIndex;i<len;i++)
    {
        CRCreg=CRCreg^data[i];
        for(int j=0;j<=7;j++)
        {
            if(CRCreg&0x01)
            {
                CRCreg=(CRCreg>>1)^0xa001;
            }
            else
            {
                CRCreg=CRCreg>>1;
            }
        }
    }
    return CRCreg;
}

七.字节和浮点型相互转换C/C++

//以C语言转换为例:转换30.96(16进制41 F7 AE 14)

#include<stdio.h>
//使用联合体来实现
typedef union _HexFloat
{

char hex[4];
float fval;
}_HexFloat;

int main()
{
    _HexFloat HexFloat;
    //将16进制值分别放进去 ,如果得出的值不对就交换位置
    HexFloat.hex[3]=0x41;
    HexFloat.hex[2]=0xf7;
    HexFloat.hex[1]=0xae;
    HexFloat.hex[0]=0x14;
    printf("fval十进制的值为=%f\n",HexFloat.fval);
	return 0;
}

八.Qt实现modbusRTU/TCP主站demo

程序只做了modbusRTU的串口demo,但是封装的类可以选择摩登busTCP协议