mbfuncholding.c

#include "stdlib.h"
#include "string.h"#include "port.h"#include "mb.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbconfig.h"// ADU:应用数据单元,从机地址+功能码+数据域+CRC校验
// PDU:协议数据单元,功能码+数据#define MB_PDU_FUNC_READ_ADDR_OFF               ( MB_PDU_DATA_OFF + 0)  //待读寄存器地址偏移,2Bytes
#define MB_PDU_FUNC_READ_REGCNT_OFF             ( MB_PDU_DATA_OFF + 2 ) //待读寄存器数量偏移,2Bytes
#define MB_PDU_FUNC_READ_SIZE                   ( 4 )                   //2+2
#define MB_PDU_FUNC_READ_REGCNT_MAX             ( 0x007D )              //读寄存器最大数量#define MB_PDU_FUNC_WRITE_ADDR_OFF              ( MB_PDU_DATA_OFF + 0)  //待写寄存器地址偏移,2Bytes
#define MB_PDU_FUNC_WRITE_VALUE_OFF             ( MB_PDU_DATA_OFF + 2 ) //待写的数据的偏移,2Bytes
#define MB_PDU_FUNC_WRITE_SIZE                  ( 4 )                   //2+2#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF          ( MB_PDU_DATA_OFF + 0 ) //待写寄存器地址偏移,2Bytes
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF        ( MB_PDU_DATA_OFF + 2 ) //待写寄存器数量偏移,2Bytes
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 4 ) //待写的字节数的偏移,1bytes
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF        ( MB_PDU_DATA_OFF + 5 ) //待写的数据偏移
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN          ( 5 )                   //2+2+1
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX        ( 0x0078 )              //写寄存器最大数量#define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF     ( MB_PDU_DATA_OFF + 0 ) //读寄存器地址偏移,2Bytes
#define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF   ( MB_PDU_DATA_OFF + 2 ) //读及黁其数量偏移,2Bytes
#define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF    ( MB_PDU_DATA_OFF + 4 ) //写寄存器地址偏移,2Bytes
#define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF  ( MB_PDU_DATA_OFF + 6 ) //写寄存器数量偏移,2Bytes
#define MB_PDU_FUNC_READWRITE_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 8 ) //待写入的字节数偏移,1Bytes
#define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF  ( MB_PDU_DATA_OFF + 9 ) //带写入的数据偏移,允许为0,即不写
#define MB_PDU_FUNC_READWRITE_SIZE_MIN          ( 9 )                   //2+2+2+2+1eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
/************************************************************** @Func : 写单个保持寄存器* @pucFrame : 主机发送的数据(功能码+数据),实际指向ucRTUBuf* @usLen : 数据长度字节数(功能码+数据)*************************************************************/
eMBException
eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{USHORT          usRegAddress;           //带写入的寄存器地址eMBException    eStatus = MB_EX_NONE;eMBErrorCode    eRegStatus;// 判断数据长度是否正确5=1功能码+2地址+2数据,MB_PDU_SIZE_MINd的值为1if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) ){//寄存器地址usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );//注意寄存器地址自加,处理时自减usRegAddress++;/* 调用函数,更新保持寄存器的值 */eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],usRegAddress, 1, MB_REG_WRITE );/* 发生错误,抛出异常 */if( eRegStatus != MB_ENOERR ){eStatus = prveMBError2Exception( eRegStatus );}}else{/* 长度非法*/eStatus = MB_EX_ILLEGAL_DATA_VALUE;}return eStatus;
}
#endif#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
/************************************************************** @Func : 写多个保持寄存器* @pucFrame : 主机发送的数据(功能码+数据),实际指向ucRTUBuf* @usLen : 数据长度字节数(功能码+数据)*************************************************************/
eMBException
eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{USHORT          usRegAddress;     //待写入的寄存器地址USHORT          usRegCount;       //待写入的寄存器数量UCHAR           ucRegByteCount;   //待写入的字节数eMBException    eStatus = MB_EX_NONE;eMBErrorCode    eRegStatus;//验证数据长度是否正确,最小为6=1功能码+2地址+2数量+1字节数if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) ){//寄存器地址usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );//注意寄存器地址自加,处理时自减usRegAddress++;//待写的寄存器的数量usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );//待写入的字节数ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];//条件判断数量及字节数是否正确if( ( usRegCount >= 1 ) &&( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&( ucRegByteCount == ( UCHAR ) ( 2 * usRegCount ) ) ){/* 调用函数更新保持寄存器的值 */eRegStatus =eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],usRegAddress, usRegCount, MB_REG_WRITE );/* 发生错误,抛出异常 */if( eRegStatus != MB_ENOERR ){eStatus = prveMBError2Exception( eRegStatus );}else{/* 返回写入的字节数 */*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;}}else{//数据非法eStatus = MB_EX_ILLEGAL_DATA_VALUE;}}else{/* 非法数据 */eStatus = MB_EX_ILLEGAL_DATA_VALUE;}return eStatus;
}
#endif#if MB_FUNC_READ_HOLDING_ENABLED > 0
/************************************************************** @Func : 读保持寄存器* @pucFrame : 主机发送的数据(功能码+数据),实际指向ucRTUBuf* @usLen : 数据长度字节数(功能码+数据)*************************************************************/
eMBException
eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{USHORT          usRegAddress;     //寄存器地址USHORT          usRegCount;       //寄存器数量UCHAR          *pucFrameCur;      //返回给主机的PDU指针eMBException    eStatus = MB_EX_NONE;eMBErrorCode    eRegStatus;//验证数据长度是否正确,5=2地址+2数量+1功能码if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) ){//寄存器地址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] );/* 验证数量是否正确 */if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) ){/* pucFrameCur指向PDU的开始,MB_PDU_FUNC_OFF的值为0 */pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];*usLen = MB_PDU_FUNC_OFF;/* 第一个字节为功能码 */*pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;*usLen += 1;/* 响应中第二个字节为字节数 */*pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );*usLen += 1;/* 调用函数将保持寄存器的值填充Buffer */eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );/* 发生错误,抛出异常 */if( eRegStatus != MB_ENOERR ){eStatus = prveMBError2Exception( eRegStatus );}else{//数据的字节数等于寄存器数量的2倍,一个寄存器为2字节*usLen += usRegCount * 2;}}else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}}else{/* 非法数据 */eStatus = MB_EX_ILLEGAL_DATA_VALUE;}return eStatus;
}#endif#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
/******************************************************************* @Func : 读写多个保持寄存器* @pucFrame : *          调用:主机发送过来的数据(功能码+数据),实际指向ucRTUBuf*          返回:从机将要返回给主机的数据(功能码+数据)* @usLen : 数据长度字节数(功能码+数据)******************************************************************/
eMBException
eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{USHORT          usRegReadAddress;      //待读取的寄存器地址USHORT          usRegReadCount;        //待读取的寄存器数量USHORT          usRegWriteAddress;     //待写的寄存器地址USHORT          usRegWriteCount;       //待写的寄存器数量UCHAR           ucRegWriteByteCount;   //待写入寄存器的字节数UCHAR          *pucFrameCur;           //读取寄存器返回的数据(功能码+数据域)eMBException    eStatus = MB_EX_NONE;eMBErrorCode    eRegStatus;//验证长度是否正确,最小字节数10=9+1功能码,MB_PDU_SIZE_MIN的值为1if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) ){//待读取的寄存器地址usRegReadAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );usRegReadAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );//注意自加,处理时自减usRegReadAddress++;//待读取的寄存器的数量usRegReadCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );usRegReadCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );//待写入的寄存器的地址usRegWriteAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );usRegWriteAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );//注意自加,处理时自减usRegWriteAddress++;//待写入的寄存器的数量usRegWriteCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );usRegWriteCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );//待写入的字节数ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];//验证数据的正确性if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) ){/* 调用eMBRegHoldingCB更新待写入的寄存器 */eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );if( eRegStatus == MB_ENOERR ){/* pucFrameCur指向PDU的开始,MB_PDU_FUNC_OFF的值为0 */pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];*usLen = MB_PDU_FUNC_OFF;/* 第一个字是功能码 */*pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;*usLen += 1;/* 第二个字节是字节数 */*pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );*usLen += 1;/* 调用函数eMBRegHoldingCB将待读取的寄存器值填充Buffer */eRegStatus =eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );if( eRegStatus == MB_ENOERR ){*usLen += 2 * usRegReadCount;}}if( eRegStatus != MB_ENOERR ){eStatus = prveMBError2Exception( eRegStatus );}}else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}}return eStatus;
}#endif

