#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);// 协议处理 }