FreeMODBUS库的扩展与增强(2)- 四种寄存器的数据读写操作

日期作者版本说明
2020.11.03TaoV0.0完成主体内容的撰写

介绍

modbus通讯的核心功能就是四种寄存器的数据读写操作。FreeModbus库提供了四种modbus寄存器的读写接口,但是具体的功能需要根据项目的不同自己实现。本文介绍了一套实现四种modbus寄存器读写操作的函数与方法,在笔者的项目中有着大量的应用和验证。

需要说明的是,本套库函数是需要配合移植的FreeModbus库一起使用的。对于保持寄存器,由于需要实现掉电保存数据与上电加载数据,需要与其他的库函数配合使用(例如EEPROM数据读写函数等),在移植到其他平台时应该特别加以注意。

类型简称起始地址结束地址功能码
线圈寄存器0x00000099990x01 读一组逻辑线圈;
0x05 写单个线圈;
0x0f 写多个线圈
离散寄存器1x10000199990x02 读一组开关输入
输入寄存器3x30000399990x04 读一个或多个输入寄存器
保持寄存器4x40000499990x03 读一个或多个保持寄存器的值;
0x06 写单个保持寄存器;
0x10 写多个保持寄存器

输入寄存器

头文件

/*
 * mb_inputreg.h
 *
 *  Created on: Oct 22, 2019
 *      Author: tao
 */

#ifndef REGISTERS_MB_INPUTREG_H_
#define REGISTERS_MB_INPUTREG_H_

#include "mb.h"

//设置起始地址(PLC地址,base 1)
#define REG_INPUT_START 1000
//设置寄存器数量
#define REG_INPUT_NREGS 50

typedef union
{
	float toFloat;
	uint16_t toUint16Array[2];
}MB_InputRegUnion;

extern USHORT usRegInputBuf[REG_INPUT_NREGS];

void RegInputBuf_Init();
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );
float InputReg_GetData(uint16_t index);
void InputRegReg_SetData(uint16_t index, float value);

#endif /* REGISTERS_MB_INPUTREG_H_ */

源文件

/*
 * mb_inputreg.c
 *
 *  Created on: Oct 22, 2019
 *      Author: tao
 */

#include "mb_inputreg.h"

//static USHORT usRegInputStart = REG_INPUT_START;
USHORT usRegInputBuf[REG_INPUT_NREGS];
MB_InputRegUnion *mb_InputRegUnion = (MB_InputRegUnion *) usRegInputBuf;


/**
 * @brief 完成输入寄存器的初始化
 */
void RegInputBuf_Init()
{
	
}


/**
 * @brief 读输入寄存器的服务函数
 * 		在mbfuncinput.c的eMBFuncReadInputRegister函数中被调用。
 * 		其功能可以简单理解为将业务程序中的usRegInputBuf数组的值copy到pucRegBuffer数组中。
 * @param pucRegBuffer: 保存输入寄存器值的缓存
 * @param usAddress: 输入寄存器的起始地址
 * @param usNRegs: 输入寄存器的数量
 * @return modbus执行的错误状态码
 */
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;

    if( ( usAddress >= REG_INPUT_START )
        && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - REG_INPUT_START );
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}


/**
 * @brief 获取指定输入寄存器的值(读)
 * @param index: 输入寄存器的索引号
 * @return 指定输入寄存器的值数据(float类型)
 */
float InputReg_GetData(uint16_t index)
{
	return mb_InputRegUnion[index].toFloat;
}


/**
 * @brief  设置指定输入寄存器的值(写)
 * @param index: 输入寄存器的索引号
 * @param value: 需要设置的值(float类型)
 */
void InputRegReg_SetData(uint16_t index, float value)
{
	mb_InputRegUnion[index].toFloat = value;
}

保持寄存器

头文件

/*
 * mb_holdingreg.h
 *
 *  Created on: Oct 25, 2019
 *      Author: tao
 */

#ifndef REGISTERS_MB_HOLDINGREG_H_
#define REGISTERS_MB_HOLDINGREG_H_

#include "mb.h"

//设置起始地址(PLC地址,base 1)
#define REG_HOLDING_START 1000
//设置寄存器数量
#define REG_HOLDING_NREGS 200

typedef union
{
	float toFloat;
	uint16_t toUint16Array[2];
}MB_HoldingRegUnion;

