292 lines
8.7 KiB
C
292 lines
8.7 KiB
C
#include "modbus.h"
|
||
|
||
uint8_t uart3_rx_buf[MAX_SIZE]; //发送数据缓冲数组
|
||
uint8_t uart3_tx_buf[MAX_SIZE]; //接收数据缓冲数据
|
||
uint16_t uart3_rx_cnt = 0;
|
||
uint16_t uart3_rx_size = 0;
|
||
uint8_t uart3_rxbuf = 0;
|
||
|
||
uint8_t uart6_rx_buf[MAX_SIZE]; //发送数据缓冲数组
|
||
uint8_t uart6_tx_buf[MAX_SIZE]; //接收数据缓冲数据
|
||
uint16_t uart6_rx_cnt = 0;
|
||
uint16_t uart6_rx_size = 0;
|
||
uint8_t uart6_rxbuf = 0;
|
||
|
||
uint8_t HostTxdbuf[100];
|
||
|
||
void modbus_host_init(void)
|
||
{
|
||
HAL_UART_Receive_IT(&huart3, (uint8_t *)&uart3_rxbuf, 1); //开启接收中断
|
||
HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart6_rxbuf, 1); //开启接收中断
|
||
__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); //手动添加
|
||
HAL_TIM_Base_Start_IT(&htim4);
|
||
__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE); //手动添加
|
||
HAL_TIM_Base_Start_IT(&htim5);
|
||
}
|
||
|
||
void modbus_uart3_rx_cb(void)
|
||
{
|
||
if(uart3_rx_cnt >= MAX_SIZE-1) //接收数据量超限,错误
|
||
{
|
||
uart3_rx_cnt = 0;
|
||
memset(uart3_rx_buf, 0x00, sizeof(&uart3_rx_cnt));
|
||
HAL_UART_Transmit(&huart3, (uint8_t *)"数据溢出", 10, 0xFFFF);
|
||
}
|
||
else //接收正常
|
||
{
|
||
uart3_rx_buf[uart3_rx_cnt++] = uart3_rxbuf; //接收数据存储到rx_buf
|
||
HAL_TIM_Base_Stop_IT(&htim4);
|
||
__HAL_TIM_SET_COUNTER(&htim4, 0);
|
||
HAL_TIM_Base_Start_IT(&htim4); //将定时器7的计数值清零后重新计数
|
||
send_cnt = 0;
|
||
}
|
||
HAL_UART_Receive_IT(&huart3, (uint8_t *)&uart3_rxbuf, 1);
|
||
}
|
||
|
||
void modbus_uart6_rx_cb(void)
|
||
{
|
||
if(uart6_rx_cnt >= MAX_SIZE-1) //接收数据量超限,错误
|
||
{
|
||
uart6_rx_cnt = 0;
|
||
memset(uart6_rx_buf, 0x00, sizeof(&uart6_rx_cnt));
|
||
HAL_UART_Transmit(&huart6, (uint8_t *)"数据溢出", 10, 0xFFFF);
|
||
}
|
||
else //接收正常
|
||
{
|
||
uart6_rx_buf[uart6_rx_cnt++] = uart6_rxbuf; //接收数据存储到rx_buf
|
||
HAL_TIM_Base_Stop_IT(&htim5);
|
||
__HAL_TIM_SET_COUNTER(&htim5, 0);
|
||
HAL_TIM_Base_Start_IT(&htim5); //将定时器7的计数值清零后重新计数
|
||
send_cnt = 0;
|
||
}
|
||
HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart6_rxbuf, 1);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ReadDisInputStateFUNC
|
||
功 能 : 功能码:0x02,读取离散量
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][02][离散量起始地址高][离散量起始地址低][离散量数量高][离散量数量低][CRC低][CRC高]
|
||
*返回:[硬件地址][02][字节长度][离散量值][离散量值][离散量值][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void readdisinputstate_host(uint8_t local_addr, uint16_t star_addr, uint16_t reg_num)
|
||
{
|
||
uint16_t CRC16Temp;
|
||
|
||
HostTxdbuf[0] = local_addr;
|
||
|
||
HostTxdbuf[1] = 0x02;
|
||
|
||
HostTxdbuf[2] = (uint8_t)(star_addr >> 8);
|
||
HostTxdbuf[3] = (uint8_t)(star_addr & 0xFF);
|
||
|
||
HostTxdbuf[4] = (uint8_t)(reg_num >> 8);
|
||
HostTxdbuf[5] = (uint8_t)(reg_num & 0xFF);
|
||
|
||
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
|
||
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
|
||
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
uart_send(&huart6,HostTxdbuf,8);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : ReadInputRegFUNC
|
||
功 能 : 功能码:0x04,读取输入寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][04][起始地址高][起始地址低][总寄存器数高][总寄存器数低][ CRC低 ][ CRC高 ]
|
||
*返回:[硬件地址][04][ 字节数 ][寄存器0高 ][ 寄存器0低 ][ 寄存器1高 ][ 寄存器1低 ][ 寄存器n高 ][ 寄存器n低 ][ CRC低 ][ CRC高 ]
|
||
*******************************************************************************/
|
||
void readinputreg_host(uint8_t local_addr, uint16_t star_addr, uint16_t reg_num)
|
||
{
|
||
uint16_t CRC16Temp;
|
||
|
||
HostTxdbuf[0] = local_addr;
|
||
|
||
HostTxdbuf[1] = 0x04;
|
||
|
||
HostTxdbuf[2] = (uint8_t)(star_addr >> 8);
|
||
HostTxdbuf[3] = (uint8_t)(star_addr & 0xFF);
|
||
|
||
HostTxdbuf[4] = (uint8_t)(reg_num >> 8);
|
||
HostTxdbuf[5] = (uint8_t)(reg_num & 0xFF);
|
||
|
||
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
|
||
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
|
||
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
uart_send(&huart6,HostTxdbuf,8);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteSingleCoilFUNC
|
||
功 能 : 功能码:0x05 写单个线圈寄存器,写入0xFF00表示将线圈置为ON,写入0x0000表示将线圈置为OFF
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][05][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
|
||
*返回:[硬件地址][05][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void writesinglecoil_host(uint8_t local_addr, uint16_t reg_addr, uint16_t reg_data)
|
||
{
|
||
uint16_t CRC16Temp;
|
||
|
||
HostTxdbuf[0] = local_addr;
|
||
|
||
HostTxdbuf[1] = 0x05;
|
||
|
||
HostTxdbuf[2] = (uint8_t)(reg_addr >> 8);
|
||
HostTxdbuf[3] = (uint8_t)(reg_addr & 0xFF);
|
||
|
||
HostTxdbuf[4] = (uint8_t)(reg_data >> 8);
|
||
HostTxdbuf[5] = (uint8_t)(reg_data & 0xFF);
|
||
|
||
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
|
||
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
|
||
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
uart_send(&huart6,HostTxdbuf,8);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteMultiCoilFUNC
|
||
功 能 : 功能码:0x0F,写多个线圈,此函数为特化版,最多写8个线圈,字节数固定为1
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][字节数][线圈值][CRC低][CRC高]
|
||
*返回:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void writemulticoil_host(uint8_t local_addr, uint16_t reg_addr, uint16_t reg_num, uint8_t reg_data)
|
||
{
|
||
uint16_t CRC16Temp;
|
||
|
||
HostTxdbuf[0] = local_addr;
|
||
|
||
HostTxdbuf[1] = 0x0F;
|
||
|
||
HostTxdbuf[2] = (uint8_t)(reg_addr >> 8);
|
||
HostTxdbuf[3] = (uint8_t)(reg_addr & 0xFF);
|
||
|
||
HostTxdbuf[4] = (uint8_t)(reg_num >> 8);
|
||
HostTxdbuf[5] = (uint8_t)(reg_num & 0xFF);
|
||
|
||
HostTxdbuf[6] = 0x01;
|
||
HostTxdbuf[7] = reg_data;
|
||
|
||
CRC16Temp = ModbusCRC16(HostTxdbuf, 8);
|
||
HostTxdbuf[8] = (uint8_t)(CRC16Temp & 0xFF);
|
||
HostTxdbuf[9] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
uart_send(&huart6,HostTxdbuf,10);
|
||
}
|
||
|
||
/*******************************************************************************
|
||
函数名称 : WriteSingleRegFUNC
|
||
功 能 : 功能码:0x06 预设(写)单寄存器
|
||
参 数 : 无
|
||
返 回 值 : 无
|
||
*发送:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
|
||
*返回:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
|
||
*******************************************************************************/
|
||
void writesinglereg_host(uint8_t local_addr, uint16_t reg_addr, uint16_t reg_data)
|
||
{
|
||
uint16_t CRC16Temp;
|
||
|
||
HostTxdbuf[0] = local_addr;
|
||
|
||
HostTxdbuf[1] = 0x06;
|
||
|
||
HostTxdbuf[2] = (uint8_t)(reg_addr >> 8);
|
||
HostTxdbuf[3] = (uint8_t)(reg_addr & 0xFF);
|
||
|
||
HostTxdbuf[4] = (uint8_t)(reg_data >> 8);
|
||
HostTxdbuf[5] = (uint8_t)(reg_data & 0xFF);
|
||
|
||
CRC16Temp = ModbusCRC16(HostTxdbuf, 6);
|
||
HostTxdbuf[6] = (uint8_t)(CRC16Temp & 0xFF);
|
||
HostTxdbuf[7] = (uint8_t)(CRC16Temp >> 8);
|
||
|
||
uart_send(&huart6,HostTxdbuf,8);
|
||
}
|
||
|
||
void modbus_analysis_host(uint8_t * HostRxdbuf, uint16_t wRxdLen)
|
||
{
|
||
uint8_t uSlaveAdd, uCmdCode;
|
||
|
||
if((HostRxdbuf == NULL) || (wRxdLen < 2)) return;
|
||
|
||
uSlaveAdd = HostRxdbuf[0];
|
||
uCmdCode = HostRxdbuf[1];
|
||
|
||
// 从机地址为本机地址或者是广播帧
|
||
if(1)
|
||
{
|
||
switch(uCmdCode)
|
||
{
|
||
case ReadDisInputState:// 读离散输入状态
|
||
{
|
||
if((uSlaveAdd % 5) == 2)
|
||
{
|
||
DisState[((uSlaveAdd - 2) / 5) * 2] = HostRxdbuf[3];
|
||
}
|
||
else if((uSlaveAdd % 5) == 3)
|
||
{
|
||
DisState[((uSlaveAdd - 3) / 5) * 2 + 1] = HostRxdbuf[3];
|
||
}
|
||
}
|
||
break;
|
||
|
||
case ReadInputReg:// 读取输入寄存器
|
||
{
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 0] = MAKEWORD(HostRxdbuf[4], HostRxdbuf[3]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 1] = MAKEWORD(HostRxdbuf[6], HostRxdbuf[5]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 2] = MAKEWORD(HostRxdbuf[8], HostRxdbuf[7]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 3] = MAKEWORD(HostRxdbuf[10], HostRxdbuf[9]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 4] = MAKEWORD(HostRxdbuf[12], HostRxdbuf[11]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 5] = MAKEWORD(HostRxdbuf[14], HostRxdbuf[13]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 6] = MAKEWORD(HostRxdbuf[16], HostRxdbuf[15]);
|
||
InputReg[((uSlaveAdd / 5) - 1) * 8 + 7] = MAKEWORD(HostRxdbuf[18], HostRxdbuf[17]);
|
||
}
|
||
break;
|
||
|
||
case WriteSingleReg:// 写单个保持寄存器
|
||
{
|
||
|
||
}
|
||
break;
|
||
|
||
case WriteSingleCoil:// 写单个线圈
|
||
{
|
||
|
||
}
|
||
break;
|
||
|
||
default:// 错误码处理
|
||
{
|
||
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void modbus_process_host(void)
|
||
{
|
||
uint16_t wFrameCRC, wCalCRC;
|
||
|
||
if(uart6_rx_size < 2) return; // 数据长度不是有效值
|
||
|
||
// 获取接收数据帧中的校验和
|
||
wFrameCRC = MAKEWORD(uart6_rx_buf[uart6_rx_size - 2], uart6_rx_buf[uart6_rx_size - 1]);
|
||
// 计算接收到的数据的校验和
|
||
wCalCRC = ModbusCRC16(uart6_rx_buf, uart6_rx_size - 2);
|
||
if(wFrameCRC != wCalCRC) return;
|
||
|
||
modbus_analysis_host(uart6_rx_buf, uart6_rx_size);// 协议处理
|
||
}
|
||
|
||
|
||
|
||
|