山高疑日近,海阔觉天低

ModBus

Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。当在一 Modbus 网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用 Modbus 协议发出。在其它网络上,包含了Modbus 协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
一,Function
1.0×03 读取多个寄存器
如下图所示,地址是大段数据,C/C++是小段,故需要转换一下,另外接受的数据理论上也是大段的Word,但实际使用的时候返回来的数据格式有些厂家并不完全按照modbus协议来,但是其它部分是完整按照modbus
实际接收数据长度Byte Count应该等于寄存器数量*2,下面的例子是查询0x0002 开始的三个寄存器数据,

Field Name 发送 Field Name 返回
Slave Address 0x80 Slave Address 0x80
Function 0x03 Function 0x03
Starting Address Hi 0x00 Byte Count 0x06
Starting Address Lo 0x02 Data 1 Hi
No. of Registers Hi 0x00 Data 1 Lo
No. of Registers Lo 0x03 Data 2 Hi
CRC Data 2 Lo
Data 3 Hi
Data 3 Lo
CRC

2.0×06 设置单个寄存器值
如下图所示,地址以及值都是是大段数据,C/C++是小段,故需要转换一下,接收和发送内容一摸一样,下面的例子是设置0x0002 寄存器的值为0x1234

Field Name 发送 Field Name 返回
Slave Address 0x80 Slave Address 0x80
Function 0x06 Function 0x03
Starting Address Hi 0x00 Starting Address Hi 0x00
Starting Address Lo 0x02 Starting Address Lo 0x02
Value of Registers Hi 0x12 Value of Registers Hi 0x12
Value of Registers Lo 0x34 Value of Registers Lo 0x34
CRC CRC

3.0×10 设置多个寄存器
如下图所示,地址是大段数据,C/C++是小段,故需要转换一下,另外接受的数据理论上也是大段的Word,但实际使用的时候返回来的数据格式有些厂家并不完全按照modbus协议来,但是其它部分是完整按照modbus
实际接收数据长度Byte Count应该等于寄存器数量*2,下面的例子是设置0x0013开始的2个寄存器值为0x1234,0x0102

Field Name 发送 Field Name 返回
Slave Address 0x80 Slave Address 0x80
Function 0x10 Function 0x10
Starting Address Hi 0x00 Starting Address Hi 0x00
Starting Address Lo 0x13 Starting Address Lo 0x13
No. of Registers Hi 0x00 No. of Registers Hi 0x00
No. of Registers Lo 0x02 No. of Registers Lo 0x02
Byte Count 0x04 CRC
Data 1 Hi 0x12
Data 1 Lo 0x34
Data 2 Hi 0x01
Data 2 Lo 0x02
CRC

二,数据类型大小端
modebus是基于word(16bit)数据的,可以说他是一个16位系统,寄存器地址是16bit,每个地址可以存放16bit数据,按照官方协议它是大端数据,与C/C++不同.有些厂商为了方便将数据部分改为小端,这样直接通过指针就可以读取到这就牵扯到数据大小端转化,这样的话u16,u32,float,都可能牵扯到大小端转化,u8有2中方式存储:2个u8构成一个word;u8直接存储,第二种方式不牵扯大小端转化,注意CRC他是小端数据,也就是说热河modbusCRC都是高位在后
三,校验CRC
第一种方式运算速度块,但需要占用512bytes大小Flash,第二种方式运算量大

#if 1
u16 modbus_CRC(char *nData, u16 wLength, u8 bCheck)
{
    static const u16 wCRCTable[] = {
        0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
        0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
        0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
        0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
        0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
        0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
        0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
        0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
        0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
        0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
        0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
        0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
        0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
        0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
        0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
        0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
        0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
        0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
        0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
        0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
        0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
        0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
        0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
        0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
        0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
        0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
        0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
        0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
        0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
        0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
        0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
        0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040};

    char nTemp;
    u16 wCRCWord = 0xFFFF;
    u16 nlen = wLength;
    while (wLength--)
    {
        nTemp = *nData++ ^ wCRCWord;
        wCRCWord >>= 8;
        wCRCWord ^= wCRCTable[nTemp];
    }
    if (bCheck)
        return wCRCWord == 0 ? 1u : 0;
    *(u16 *)nData = wCRCWord;
    return nlen + 2;
}
#else
    u16 crc = 0xFFFF;
    for (int pos = 0; pos < len; pos++)
    {
        crc ^= (u16)buf[pos]; // XOR byte into least sig. byte of crc
        for (int i = 8; i != 0; i--)
        { // Loop over each bit
            if ((crc & 0x0001) != 0)
            {              // If the LSB is set
                crc >>= 1; // Shift right and XOR 0xA001
                crc ^= 0xA001;
            }
            else           // Else LSB is not set
                crc >>= 1; // Just shift right
        }
    }
    if (bCheck)
        return crc == 0 ? 1 : 0;
    *(u16 *)(buf + len) = crc;
    return len + 2;
#endif

四,工具
modbus poll

赞(0) 打赏
未经允许不得转载:Mr.Zhang » ModBus

你的打赏是我的动力

登录

找回密码

注册