extern USHORT usRegHoldingBuf[REG_HOLDING_NREGS];
extern MB_HoldingRegUnion *mb_HoldingRegUnion;

void RegHoldingBuf_Init();
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, uint16_t usAddress, uint16_t usNRegs, eMBRegisterMode eMode);
float HoldingReg_GetData(uint16_t index);
void HoldingReg_SetData(uint16_t index, float value);

#endif /* REGISTERS_MB_HOLDINGREG_H_ */

源文件

/*
 * mb_holdingreg.c
 *
 *  Created on: Oct 25, 2019
 *      Author: tao
 */

#include "mb_holdingreg.h"
#include "globalVariate.h"

//static USHORT usRegHoldingStart = REG_HOLDING_START;
USHORT usRegHoldingBuf[REG_HOLDING_NREGS];
MB_HoldingRegUnion *mb_HoldingRegUnion = (MB_HoldingRegUnion *) usRegHoldingBuf;


/**
 * @brief 完成保持寄存器的初始化
 * 		保持寄存器需要掉电保存,因此在初始化的时候需要读取EEPROM数据完成初始化
 */
void RegHoldingBuf_Init()
{
	for (uint8_t i = 0; i < STORABLE_DATA_COUNT; i++)
	{
		usRegHoldingBuf[2 * i] = StorableData[i + 1].value.toUint16Array[0];
		usRegHoldingBuf[2 * i + 1] = StorableData[i + 1].value.toUint16Array[1];
	}
}


/**
 * @brief 读保持寄存器的服务函数
 * 		在mbfuncholding.c的eMBFuncReadHoldingRegister, eMBFuncReadWriteMultipleHoldingRegister,
 * 		eMBFuncWriteHoldingRegister, eMBFuncWriteMultipleHoldingRegister四个函数中被调用。
 * 		其功能可以简单理解为将业务程序中的usRegInputBuf数组的值copy到pucRegBuffer数组中。
 * @param pucRegBuffer: 保存保持寄存器值的缓存
 * @param usAddress: 保存寄存器的起始地址
 * @param usNRegs: 保持寄存器的数量
 * @param eMode: 操作保持寄存器的模式(读 or 写)
 * @return modbus执行的错误状态码
 */
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, uint16_t usAddress, uint16_t usNRegs, eMBRegisterMode eMode)
{
	//错误状态
	eMBErrorCode eStatus = MB_ENOERR;
	//偏移量
	int16_t iRegIndex;

	//判断寄存器是不是在范围内
	if (((int16_t) usAddress >= REG_HOLDING_START) && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
	{
		//计算偏移量
		iRegIndex = (int16_t) (usAddress - REG_HOLDING_START);

		switch (eMode)
		{
		//读处理函数
		case MB_REG_READ:
			while (usNRegs > 0)
			{
				*pucRegBuffer++ = (uint8_t) (usRegHoldingBuf[iRegIndex] >> 8);
				*pucRegBuffer++ = (uint8_t) (usRegHoldingBuf[iRegIndex] & 0xFF);
				iRegIndex++;
				usNRegs--;
			}
			break;

			//写处理函数
		case MB_REG_WRITE:
			while (usNRegs > 0)
			{
				usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
				usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
				/**
				 * Sync holding register data to storable data.
				 * Save holding register data to eeprom.
				 */
				/*************************************/
				if (iRegIndex % 2 == 1)
				{
//					StorableData[iRegIndex / 2 + 1].value.toUint16Array[0] = usRegHoldingBuf[iRegIndex - 1];
//					StorableData[iRegIndex / 2 + 1].value.toUint16Array[1] = usRegHoldingBuf[iRegIndex];

					StorableData_SetValue_16BitArray(iRegIndex / 2 + 1,&usRegHoldingBuf[iRegIndex - 1]);
					StorableData_SaveValue((const EepromData_typedef *)&StorableData[iRegIndex / 2 + 1]);
				}
				/*************************************/

				iRegIndex++;
				usNRegs--;
			}
			break;
		default:
			eStatus = MB_EINVAL;
			break;
		}
	}
	else
	{
		//返回错误状态
		eStatus = MB_ENOREG;
	}

	return eStatus;
}


/**
 * @brief 获取指定保持寄存器的值(读)
 * @param index: 输入寄存器的索引号
 * @return 指定保持寄存器的值(float类型)
 */
float HoldingReg_GetData(uint16_t index)
{
	return mb_HoldingRegUnion[index].toFloat;
}


/**
 * @brief 设置指定保持寄存器的值(写)
 * @param index: 保持寄存器的索引号
 * @param value: 需要设置的值(float类型)
 */
void HoldingReg_SetData(uint16_t index, float value)
{
	mb_HoldingRegUnion[index].toFloat = value;
}

离散寄存器

头文件

/*
 * mb_discretereg.h
 *
 *  Created on: Oct 25, 2019
 *      Author: tao
 */

#ifndef REGISTERS_MB_DISCRETEREG_H_
#define REGISTERS_MB_DISCRETEREG_H_

#include "mb.h"

//设置起始地址(PLC地址,base 1)
#define REG_DISCRETE_START		1000
//设置寄存器数量
#define REG_DISCRETE_NREGS		20
//由于线圈/离散寄存器表示的是开关量,因此1个字节可以保存8个开关量
#define REG_DISCRETE_SIZE		REG_DISCRETE_NREGS * 8

UCHAR ucRegDiscteteBuf[REG_DISCRETE_NREGS];
void RegDiscreteBuf_Init();
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, uint16_t usAddress, uint16_t usNDiscrete );
uint8_t DiscreteReg_GetBit(uint16_t index);
void DiscreteReg_SetBit(uint16_t index, uint8_t status);

