modbus和字节序

numconvert软件上显示的十六进制是大端顺序,即数值顺序。

modbus协议规定是按大端传输(见英文版说明),但是确切的说,它只是借用“大端”这个术语以表示它是由左往右依次字节传输的,因为毕竟大小端只有到了数值层面才有意义。

针对16位传输,只存在正序(AB)或反序(BA)两种方式。

针对双字32位数据传输,存在四种顺序方式:

Big-endian :ABCD
Little-endian :DCBA
Big-endian byte swap :BADC
Little-endian byte swap :CDAB
ModbusSlave软件,它传输的顺序就是它显示的十六进制字节顺序,也即,对于一个寄存器中的数值来说,无论显示还是传输,都是它的大端序。

ModbusSlave软件,可以设置浮点数格式,如果设置为Little-endian byte swap,也就是先把四个字节调换为小端DCBA,再把字内部字节调换回大端,例如浮点数65.253,其数值即大端序为0x42828189,当在ModbusSlave上设置值为65.253后,切换为十六进制会看到,其两个寄存器先后是0x8189 0x4282。

ModbusSlave软件,要把一个浮点数切换为十六进制显示,需要按住ctrl键,选中它所占用的两个寄存器。

使用libmodbus库时,调用它的uint16_t相关接收函数时,它自动对每个字(注意,仅仅是字,即两字节,而不是四字节)在内存层面进行了高低字节转换,此时数据在内存中每个字的两个字节跟发送端顺序是对调了的,那么因此,字的数值顺序看上去反而是跟发送端顺序一致的,这个过程可以表示为[以数值4为例,程序以小端序0x0400赋值-->程序会按大端序0x0004发送-->libmodbus自动又转回小端序0x0400],在ModbusSlave软件上把一个寄存器赋值为4,看到十六进制显示的是0x0004,是因为它是直接按大端显示的,实际上相当于“程序以小端序0x0400赋值”,总之一句话,用了libmodbus后,无需再执行ntohs啥的进行转换,拿到的就是发送程序的;由于位运算用的是数值顺序而不是内存顺序,因此在做位运算时直接以发送端顺序为参照做即可,这一点尤其注意。

在使用printf(%04x)打印字时,它是把整个字看作一个整体,按大端输出的,即你看到的顺序跟内存中的顺序是反着的,这一点尤其在做位运算的时候注意迷惑性:
uint16_t d;
printf("[%04x]\n", d); // 输出的是大端,即跟内存中顺序相反

如果要按内存中的顺序打印,则应当使用printf(%02x)逐个字节打印:
printf("[%02x][%02x]\n", *((unsigned char *)(&d)), *((unsigned char *)(&d) + 1));

大小端转换可以使用htons和ntohs,并且对于大小端转换来说,它俩效果是一样的,用哪个都行。

位运算用的是数值顺序而不是内存顺序,这一点尤其在做位运算的时候需要注意。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/dyzhen/article/details/135980360

posted @ 2024-04-25 10:02  三驾马车  阅读(52)  评论(0编辑  收藏  举报