IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> FreeModbus从站源码解析(mbfuncholding.c、mbfunccoils.c、mbfuncdisc.c、mbfuncinput.c) -> 正文阅读

[C++知识库]FreeModbus从站源码解析(mbfuncholding.c、mbfunccoils.c、mbfuncdisc.c、mbfuncinput.c)

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+1

eMBException    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的值为1
    if( *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的值为1
    if( *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.zipFreeModbusV1.6源码
FreeModbusMasterSlave(Rev1.0.0).zip笔者移植好测试通过STM32+FreeRTOS+FreeModbus Master Slave代码
ModbusSlave 7.0和ModbusPoll_7.0软件注册码.zipFreeModbus Master Slave调试工具
FreeModbus V1.6 主机使用说明.mdFreeModbus 主机使用说明文档
FreeModbus 从机流程图.vsdFreeModbus 从机流程图
FreeModbus 主机流程图.vsdFreeModbus 主机流程图
Modbus应用协议.doc笔者整理的 FreeModbus 协议文档
FreeModbus Datasheet笔者搜集 FreeModbus 官方协议文档

资料链接:👉FreeModbus资源传送门👈
资料介绍:👉FreeModbus资源介绍传送门👈

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 15:50:34  更:2022-03-03 15:55:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:37:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码