#endif /* REGISTERS_MB_DISCRETEREG_H_ */

源文件

/*
 * mb_discretereg.c
 *
 *  Created on: Oct 25, 2019
 *      Author: tao
 */

#include "mb_discretereg.h"
#include "mbutils.h"

//static USHORT usRegDiscreteStart = REG_DISCRETE_START;
UCHAR ucRegDiscreteBuf[REG_DISCRETE_NREGS];


/**
 * @brief 完成离散寄存器的初始化
 */
void RegDiscreteBuf_Init()
{
//	for(uint8_t i =0; i<REG_DISCRETE_SIZE; i++)
//	{
//		DiscreteReg_SetBit(i,0);
//	}
}


/**
 * @brief 读离散寄存器的服务函数
 * @param pucRegBuffer: 操作离散寄存器值的缓存
 * @param usAddress: 离散寄存器的首地址
 * @param usNDiscrete: 离散寄存器的数量(字节数组数量 x 8)
 * @return modbus执行的错误状态码
 */
eMBErrorCode eMBRegDiscreteCB(UCHAR * pucRegBuffer, uint16_t usAddress, uint16_t usNDiscrete)
{
	//错误状态
	eMBErrorCode eStatus = MB_ENOERR;
	//寄存器个数
	int16_t iNDiscrete = (int16_t) usNDiscrete;
	//偏移量
	uint16_t usBitOffset;

	//判断寄存器时候再制定范围内
	if (((int16_t) usAddress >= REG_DISCRETE_START)
			&& (usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE))
	{
		//获得偏移量
		usBitOffset = (uint16_t) (usAddress - REG_DISCRETE_START);

		while (iNDiscrete > 0)
		{
			*pucRegBuffer++ = xMBUtilGetBits(ucRegDiscreteBuf, usBitOffset, (uint8_t) (iNDiscrete > 8 ? 8 : iNDiscrete));
			iNDiscrete -= 8;
			usBitOffset += 8;
		}
	}
	else
	{
		eStatus = MB_ENOREG;
	}
	return eStatus;
}


/**
 * @brief 获取指定离散寄存器的值(读)
 * @param index: 离散寄存器的索引号
 * @return 指定离散寄存器的值(uint8_t类型)
 */
uint8_t DiscreteReg_GetBit(uint16_t index)
{
	return ((0x01 << index%8) & ucRegDiscreteBuf[index/8]) >> (index%8);
}


/**
 * @brief 设置指定离散寄存器的值(写)
 * @param index: 离散寄存器的索引号
 * @param value: 需要设置的值(uint8_t类型)
 */
void DiscreteReg_SetBit(uint16_t index, uint8_t status)
{
	if(status != 0)
	{
		ucRegDiscreteBuf[index/8] |= (0x01 << (index%8));
	}
	else
	{
		ucRegDiscreteBuf[index/8] &= (~(0x01 << (index%8)));
	}
}