mbfunccoils.c、mbfuncdisc.c、mbfuncinput.c与mbfuncholding.c文件大同小异,分别是对线圈、分离量、输入寄存器的读写操作,参照即可

Modbus资料整理

笔者将Modbus 主机、从机协议完整资料整理如下:

文件 说明
freemodbus-v1.6.zip FreeModbusV1.6源码
FreeModbusMasterSlave(Rev1.0.0).zip 笔者移植好测试通过STM32+FreeRTOS+FreeModbus Master Slave代码
ModbusSlave 7.0和ModbusPoll_7.0软件注册码.zip FreeModbus Master Slave调试工具
FreeModbus V1.6 主机使用说明.md FreeModbus 主机使用说明文档
FreeModbus 从机流程图.vsd FreeModbus 从机流程图
FreeModbus 主机流程图.vsd FreeModbus 主机流程图
Modbus应用协议.doc 笔者整理的 FreeModbus 协议文档
FreeModbus Datasheet 笔者搜集 FreeModbus 官方协议文档

资料链接:

FreeModbus从站源码解析(mbfuncholding.c、mbfunccoils.c、mbfuncdisc.c、mbfuncinput.c)相关推荐

  1. FreeModbus从站源码解析(portserial.c)

    portserial.c #include "port.h" #include "mb.h" #include "mbport.h"#def ...

  2. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  3. 谷歌BERT预训练源码解析(三):训练过程

    目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...

  4. 谷歌BERT预训练源码解析(一):训练数据生成

    目录 预训练源码结构简介 输入输出 源码解析 参数 主函数 创建训练实例 下一句预测&实例生成 随机遮蔽 输出 结果一览 预训练源码结构简介 关于BERT,简单来说,它是一个基于Transfo ...

  5. Gin源码解析和例子——中间件(middleware)

    在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...

  6. Colly源码解析——结合例子分析底层实现

    通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...

  7. libev源码解析——定时器监视器和组织形式

    我们先看下定时器监视器的数据结构.(转载请指明出于breaksoftware的csdn博客) /* invoked after a specific time, repeatable (based o ...

  8. libev源码解析——定时器原理

    本文将回答<libev源码解析--I/O模型>中抛出的两个问题.(转载请指明出于breaksoftware的csdn博客) 对于问题1:为什么backend_poll函数需要指定超时?我们 ...

  9. libev源码解析——I/O模型

    在<libev源码解析--总览>一文中,我们介绍过,libev是一个基于事件的循环库.本文将介绍其和事件及循环之间的关系.(转载请指明出于breaksoftware的csdn博客) 目前i ...

最新文章

  1. J2EE 中的服务器 tomcat6.0 配置
  2. 只需2040张图片,训练视觉Transformer:南大吴建鑫团队提出IDMM
  3. Js获取宽高度的归纳总结
  4. 面试官问我:spring、springboot、springcloud的区别,我笑了
  5. Windows 8 Release Preview 安装秘技两则
  6. .NET 时间轴:从出生到巨人
  7. python中定义结构体
  8. eclipse创建spring boot项目,tomcat启动成功,但http://localhost:8080无法访问报错404解决方案...
  9. Html5+Css3小试牛刀
  10. 不同CPU指令的指令集密度
  11. html audio解决浏览器无法播放问题
  12. STM32入门教程第一讲
  13. Byond公司发布BIS平台,未来开发VR、AR不再繁杂
  14. LA 4670 Dominating Patterns
  15. 从吃凉的就会肚子疼,不敢吃可爱多以下的雪糕,吃饱后去逛街肚子就会胀,到后来吃饭的时候就胃疼解决办法
  16. Prim 算法的实现
  17. 快手扫码登录【2021-12-03】
  18. Web前端开发工程师与UI设计师的区别是什么?
  19. 模块化UPS与数据中心供配电架构的发展方向
  20. 代码执行与命令执行的区别

热门文章

  1. 一起学 WebGL:感受三维世界之视图矩阵
  2. 国土“双评价”建模探索
  3. 最新shsh备份详细教程(现在只能备份最新的固件)
  4. 干净删除3721等流氓插件
  5. 网络信息安全亮红灯,确保数据安全是大势所趋
  6. SEO建设者,有哪些说不出的苦?
  7. sweet home3d_Sweet Home 3D:一个开源工具,可帮助您决定梦想中的家
  8. 2021 技术展望 | 走向未来的实时生成技术
  9. vivo自带便签新版_vivo手机便签怎么导出到新手机?
  10. Sublime Text 4 下 LaTeXtool 和 Latex-cwl 插件自动补全问题(补充)