摘要:网上看到有好心的网友提示,freemodbus协议中的mbfuncholding.c 文件中eMBFuncReadHoldingRegister()函数,有一处错误,即:第185行的“usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”应为“usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”,我认为这不能算是一个错误,且听我的分析。

关键词:freemodbus Modbus 保持寄存器 eMBFuncReadHoldingRegister

1.关于freemodbus协议栈的一点粗浅体会

Modbus通信协议,搞过工业控制的人,多多少少应该了解一点。其结构简单,应用广泛。几乎是很多PLC的标配接口。但其通信规约也有几十页之多,要在单片机上实现,如果自己写源代码,估计还是需要一些时间的,因为不光要实现常用的功能,还要保持协议的完整性和错误处理机制。

freemodbus是一个比较完整的协议栈,有机构在维护,并且开源。有点单片机基础得朋友,1个小时应该可以移植好(前提能参考一个不错的教程)。比自己撸代码快N倍。个人感觉这个协议栈还是很好用的,但免费的只支持从站,需要做主站就要自己再想办法了。

2.为什么说这不算个错误

首先要看这句代码是干什么用的?上下文如下:

usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );

usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );

usRegAddress++;

usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );

usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );

pucFrame[MB_PDU_FUNC_READ_ADDR_OFF]存储的是Modbus数据帧中寄存器起始地址的高字节,pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] 存储的是Modbus数据帧中寄存器起始地址的低字节,pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 存储的是Modbus数据帧中寄存器个数的高字节,pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] 存储的是Modbus数据帧中寄存器个数的低字节。

下面给一个实例,能更好理解,如图1。此帧数据是读取地址为1的从站的保持寄存器,寄存器起始地址为:18430(0x47FE),读取寄存器的个数为:101(0x0065),在这里:

pucFrame[MB_PDU_FUNC_READ_ADDR_OFF]的值为:0x47;

pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] 的值为:0xFE;

pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 的值为:0x00;

pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] 的值为:0x65。

从这里也可以看出,Modbus在发送一个word(16bit)数据的时候,是高字节在前,低字节在后。

图1

既然pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 表示的是寄存器个数的高字节,那么我们来查看一下Modbus协议,看一下这个参数的范围,如图2、图3所示。此两图是从Modbus协议文本中截出来的,0x03功能码是读保持寄存器,0x10功能码是写多个保持寄存器,这两个功能码会涉及到保持寄存器数量的问题,寄存器数量的范围一个是0x7D,一个是0x78,都在一个字节的范围内,因此,寄存器数量这个参数的高字节始终为0,也就是说pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF]是等于0的,可以不处理。

图2

图3

3.总结及讨论

综上,我认为这个不能算是个错误,不影响程序的正常结果,只是写法不够严谨。但有一个极端情况,是有影响的,Modbus主站读写寄存器的数量超过协议规定的数量的时候,本应该返回错误码,但这种写法由于只处理了低字节,就有可能认为没有错误,而对数据进行处理。为了安全起见,大家还是把这句代码改掉吧,改为“usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”,以防止极端情况的发生。

还有一个问题,Modbus协议规定的读写保持寄存器的数量都在一个字节的范围内,发送数据的时候为什么要用2个字节来表示寄存器数量,这个还没有做深入研究,可能是考虑协议的整体兼容性吧,有兴趣的朋友可以一起讨论。

