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,并且对于大小端转换来说,它俩效果是一样的,用哪个都行。

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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值