val-off-little/modbus/modbus_rtu.c

653 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "modbus.h"
void modbus_errfunction_rtu(uint8_t uCmdCode, uint8_t uErrorCode);
uint8_t uart1_rx_buf[UART1_RXSIZE]; //发送数据缓冲数组
uint8_t uart1_tx_buf[UART1_TXSIZE]; //接收数据缓冲数据
void modbus_rtu_init(UART_HandleTypeDef *huart,TIM_HandleTypeDef *htim)
{
if(huart->Instance == USART1)
{
MODBUS_UART.rx_buf = uart1_rx_buf; //接收数据变量初始化
MODBUS_UART.rx_buf_cnt = 0;
MODBUS_UART.rx_size = 0;
MODBUS_UART.rx_flag = 0;
MODBUS_UART.tx_buf = uart1_tx_buf; //发送数据变量初始化
MODBUS_UART.tx_buf_cnt = UART1_TXSIZE;
MODBUS_UART.tx_size = 0;
HAL_UART_Receive_IT(huart, (uint8_t *)&RxBuffer, 1); //开启接收中断
}
if(htim == &MODBUS_HTIM)
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); //手动添加
HAL_TIM_Base_Start_IT(htim);
}
}
void modbus_rx_cb(void)
{
if(uart1.rx_buf_cnt >= UART1_RXSIZE-1) //接收数据量超限,错误
{
MODBUS_UART.rx_buf_cnt = 0;
memset(MODBUS_UART.rx_buf, 0x00, sizeof(&MODBUS_UART.rx_buf));
HAL_UART_Transmit(&MODBUS_HUART, (uint8_t *)"数据溢出", 10, 0xFFFF);
}
else //接收正常
{
uart1.rx_buf[MODBUS_UART.rx_buf_cnt++] = RxBuffer; //接收数据存储到rx_buf
HAL_TIM_Base_Stop_IT(&MODBUS_HTIM);
__HAL_TIM_SET_COUNTER(&MODBUS_HTIM, 0);
HAL_TIM_Base_Start_IT(&MODBUS_HTIM); //将定时器7的计数值清零后重新计数
}
HAL_UART_Receive_IT(&MODBUS_HUART, (uint8_t *)&RxBuffer, 1);
}
/*******************************************************************************
函数名称 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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
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);
modbus_send(&MODBUS_HUART, MODBUS_UART.tx_buf, MODBUS_UART.tx_size);
}
/*******************************************************************************
函数名称 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 = MODBUS_UART.rx_buf; // 接收数据起始地址
wFrameLen = MODBUS_UART.rx_size; // 接收数据长度
if(wFrameLen < 2) return; // 数据长度不是有效值
// 获取接收数据帧中的校验和
wFrameCRC = MAKEWORD(pFrame[wFrameLen - 2], pFrame[wFrameLen - 1]);
// 计算接收到的数据的校验和
wCalCRC = ModbusCRC16(pFrame, wFrameLen - 2);
if(wFrameCRC != wCalCRC) return;
modbus_analysis_rtu(MODBUS_UART.rx_buf, MODBUS_UART.rx_size);// 协议处理
}