关于freemodbus协议中eMBFuncReadHoldingRegister()函数的所谓错误的更多相关文章

  1. 《APUE》中的函数整理

    第1章 unix基础知识 1. char *strerror(int errnum) 该函数将errnum(就是errno值)映射为一个出错信息字符串,返回该字符串指针.声明在string.h文件中. ...

  2. [VBA]用一个简单例子说明如何在Excel中自定义函数

    Excel中的函数无疑是强大的,但是再强大的战士也有他脆弱的脚后跟[1].这两天在使用Excel的时候遇到了一个需求,要在某一个单元格里面自动计算今天是星期几(如显示 Today is Tuesday ...

  3. Socks5协议中文文档

    译者:Radeon(Radeon bise@cmmail.com) 译文公布时间:2001-6-18 文件夹 1.介绍 2.现有的协议 3.基于TCP协议的客户 4.请求 5.地址 6.应答 7.基于 ...

  4. TCP/IP协议中backlog参数

    TCP建立连接是要进行三次握手,但是否完成三次握手后,服务器就处理(accept)呢? backlog其实是一个连接队列,在Linux内核2.2之前,backlog大小包括半连接状态和全连接状态两种队 ...

  5. JS中的函数、Bom、DOM及JS事件

    本期博主给大家带来JS的函数.Bom.DOM操作,以及JS各种常用的数据类型的相关知识,同时,这也是JavaScript极其重要的部分,博主将详细介绍各种属性的用法和方法. 一.JS中的函数 [函数的 ...

  6. JS中的函数、BOM和DOM操作

     一.JS中的函数 [关于注释] /** [文档注释]:开头两个*.写在函数上方,在调用函数时可以看到文档上方的描述信息. */   // 单行注释 /* 多行注释 */ 1.函数的声明及调用 (1) ...

  7. DTLS协议中client/server的认证过程和密钥协商过程

    我的总结:DTLS的握手就是协商出一个对称加密的秘钥(每个客户端的秘钥都会不一样),之后的通信就要这个秘钥进行加密通信.协商的过程要么使用非对称加密算法进行签名校验身份,要么通过客户端和服务器各自存对 ...

  8. Http协议中Get和Post的浅谈

    起名困难户,每次写文章最愁的就是不知道该如何起个稍具内涵的名字,如果这篇文章我只是写写Get和Post的区别,我可以起个名字“Get和Post的那点事”,如果打算阐述一下Http协议原理性内容,那该叫 ...

  9. 从TCP三次握手说起–浅析TCP协议中的疑难杂症(2)

    版权声明:本文由黄日成原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/108 来源:腾云阁 https://www.qclo ...

随机推荐

  1. Cubmap

    视差 Cubmap https://chengkehan.github.io/LocalCubmap.html http://www.manew.com/thread-93923-1-1.html h ...

  2. 分布式ID生成方案汇总

    1.目标 1.1.全局唯一 不能出现重复的ID,全局唯一是最基本的要求. 1.2.趋势有序 业务上分页查询需求,排序需求,如果ID直接有序,则不必建立更多的索引,增加查询条件. 而且Mysql Inn ...

  3. Jwt快速入门(copy即可)

    Jwt 什么是jwt JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法. 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和 ...

  4. Oracle适配问题解决

    问题一:SQL 命令未正确结束 问题二:ORA-00907: 缺失右括号 问题三:mysql函数在Oracle中不适用 问题四:ORA-00936: 缺失表达式 问题五:No serializer f ...

  5. 如何入门Pytorch之四:搭建神经网络训练MNIST

    上一节我们学习了Pytorch优化网络的基本方法,本节我们将以MNIST数据集为例,通过搭建一个完整的神经网络,来加深对Pytorch的理解. 一.数据集 MNIST是一个非常经典的数据集,下载链接: ...

  6. python之读取yaml数据

    一.yaml简介 yaml:一种标记语言,专门用来写配置文件. 二.yaml基础语法 区分大小写: 使用缩进表示层级关系: 使用空格键缩进,而非Tab键缩进 缩进的空格数目不固定,只需要相同层级的元素 ...

  7. Git使用教程与基本原理和Sourcetree基本使用探微

    什么是GIT Git是一个强调速度的分布式版本控制软件和源代码管理系统(SCM,source code management).Git最初是由Linus Torvalds为内核开发而设计的管理软件.自 ...

  8. 学习 | less入门

    最近在写css的时候,发现自己写的css特别长,觉得自己写的特别low,所以为了加快自己的开发效率,又重新温习了less,下面就是我学习less的过程. less是不能被浏览器识别的,要转换成css, ...

  9. IntelliJ IDEA编辑器激活码

    2020-3-31 日 亲自测试有效,什么时候失效就母鸡了 激活码一: T3ACKYHDVF-eyJsaWNlbnNlSWQiOiJUM0FDS1lIRFZGIiwibGljZW5zZWVOYW1lI ...

  10. 2020华为杯数学建模B题-RON建模 赛后总结与分析

    好久好久没有写博客了...挺累的,从二月份开始找暑期实习,接着在进行暑期实习,然后马不停蹄地进行秋招,现在总算结束实习,前两天又参加了华为杯数学建模竞赛,感觉接下来就会很轻松了,希望能好好休息休息.这 ...