765 lines
27 KiB
C
765 lines
27 KiB
C
#include "modbus_rtu.h"
|
||
|
||
uint8_t CoilState[(MAX_COIL_NUM + 7) / 8] = {0x00,0x00,0x00,0x00,0x00}; //线圈寄存器
|
||
uint8_t DisState[(MAX_DIS_NUM + 7) / 8] = {0x00,0x00,0x00,0x00,0x00,0x00}; //离散量寄存器
|
||
uint16_t InputReg[MAX_INPUT_REG_NUM] = {0x0000,0x0000,0x0000,0x0000}; //输入寄存器
|
||
uint16_t HoldReg[MAX_HOLD_REG_NUM] = {0, 0,0,0x00C8}; //保持寄存器
|
||
|
||
Var_Reg SamVarReg;
|
||
eMBException ex_message = MB_EX_NONE; //从设备返回的异常信息
|
||
|
||
/*******************************************************************************
|
||
函数名称 : Modbus_Analysis
|
||
功 能 : CRC校验
|
||
参 数 : ptr--校验数组指针 len--校验数据长度
|
||
返 回 值 : CRC校验码,双字节
|
||
*******************************************************************************/
|
||
void modbus_analysis_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint8_t uSlaveAdd, uCmdCode;
|
||
|
||
if((upRxdbuf == NULL) || (wRxdLen < 2)) return;
|
||
|
||
uSlaveAdd = upRxdbuf[0];
|
||
uCmdCode = upRxdbuf[1];
|
||
|
||
// 从机地址为本机地址或者是广播帧
|
||
if((uSlaveAdd == LOCAL_ADDRESS) || (uSlaveAdd == BROADCAST_ADDRESS))
|
||
{
|
||
switch(uCmdCode)
|
||
{
|
||
case ReadCoilState:
|
||
readcoilstate_rtu(upRxdbuf + 2, wRxdLen - 2); // 读线圈状态
|
||
break;
|
||
|
||
case ReadDisInputState:
|
||
readdisinputstate_rtu(upRxdbuf + 2, wRxdLen - 2); // 读离散输入状态
|
||
break;
|
||
|
||
case ReadHoldReg:
|
||
readholdreg_rtu(upRxdbuf + 2, wRxdLen - 2); // 读取保持寄存器
|
||
break;
|
||
|
||
case ReadInputReg:
|
||
readinputreg_rtu(upRxdbuf + 2, wRxdLen - 2); // 读取输入寄存器
|
||
break;
|
||
|
||
case WriteSingleReg:
|
||
writesinglereg_rtu(upRxdbuf + 2, wRxdLen - 2); // 写单个寄存器
|
||
break;
|
||
|
||
case WriteMultiCoil:
|
||
writemulticoil_rtu(upRxdbuf + 2, wRxdLen - 2); // 写多个线圈
|
||
break;
|
||
|
||
case WriteMultiReg:
|
||
writemultireg_rtu(upRxdbuf + 2, wRxdLen - 2); // 写多个寄存器
|
||
break;
|
||
|
||
case WriteSingleCoil:
|
||
writesinglecoil_rtu(upRxdbuf + 2, wRxdLen - 2); // 写单个线圈
|
||
break;
|
||
|
||
default:
|
||
modbus_errfunction_rtu(upRxdbuf[1], 0x01); // 错误码处理
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void modbus_process_rtu(void)
|
||
{
|
||
uint8_t *pFrame;
|
||
uint16_t wFrameLen = 0;
|
||
uint16_t wFrameCRC, wCalCRC;
|
||
|
||
pFrame = scom2_rs485.rx_buff; // 接收数据起始地址
|
||
wFrameLen = scom2_rs485.rx_len; // 接收数据长度
|
||
|
||
if(wFrameLen < 2) return; // 数据长度不是有效值
|
||
|
||
// 获取接收数据帧中的校验和
|
||
wFrameCRC = MAKEWORD(pFrame[wFrameLen - 2], pFrame[wFrameLen - 1]);
|
||
// 计算接收到的数据的校验和
|
||
wCalCRC = ModbusCRC16(pFrame, wFrameLen - 2);
|
||
if(wFrameCRC != wCalCRC) return;
|
||
|
||
modbus_analysis_rtu(scom2_rs485.rx_buff, scom2_rs485.rx_len);// 协议处理
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ReadCoilStateFUNC
|
||
功 能 : 功能码:0x01,读取线圈
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][01][线圈起始地址高][线圈起始地址低][线圈数量高][线圈数量低][CRC低][CRC高]
|
||
*返回:[硬件地址][01][字节长度][线圈值][线圈值][线圈值][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void readcoilstate_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wCoilStartAddr,wCoilNum,wTotalCoilNum,CRC16Temp;
|
||
uint8_t i,k,uCommIndexNum = 0,uByteCount,uCoilVal,uErrorCode,uExit = 0;
|
||
uint8_t upTxdbuf[MAX_SIZE] = {0};
|
||
|
||
wCoilStartAddr = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取线圈起始地址
|
||
wCoilNum = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取线圈个数
|
||
|
||
if((wCoilNum >= 0x0001) || (wCoilNum <= MAX_COIL_NUM))
|
||
{
|
||
if(((wCoilStartAddr <= COIL_ADD_MAX)) &&
|
||
(wCoilNum + wCoilStartAddr <= COIL_ADD_MAX + 1))//(wCoilStartAddr >= COIL_ADD_MIN) &&
|
||
{
|
||
uByteCount = (wCoilNum + 7) / 8; //返回数据字节个数
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = ReadCoilState;
|
||
upTxdbuf[uCommIndexNum ++] = uByteCount;
|
||
|
||
wTotalCoilNum = 0;
|
||
for(k = 0; k < uByteCount; k++)
|
||
{
|
||
upTxdbuf[uCommIndexNum] = 0;
|
||
for(i = 0; i < 8; i++)
|
||
{
|
||
GetOneCoilVal(wCoilStartAddr + wTotalCoilNum,&uCoilVal);
|
||
upTxdbuf[uCommIndexNum] |= uCoilVal << i;
|
||
|
||
wTotalCoilNum ++;
|
||
if(wTotalCoilNum >= wCoilNum)
|
||
{
|
||
uExit = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
uCommIndexNum ++;
|
||
|
||
if(uExit == 1)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
|
||
modbus_errfunction_rtu(ReadCoilState, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ReadDisInputStateFUNC
|
||
功 能 : 功能码:0x02,读取离散量
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][02][离散量起始地址高][离散量起始地址低][离散量数量高][离散量数量低][CRC低][CRC高]
|
||
*返回:[硬件地址][02][字节长度][离散量值][离散量值][离散量值][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void readdisinputstate_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wDisStartAddr,wDisNum,wTotalDisNum,CRC16Temp;
|
||
uint8_t i,k,uCommIndexNum = 0,uByteCount,uDisVal,uErrorCode,uExit = 0;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
wDisStartAddr = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取离散量起始地址
|
||
wDisNum = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取离散量个数
|
||
|
||
if((wDisNum >= 0x0001) || (wDisNum <= MAX_DIS_NUM))
|
||
{
|
||
if(((wDisStartAddr <= DIS_ADD_MAX)) &&
|
||
(wDisNum + wDisStartAddr <= DIS_ADD_MAX + 1))//(wDisStartAddr >= DIS_ADD_MIN) &&
|
||
{
|
||
uByteCount = (wDisNum + 7) / 8; //返回数据字节个数
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = ReadDisInputState;
|
||
upTxdbuf[uCommIndexNum ++] = uByteCount;
|
||
|
||
wTotalDisNum = 0;
|
||
for(k = 0; k < uByteCount; k++)
|
||
{
|
||
upTxdbuf[uCommIndexNum] = 0;
|
||
for(i = 0; i < 8; i++)
|
||
{
|
||
GetOneDisInputVal(wDisStartAddr + wTotalDisNum,&uDisVal);
|
||
upTxdbuf[uCommIndexNum] |= uDisVal << i;
|
||
|
||
wTotalDisNum ++;
|
||
if(wTotalDisNum >= wDisNum)
|
||
{
|
||
uExit = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
uCommIndexNum ++;
|
||
|
||
if(uExit == 1)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
|
||
modbus_errfunction_rtu(ReadDisInputState, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ReadHoldRegFUNC
|
||
功 能 : 功能码:0x03,读取保持寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][03][起始地址高][起始地址低][总寄存器数高][总寄存器数低][CRC低][CRC高]
|
||
*返回:[硬件地址][03][字节数][寄存器0高][寄存器0低][寄存器1高][寄存器1低][寄存器n高][寄存器n低][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void readholdreg_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wRegStartAdd, wRegLen, i, wRegValue, CRC16Temp;
|
||
uint8_t uErrorCode, uCommIndexNum = 0;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
if(upRxdbuf == NULL) return;
|
||
|
||
wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器起始地址
|
||
wRegLen = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取读取寄存器长度
|
||
|
||
if((wRegLen >= 0x01) && (wRegLen <= MAX_HOLD_REG_NUM))
|
||
{
|
||
if(((wRegStartAdd <= HOLD_REG_ADD_MAX)) &&
|
||
(((wRegStartAdd + wRegLen) >= HOLD_REG_ADD_MIN) && ((wRegStartAdd + wRegLen) <= HOLD_REG_ADD_MAX + 1)))//(wRegStartAdd >= HOLD_REG_ADD_MIN) &&
|
||
{
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = ReadHoldReg;
|
||
upTxdbuf[uCommIndexNum ++] = wRegLen * 2;
|
||
|
||
for(i = 0; i < wRegLen; i++)
|
||
{
|
||
//获取16位数据并返回
|
||
wRegValue = GetHoldRegData(wRegStartAdd + i);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue >> 8);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue & 0xFF);
|
||
}
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8); // crc16高字节在后
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
modbus_errfunction_rtu(ReadHoldReg, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ReadInputRegFUNC
|
||
功 能 : 功能码:0x04,读取输入寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][04][起始地址高][起始地址低][总寄存器数高][总寄存器数低][ CRC低 ][ CRC高 ]
|
||
*返回:[硬件地址][04][ 字节数 ][寄存器0高 ][ 寄存器0低 ][ 寄存器1高 ][ 寄存器1低 ][ 寄存器n高 ][ 寄存器n低 ][ CRC低 ][ CRC高 ]
|
||
*******************************************************************************/
|
||
void readinputreg_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wRegStartAdd, wRegLen, i, wRegValue, CRC16Temp;
|
||
uint8_t uErrorCode, uCommIndexNum = 0;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
if(upRxdbuf == NULL) return;
|
||
|
||
wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器起始地址
|
||
wRegLen = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取读取寄存器长度
|
||
|
||
if((wRegLen >= 0x01) && (wRegLen <= MAX_INPUT_REG_NUM))
|
||
{
|
||
if(((wRegStartAdd <= INPUT_REG_ADD_MAX)) &&
|
||
((wRegStartAdd + wRegLen) <= INPUT_REG_ADD_MAX + 1))//(wRegStartAdd >= INPUT_REG_ADD_MIN) &&
|
||
{
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = ReadInputReg;
|
||
upTxdbuf[uCommIndexNum ++] = wRegLen * 2;
|
||
|
||
for(i = 0; i < wRegLen; i++)
|
||
{
|
||
//获取16位数据并返回
|
||
wRegValue = GetInputRegData(wRegStartAdd + i);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue >> 8);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue & 0xFF);
|
||
}
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8); // crc16高字节在后
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
modbus_errfunction_rtu(ReadInputReg, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteSingleRegFUNC
|
||
功 能 : 功能码:0x06 预设(写)单寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
|
||
*返回:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void writesinglereg_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wRegAddr, wRegValue, CRC16Temp;
|
||
uint8_t uCommIndexNum = 0, uErrorCode;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
if(upRxdbuf == NULL) return;
|
||
|
||
wRegAddr = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器地址
|
||
wRegValue = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取数据
|
||
|
||
if((wRegAddr <= HOLD_REG_ADD_MAX))//(wRegAddr >= HOLD_REG_ADD_MIN) &&
|
||
{
|
||
WriteHoldRegData(wRegAddr, wRegValue);
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = WriteSingleReg;
|
||
memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
|
||
uCommIndexNum += 4;
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8); // crc16高字节在后
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
modbus_errfunction_rtu(WriteSingleReg, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteMultiRegFUNC
|
||
功 能 : 功能码:0x10 写多个保持寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*******************************************************************************/
|
||
void writemultireg_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t i, wRegStartAdd, wRegNum, CRC16Temp, uErrorCode, wRegValue;
|
||
uint8_t uCommIndexNum = 0, uByteNum;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
if(upRxdbuf == NULL) return;
|
||
|
||
wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器地址
|
||
wRegNum = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取寄存器数量
|
||
uByteNum = upRxdbuf[4]; //获取字节数
|
||
|
||
if((wRegNum >= 0x01) && (wRegNum <= MAX_HOLD_REG_NUM) && (uByteNum == wRegNum * 2))
|
||
{
|
||
if(((wRegStartAdd <= HOLD_REG_ADD_MAX) &&
|
||
(wRegStartAdd + wRegNum <= HOLD_REG_ADD_MAX + 1)))//(wRegStartAdd >= HOLD_REG_ADD_MIN) &&
|
||
{
|
||
for(i = 0; i < wRegNum; i++)
|
||
{
|
||
wRegValue = MAKEWORD(upRxdbuf[6 + i * 2], upRxdbuf[5 + i * 2]);
|
||
WriteHoldRegData(wRegStartAdd + i, wRegValue);
|
||
}
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = WriteMultiReg;
|
||
memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
|
||
uCommIndexNum += 4;
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
modbus_errfunction_rtu(WriteMultiReg, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteSingleCoilFUNC
|
||
功 能 : 功能码:0x05 写单个线圈寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*******************************************************************************/
|
||
void writesinglecoil_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wCoilAddr, wCoilValue, CRC16Temp;
|
||
uint8_t uCommIndexNum = 0, uErrorCode;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
wCoilAddr = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取线圈地址
|
||
wCoilValue = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取线圈数据
|
||
|
||
if((wCoilValue == 0x0000) || (wCoilValue == 0xFF00))
|
||
{
|
||
if((wCoilAddr <= COIL_ADD_MAX))//(wCoilAddr >= DIS_ADD_MIN ) &&
|
||
{
|
||
WriteOneCoilData(wCoilAddr, wCoilValue);
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = WriteSingleCoil;
|
||
memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
|
||
uCommIndexNum += 4;
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
modbus_errfunction_rtu(WriteSingleCoil, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteMultiCoilFUNC
|
||
功 能 : 功能码:0x0F,写多个线圈
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][字节数][线圈值][CRC低][CRC高]
|
||
*返回:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void writemulticoil_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint16_t wCoilStartAddr,wCoilNum,wCoilVal,wTotalCoilNum,CRC16Temp;
|
||
uint8_t i,k,uCommIndexNum = 0,uByteNum,uByteVal,uExit = 0,uErrorCode;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
wCoilStartAddr = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取线圈地址
|
||
wCoilNum = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取线圈个数
|
||
uByteNum = upRxdbuf[4]; //获取字节数
|
||
|
||
if((wCoilNum >= 0x01) && (wCoilNum <= MAX_COIL_NUM) && (wCoilNum <= 8 * uByteNum))
|
||
{
|
||
if((wCoilStartAddr <= COIL_ADD_MAX) &&
|
||
(wCoilStartAddr + wCoilNum <= COIL_ADD_MAX + 1))//(wCoilStartAddr >= COIL_ADD_MIN) &&
|
||
{
|
||
wTotalCoilNum = 0;
|
||
for(k = 0; k < uByteNum; k++)
|
||
{
|
||
uByteVal = upRxdbuf[5 + k];
|
||
for(i = 0; i < 8; i++)
|
||
{
|
||
if(uByteVal & (1 << i)) wCoilVal = 0xFF00;
|
||
else wCoilVal = 0x0000;
|
||
|
||
WriteOneCoilData(wCoilStartAddr + wTotalCoilNum, wCoilVal);
|
||
|
||
wTotalCoilNum ++;
|
||
if(wTotalCoilNum >= wCoilNum)
|
||
{
|
||
uExit = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(uExit == 1)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = WriteMultiCoil;
|
||
memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
|
||
uCommIndexNum += 4;
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
|
||
}
|
||
modbus_errfunction_rtu(WriteMultiCoil, uErrorCode);
|
||
return;
|
||
}
|
||
|
||
/********
|
||
***********************************************************************
|
||
函数名称 : MODBUS_ERRFunction
|
||
功 能: 错误回应指令
|
||
参 数: 无
|
||
返 回 值: 无
|
||
异常功能码 = 功能码+0x80
|
||
*******************************************************************************/
|
||
void modbus_errfunction_rtu(uint8_t uCmdCode, uint8_t uErrorCode)
|
||
{
|
||
uint8_t uCommIndexNum = 0;
|
||
uint16_t CRC16Temp = 0;
|
||
uint8_t upTxdbuf[MAX_SIZE];
|
||
|
||
upTxdbuf[uCommIndexNum ++] = LOCAL_ADDRESS;
|
||
upTxdbuf[uCommIndexNum ++] = uCmdCode | 0x80;
|
||
upTxdbuf[uCommIndexNum ++] = uErrorCode;
|
||
|
||
CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); //crc16低字节在前
|
||
upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
// MODBUS_UART.tx_size = (uCommIndexNum <= MODBUS_UART.tx_buf_cnt ? uCommIndexNum : MODBUS_UART.tx_buf_cnt);
|
||
// memcpy(MODBUS_UART.tx_buf, upTxdbuf, MODBUS_UART.tx_size);
|
||
// uart_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
|
||
scom2_rs485.tx_len = (uCommIndexNum <= MAX_SIZE)?(uCommIndexNum):(MAX_SIZE);
|
||
memcpy(scom2_rs485.tx_buff, upTxdbuf, scom2_rs485.tx_len);
|
||
scom2_rs485.tx_flag = TRUE;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ModbusCRC16
|
||
功 能 : CRC校验
|
||
参 数 : ptr--校验数组指针 len--校验数据长度
|
||
返 回 值 : CRC校验码,双字节
|
||
*******************************************************************************/
|
||
uint16_t ModbusCRC16(uint8_t *ptr, uint16_t len)
|
||
{
|
||
uint8_t i;
|
||
uint16_t crc = ~0x00;
|
||
|
||
if((ptr == NULL) || (len == 0xFFFF)) return crc;
|
||
|
||
while(len--)
|
||
{
|
||
crc ^= *ptr++;
|
||
for(i = 0; i < 8; i++)
|
||
{
|
||
if(crc & 0x01)
|
||
{
|
||
crc >>= 1;
|
||
crc ^= 0xA001;
|
||
}
|
||
else
|
||
{
|
||
crc >>= 1;
|
||
}
|
||
}
|
||
}
|
||
return(crc);
|
||
}
|
||
|
||
void GetOneCoilVal(uint16_t wCoilAddr, uint8_t *pCoilVal)
|
||
{
|
||
uint8_t uVal;
|
||
|
||
uVal = CoilState[(wCoilAddr - COIL_ADD_MIN) / 8 ];
|
||
if(uVal & ( 1 << ((wCoilAddr - COIL_ADD_MIN) % 8 )))
|
||
{
|
||
*pCoilVal = 0x01;
|
||
}
|
||
else
|
||
{
|
||
*pCoilVal = 0x00;
|
||
}
|
||
}
|
||
|
||
void GetOneDisInputVal(uint16_t wDisInputAddr, uint8_t *pDisInputVal)
|
||
{
|
||
uint8_t uVal;
|
||
|
||
uVal = DisState[(wDisInputAddr - DIS_ADD_MIN) / 8 ];
|
||
if(uVal & ( 1 << ((wDisInputAddr - DIS_ADD_MIN) % 8 )))
|
||
{
|
||
*pDisInputVal = 0x01;
|
||
}
|
||
else
|
||
{
|
||
*pDisInputVal = 0x00;
|
||
}
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : GetHoldRegData
|
||
功 能 : 获取RegAdd的数据
|
||
参 数 : u16 RegAdd
|
||
返 回 值 : 两字节寄存器数据
|
||
*******************************************************************************/
|
||
uint16_t GetHoldRegData(uint16_t RegAdd)
|
||
{
|
||
int16_t wRegValue;
|
||
|
||
wRegValue = HoldReg[RegAdd - HOLD_REG_ADD_MIN];
|
||
|
||
return wRegValue;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : GetInputRegData
|
||
功 能 : 获取RegAdd的数据
|
||
参 数 : u16 RegAdd
|
||
返 回 值 : 两字节寄存器数据
|
||
*******************************************************************************/
|
||
uint16_t GetInputRegData(uint16_t RegAdd)
|
||
{
|
||
int16_t wRegValue;
|
||
|
||
wRegValue = InputReg[RegAdd - INPUT_REG_ADD_MIN];
|
||
|
||
return wRegValue;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteHoldRegData
|
||
功 能 : 保存写入的保持寄存器数据
|
||
参 数 : u16 StartAdd
|
||
返 回 值 : 无
|
||
*******************************************************************************/
|
||
void WriteHoldRegData(uint16_t wRegAddr, uint16_t RegData)
|
||
{
|
||
HoldReg[wRegAddr - HOLD_REG_ADD_MIN] = RegData;
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteOneCoilData
|
||
功 能 : 保存写入的线圈寄存器数据
|
||
参 数 : u16 StartAdd
|
||
返 回 值 : 无
|
||
*******************************************************************************/
|
||
void WriteOneCoilData(uint16_t wRegAddr, uint16_t RegData)
|
||
{
|
||
if(RegData == 0xFF00)
|
||
{
|
||
CoilState[(wRegAddr - COIL_ADD_MIN) / 8] |= 1 << ((wRegAddr - COIL_ADD_MIN) % 8);
|
||
}
|
||
else if(RegData == 0x0000)
|
||
{
|
||
CoilState[(wRegAddr - COIL_ADD_MIN) / 8] &= ~(1 << ((wRegAddr - COIL_ADD_MIN) % 8));
|
||
}
|
||
}
|