#include "modbus.h" uint8_t Coil[1250]; ///<存放线圈的数组 uint8_t Register_H[10000]; ///<寄存器的高字节 uint8_t Register_L[10000]; ///<寄存器的低字节 uint8_t EXRegister_H[10000]; ///<0x10000开始寄存器的高字节 uint8_t EXRegister_L[10000]; ///<0x10000开始寄存器的低字节 uint8_t History[3][512]; /*存放历史的地方*/ uint8_t HistoryLongth[3]; /*历史数据大小的计数*/ uint8_t HistoryLocation; /*当前历史存放到了第几条*/ uint8_t SaveFlag = 0; uint8_t SentPocket[512]; uint8_t Writr_dat[1024]; /** * @brief 写单个线圈 * @param[in] addr 写入线圈的地址(第几个线圈) * @param[in] dat 给线圈写入的值 * @return 无 */ void WriteBit(uint16_t addr,uint8_t dat) { uint16_t temp; temp=addr%8; if(dat) { Coil[addr/8]|= (0x01 << temp); } else { Coil[addr/8]&=~(0x01 << temp); } } /** * @brief 读单个线圈 * @param[in] addr 读取线圈的地址(第几个线圈) * @param[in] *dat 线圈的值放在哪里 * @return 无 */ void ReadBit(uint16_t addr,uint8_t * dat) { uint16_t temp; temp=addr%8; if((Coil[addr/8])&(0x01 << temp)) { *dat=0x01; } else { *dat=0x00; } } /** * @brief Modbus数据的初始处理 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void ProcessModbusFrame(uint8_t buffer[], uint16_t longth) { uint8_t crc_8[2], cmdCode; uint16_t modbusCrc; modbusCrc = modbus_crc16(buffer, longth - 2); memcpy(crc_8, &modbusCrc, 2); cmdCode = buffer[1]; /* 如果通过了CRC校验 */ if (crc_8[0] == buffer[longth - 2] && crc_8[1] == buffer[longth - 1]) { switch (cmdCode) { case READ_COIL_CODE: ReadCoilProcess(buffer, longth) /* 读线圈 01 */ ;break; case WRUTE_MUL_COIL_CODE: WriteMulCoilProcess(buffer, longth) /* 写多线圈 0f */ ;break; case READ_REGUSTER_CODE: ReadRegisterProcess(buffer, longth) /* 读寄存器 03 */ ;break; case WRITE_COIL_CODE: WriteCoilProcess(buffer, longth) /* 写线圈 05 */ ;break; case WRITE_MUL_REGISTER_CODE: WriteMulRegisterProcess(buffer, longth) /* 写多寄存器 10 */ ;break; case GET_HISTORY_CODE: GetHistory(buffer, longth) /* 获取历史 55 */ ;break; case READ_ODD_REGUSTER_CODE: ReadOddRegisterProcess(buffer, longth) /* 获取奇数的寄存器 33 */ ;break; case READ_EXREGUSTER_CODE: ReadEXRegisterProcess(buffer, longth) /* 读0x10000处的寄存器 30*/ ;break; case WRITE_MUL_EXREGISTER_CODE: WriteEXRegisterProcess(buffer, longth) /* 写0x10000处的寄存器 31*/ ;break; default :ErrorBack(buffer, longth); /* 无效指令码 */ ;break; } } } /** * @brief 0x01指令码的执行,读取多线圈 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void ReadCoilProcess (uint8_t buffer[], uint16_t longth) { uint16_t startPoint, step, modbusCrc; /* 从哪里开始读取,读取了多少线圈 */ uint8_t sentCount, crc_8[2], temp_data, errCode = 0x00, SentData[400]; /* 要发送多少字节的数据。 crc_8是crc的校验值 temp_data用来存放读到的字节 */ startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装为16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装为16位 */ sentCount = step / 8; /* 计算要用多少字节发送 */ if (step % 8 != 0 ) sentCount++; /* 补全发送字节 */ memset(SentData, 0, 400); /* 如果是与本设备通信 */ if (buffer[0] == SLAVES_ADDRES) { /* 异常分析 */ if(longth != 8) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f + 1) errCode = 0x02; if(step == 0 || step > 0x07d0) errCode = 0x03; if(errCode == 0x00) { for (int i = 0; i < step; i++ )/* 循环到获取完整的字节 */ { ReadBit(startPoint + i, &temp_data); SentData[i/8] = SentData[i/8] | (temp_data << (i % 8)); } /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x01; SentPocket[2] = sentCount; for (int j = 0; j < sentCount; j++)/* 数据组装 */ { memcpy( &SentPocket[3 + j], &SentData[j], 1); } modbusCrc = modbus_crc16(SentPocket, 3 + sentCount);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3 + sentCount] = crc_8[0]; SentPocket[4 + sentCount] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5 + sentCount); SaveHistory(buffer, longth); } else { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x0f指令码的执行,写入多线圈 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void WriteMulCoilProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint,step, modbusCrc; /* 从哪里开始写入,写入的终点,写入了多少线圈 */ uint8_t crc_8[2],datCount, errCode = 0x00, sentCount; /* crc_8是crc的校验值,datCount,数据计数,有多少位的数据,Writr_dat存放要写入的数据 */ startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ datCount = buffer[6]; memset(Writr_dat, 0, 1024); sentCount = step / 8; /* 计算要用多少字节发送 */ if (step % 8 != 0 ) sentCount++; /* 补全发送字节 */ /*数据转移,将buffer内的数据存如写数组。*/ for (int i = 0; i < datCount; i++) { Writr_dat[i] = buffer[i + 7]; } /* 如果是与本设备通信 */ if((buffer[0] == SLAVES_ADDRES || buffer[0] == 0x00)) { /* 异常分析 */ if(buffer[6] + 9 != longth) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f) errCode = 0x02; if(step == 0 || step > 0x07b0 || sentCount != datCount) errCode = 0x03; if(errCode == 0x00) { for (int j = 0; j < step; j++) { if ((Writr_dat[j / 8]) & (0x01)<<(j % 8)) { WriteBit(startPoint + j, 0x01); } else { WriteBit(startPoint + j, 0x00); } } /* 如果不是广播,发送返回消息 */ if(buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x0f; SentPocket[2] = buffer[2]; SentPocket[3] = buffer[3]; SentPocket[4] = buffer[4]; SentPocket[5] = buffer[5]; modbusCrc = modbus_crc16(SentPocket, 6);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[6] = crc_8[0]; SentPocket[7] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,8); SaveHistory(buffer, longth); } } else if(errCode != 0x00 && buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x03指令码的执行,读出输出寄存器 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void ReadRegisterProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint,step, modbusCrc; /* 从哪里开始读取,读取多少寄存器 */ uint8_t crc_8[2], SentData[256], errCode = 0x00; startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ /* 如果是与本设备通信 */ if (buffer[0] == SLAVES_ADDRES) { if(longth != 8) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f + 1) errCode = 0x02; if(step == 0 || step > 0x007d) errCode = 0x03; if(errCode == 0x00) { for (int i = 0; i < step; i++) /* 将数据存取发出数据缓存 */ { SentData[i * 2] = Register_H[startPoint + i]; SentData[i * 2 +1 ] = Register_L[startPoint + i]; } /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x03; SentPocket[2] = buffer[5] * 2; for (int j = 0; j < buffer[5] * 2; j++)/* 数据组装 */ { SentPocket[3+j] = SentData[j]; } modbusCrc = modbus_crc16(SentPocket, (buffer[5] * 2)+ 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[(buffer[5] * 2)+ 3] = crc_8[0]; SentPocket[(buffer[5] * 2)+ 4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,(buffer[5] * 2)+ 5 ); SaveHistory(buffer, longth); } else { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x30指令码的执行,读出额外输出寄存器 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void ReadEXRegisterProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint,step, modbusCrc; /* 从哪里开始读取,读取多少寄存器 */ uint8_t crc_8[2], SentData[256], errCode = 0x00; startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ /* 如果是与本设备通信 */ if (buffer[0] == SLAVES_ADDRES) { if(longth != 8) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f + 1) errCode = 0x02; if(step == 0 || step > 0x007d) errCode = 0x03; if(errCode == 0x00) { for (int i = 0; i < step; i++) /* 将数据存取发出数据缓存 */ { SentData[i * 2] = EXRegister_H[startPoint + i]; SentData[i * 2 +1 ] = EXRegister_L[startPoint + i]; } /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x30; SentPocket[2] = buffer[5] * 2; for (int j = 0; j < buffer[5] * 2; j++)/* 数据组装 */ { SentPocket[3+j] = SentData[j]; } modbusCrc = modbus_crc16(SentPocket, (buffer[5] * 2)+ 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[(buffer[5] * 2)+ 3] = crc_8[0]; SentPocket[(buffer[5] * 2)+ 4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,(buffer[5] * 2)+ 5 ); SaveHistory(buffer, longth); } else { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x33指令码的执行,读取奇数位寄存器 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void ReadOddRegisterProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint,step, modbusCrc; /* 从哪里开始读取,读取多少寄存器 */ uint8_t crc_8[2], SentData[256], errCode = 0x00; startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ /* 如果是与本设备通信 */ if (buffer[0] == SLAVES_ADDRES) { if(longth != 8) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f + 1 || startPoint % 2 == 0) errCode = 0x02; if(step == 0 || step > 0x007d) errCode = 0x03; if(errCode == 0x00) { for (int i = 0; i < step * 2; i+= 2) /* 将数据存取发出数据缓存 */ { SentData[i] = Register_H[startPoint + i]; SentData[i + 1] = Register_L[startPoint + i]; } /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x33; SentPocket[2] = step * 2; for (int j = 0; j < step * 2; j++)/* 数据组装 */ { SentPocket[3+j] = SentData[j]; } modbusCrc = modbus_crc16(SentPocket, step * 2 + 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[(buffer[5] * 2)+ 3] = crc_8[0]; SentPocket[(buffer[5] * 2)+ 4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,(step * 2)+ 5 ); SaveHistory(buffer, longth); } else { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x10指令码的执行,写入多寄存器 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void WriteMulRegisterProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint, step, modbusCrc; /* 从哪里开始写入,写入多少寄存器 */ uint8_t crc_8[2], datCount, errCode = 0x00; /* crc校验;数据计数 */ startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ datCount = buffer[6] / 2; /* 如果是与本设备通信 */ if ((buffer[0] == SLAVES_ADDRES || buffer[0] == 0x00)) { if(buffer[6] + 9 != longth) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f + 1) errCode = 0x02; if(step == 0x00 || step > 0x07b || step * 2 != buffer[6] ) errCode = 0x03; if(errCode == 0x00) { for (int i = 0; i < datCount; i++) /* 数据写入 */ { Register_H[startPoint + i] = buffer[(i * 2)+ 7]; Register_L[startPoint + i] = buffer[(i * 2)+ 8]; } /* 如果不是广播,发送返回消息 */ if(buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x10; SentPocket[2] = buffer[2]; SentPocket[3] = buffer[3]; SentPocket[4] = buffer[4]; SentPocket[5] = buffer[5]; modbusCrc = modbus_crc16(SentPocket, 6);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[6] = crc_8[0]; SentPocket[7] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,8); SaveHistory(buffer, longth); } } else if(errCode != 0x00 && buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x31指令码的执行,写入额外多寄存器 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void WriteEXRegisterProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint, step, modbusCrc; /* 从哪里开始写入,写入多少寄存器 */ uint8_t crc_8[2], datCount, errCode = 0x00; /* crc校验;数据计数 */ startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ step = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ datCount = buffer[6] / 2; /* 如果是与本设备通信 */ if ((buffer[0] == SLAVES_ADDRES || buffer[0] == 0x00)) { if(buffer[6] + 9 != longth) errCode = 0x04; if(startPoint > 0x270f || startPoint + step > 0x270f + 1) errCode = 0x02; if(step == 0x00 || step > 0x07b || step * 2 != buffer[6] ) errCode = 0x03; if(errCode == 0x00) { for (int i = 0; i < datCount; i++) /* 数据写入 */ { EXRegister_H[startPoint + i] = buffer[(i * 2)+ 7]; EXRegister_L[startPoint + i] = buffer[(i * 2)+ 8]; } /* 如果不是广播,发送返回消息 */ if(buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = 0x31; SentPocket[2] = buffer[2]; SentPocket[3] = buffer[3]; SentPocket[4] = buffer[4]; SentPocket[5] = buffer[5]; modbusCrc = modbus_crc16(SentPocket, 6);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[6] = crc_8[0]; SentPocket[7] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,8); SaveHistory(buffer, longth); } } else if(errCode != 0x00 && buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = errCode; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } } /** * @brief 0x05指令码的执行,写入单线圈 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void WriteCoilProcess(uint8_t buffer[], uint16_t longth) { uint16_t startPoint, State; /* 从哪里开始写入,写入多少寄存器 */ startPoint = (buffer[2] << 8 )| buffer[3]; /* 将8位数据组装位16位 */ State = (buffer[4] << 8) | buffer[5]; /* 将8位数据组装位16位 */ if ((buffer[0] == SLAVES_ADDRES || buffer[0] == 0x00))/* 如果是与本设备通信 */ { if(State == 0xff00) { Coil[startPoint/8]|= (0x01 << (startPoint % 8) ); } if(State == 0x0000) { Coil[startPoint/8]&=~(0x01 << (startPoint % 8) ); } /* 如果不是广播,发送返回消息 */ if(buffer[0] == SLAVES_ADDRES) { HAL_UART_Transmit_DMA(&huart1, buffer, longth); } } } /** * @brief 指令码错误的返回报文 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void ErrorBack(uint8_t buffer[], uint16_t longth) { uint16_t modbusCrc; uint8_t crc_8[2]; /* 如果是与本设备通信 */ if (buffer[0] == SLAVES_ADDRES) { /* 准备发送应答 */ SentPocket[0] = 0x01; SentPocket[1] = buffer[1] + 0x80; SentPocket[2] = 0x01; modbusCrc = modbus_crc16(SentPocket, 3);/* 计算CRC */ memcpy(crc_8, &modbusCrc, 2); SentPocket[3] = crc_8[0]; SentPocket[4] = crc_8[1]; HAL_UART_Transmit_DMA(&huart1,SentPocket,5); } } /** * @brief 历史保存 * @param[in] buffer[] 保存的数据 * @param[in] longth 数据的长度 * @return 无 */ void SaveHistory(uint8_t buffer[], uint16_t longth) { memcpy(History[HistoryLocation], buffer, longth); HistoryLongth[HistoryLocation] = longth; HistoryLocation++; if(HistoryLocation == 3) { HistoryLocation = 0; } } /** * @brief 历史读取 * @return 无 */ void LoadHistory(void) { uint8_t temp; temp = HistoryLocation; for(int i = 0; i < 3; i++) { if(temp == 3) { temp = 0; } HAL_UART_Transmit(&huart1, History[temp], HistoryLongth[temp], 0xffff); temp++; } } /** * @brief 0x55指令码的执行,输出历史 * @param[in] buffer[] 预处理的数据 * @param[in] longth 数据的长度 * @return 无 */ void GetHistory(uint8_t buffer[], uint16_t longth) { /* 如果是与本设备通信 */ if (buffer[0] == SLAVES_ADDRES) { LoadHistory(); } } /** * @brief 读取并还原sram数据。 * @return 无 */ void ModbusLoadSRAM(void) { uint32_t temp[5]; Read_Backup_SRAM(temp,5); memcpy(SramData, temp, 20); for(int i = 0; i < 10; i++) { Register_H[i] = SramData[i * 2]; Register_L[i] = SramData[i * 2 + 1]; } } /** * @brief 存入sram数据。 * @return 无 */ void ModbusSaveSRAM(void) { uint32_t temp[5]; for (int i = 0; i < 10; i++) { SramData[i * 2] = Register_H[i]; SramData[i * 2 + 1] = Register_L[i]; } memcpy(temp, SramData, 20); Write_Backup_SRAM(temp, 5); }