线圈寄存器

头文件

/*
 * mb_coilsreg.h
 *
 *  Created on: Oct 25, 2019
 *      Author: tao
 */

#ifndef REGISTERS_MB_COILSREG_H_
#define REGISTERS_MB_COILSREG_H_

#include "mb.h"

//设置起始地址(PLC地址,base 1)
#define REG_COILS_START 1000
//设置寄存器数量
#define REG_COILS_NREGS 20
//由于线圈/离散寄存器表示的是开关量,因此1个字节可以保存8个开关量
#define REG_COILS_SIZE REG_COILS_NREGS * 8

UCHAR ucRegCoilsBuf[REG_COILS_NREGS];
void RegCoilsBuf_Init();
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, uint16_t usAddress, uint16_t usNCoils, eMBRegisterMode eMode );
uint8_t CoilsReg_GetBit(uint16_t index);
void CoilsReg_SetBit(uint16_t index, uint8_t status);

#endif /* REGISTERS_MB_COILSREG_H_ */

源文件

/*
 * mb_coilsreg.c
 *
 *  Created on: Oct 25, 2019
 *      Author: tao
 */

#include "mb_coilsreg.h"
#include "mbutils.h"

UCHAR ucRegCoilsBuf[REG_COILS_NREGS];


/**
 * @brief 完成线圈寄存器的初始化
 */
void RegCoilsBuf_Init()
{
//	for(uint8_t i =0; i<REG_COILS_SIZE; i++)
//	{
//		CoilsReg_SetBit(i,0);
//	}
}


/**
 * @brief 读写线圈寄存器的服务函数
 * @param pucRegBuffer: 操作线圈寄存器值的缓存
 * @param usAddress: 线圈寄存器的首地址
 * @param usNCoils: 线圈寄存器的数量(字节数组数量 x 8)
 * @param eMode: 操作线圈寄存器的模式(读 or 写)
 * @return modbus执行的错误状态码
 */
eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, uint16_t usAddress, uint16_t usNCoils, eMBRegisterMode eMode)
{
	//错误状态
	eMBErrorCode eStatus = MB_ENOERR;
	//寄存器个数
	int16_t iNCoils = (int16_t) usNCoils;
	//寄存器偏移量
	int16_t usBitOffset;

	//检查寄存器是否在指定范围内
	if (((int16_t) usAddress >= REG_COILS_START) && (usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE))
	{
		//计算寄存器偏移量
		usBitOffset = (int16_t) (usAddress - REG_COILS_START);
		switch (eMode)
		{
		//读操作
		case MB_REG_READ:
			while (iNCoils > 0)
			{
				*pucRegBuffer++ = xMBUtilGetBits(ucRegCoilsBuf, usBitOffset, (uint8_t) (iNCoils > 8 ? 8 : iNCoils));
				iNCoils -= 8;
				usBitOffset += 8;
			}


			break;

			//写操作
		case MB_REG_WRITE:
			while (iNCoils > 0)
			{
				xMBUtilSetBits(ucRegCoilsBuf, usBitOffset, (uint8_t) (iNCoils > 8 ? 8 : iNCoils), *pucRegBuffer++);
				iNCoils -= 8;
			}
			break;
		default:
			eStatus = MB_EINVAL;
			break;
		}
	}
	else
	{
		eStatus = MB_ENOREG;
	}
	return eStatus;
}


/**
 * @brief 获取指定线圈寄存器的值(读)
 * @param index: 线圈寄存器的索引号
 * @return 指定线圈寄存器的值(uint8_t类型)
 */
uint8_t CoilsReg_GetBit(uint16_t index)
{
	return ((0x01 << index%8) & ucRegCoilsBuf[index/8]) >> (index%8);
}


/**
 * @brief 设置指定线圈寄存器的值(写)
 * @param index: 线圈寄存器的索引号
 * @param value: 需要设置的值(uint8_t类型)
 */
void CoilsReg_SetBit(uint16_t index, uint8_t status)
{
	if(status != 0)
	{
		ucRegCoilsBuf[index/8] |= (0x01 << (index%8));
	}
	else
	{
		ucRegCoilsBuf[index/8] &= (~(0x01 << (index%8)));
	}
}

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全能骑士涛锅锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值