#include "modbus_m.h" #ifdef MODBUS_M #include "inout.h" #include "delay.h" #include "trigger.h" #ifndef MODBUS_M_NUM #define MODBUS_M_NUM 1 #endif //----------------------------------------------------------------- // 控制结构 ModbusCtrl g_modBusMCtrl[MODBUS_M_NUM]; //----------------------------------------------------------------- /*----------------------------------------------------------------- 功能:初始化 Modbus 主设备串口 midx : 主站序号 baud : 波特率 dat: 数据长度 parity: 校验位 stop: 停止位 mode: 数据模式 */ void InitModbus_m(int midx, int usart, BAUD_TypeDef baud, char dat, char parity, char stop, char mode) { if (midx < 0 || midx >= MODBUS_M_NUM) { printf("init modbus_m, idx error\r\n"); return; } memset(&g_modBusMCtrl[midx], 0, sizeof(ModbusCtrl)); if (mode == 'A' || mode == 'a') { g_modBusMCtrl[midx].modBusMode = 1; } else { g_modBusMCtrl[midx].modBusMode = 0; } // 延时 switch(baud) { // 数据位 + 1个起始位 + 奇偶校验位(无校验则没有) + 停止位 // 根据波特率来计算 通讯延时, 单位us = 10000000 / baud(按照一个字节10位计算, 8 N 1) case B4800: { g_modBusMCtrl[midx].modBusWait = 2200; break; } case B9600: { g_modBusMCtrl[midx].modBusWait = 1100; break; } case B14400: { g_modBusMCtrl[midx].modBusWait = 750; break; } case B19200: { g_modBusMCtrl[midx].modBusWait = 600; break; } case B38400: { g_modBusMCtrl[midx].modBusWait = 300; break; } case B57600: { g_modBusMCtrl[midx].modBusWait = 200; break; } case B115200: { g_modBusMCtrl[midx].modBusWait = 100; break; } case B230400: { g_modBusMCtrl[midx].modBusWait = 50; break; } case B460800: { g_modBusMCtrl[midx].modBusWait = 25; break; } case B921600: { g_modBusMCtrl[midx].modBusWait = 13; break; } default: { g_modBusMCtrl[midx].modBusWait = 0; } } if ((dat == '8') && (parity != 'N') && (parity != 'n')) // 7位数据过滤校验位 { g_modBusMCtrl[midx].filterChk = 1; } else { g_modBusMCtrl[midx].filterChk = 0; } #ifndef USART1_485OutEn #define USART1_485OutEn DefOutEn #endif #ifndef USART1_485OutDis #define USART1_485OutDis DefOutDis #endif #ifndef USART2_485OutEn #define USART2_485OutEn DefOutEn #endif #ifndef USART2_485OutDis #define USART2_485OutDis DefOutDis #endif #ifndef USART3_485OutEn #define USART3_485OutEn DefOutEn #endif #ifndef USART3_485OutDis #define USART3_485OutDis DefOutDis #endif #ifndef USART4_485OutEn #define USART4_485OutEn DefOutEn #endif #ifndef USART4_485OutDis #define USART4_485OutDis DefOutDis #endif #ifndef USART5_485OutEn #define USART5_485OutEn DefOutEn #endif #ifndef USART5_485OutDis #define USART5_485OutDis DefOutDis #endif #ifndef USART6_485OutEn #define USART6_485OutEn DefOutEn #endif #ifndef USART6_485OutDis #define USART6_485OutDis DefOutDis #endif // 初始化串口 switch(usart) { #ifdef COMM_USART1 case COMM_USART1: { InitUsart1(baud, dat, parity, stop); // 串口1 RegisterModbusCommFunc(&g_modBusMCtrl[midx], Usart1SendData, Usart1GetData, Usart1CleanRsBuf, IsUsart1SendOver, USART1_485OutEn, USART1_485OutDis); break; } #endif #ifdef COMM_USART2 case COMM_USART2: { InitUsart2(baud, dat, parity, stop); // 串口2 RegisterModbusCommFunc(&g_modBusMCtrl[midx], Usart2SendData, Usart2GetData, Usart2CleanRsBuf, IsUsart2SendOver, USART2_485OutEn, USART2_485OutDis); break; } #endif #ifdef COMM_USART3 case COMM_USART3: { InitUsart3(baud, dat, parity, stop); // 串口3 RegisterModbusCommFunc(&g_modBusMCtrl[midx], Usart3SendData, Usart3GetData, Usart3CleanRsBuf, IsUsart3SendOver, USART3_485OutEn, USART3_485OutDis); break; } #endif #ifdef COMM_USART4 case COMM_USART4: { InitUsart4(baud, dat, parity, stop); // 串口4 RegisterModbusCommFunc(&g_modBusMCtrl[midx], Usart4SendData, Usart4GetData, Usart4CleanRsBuf, IsUsart4SendOver, USART4_485OutEn, USART4_485OutDis); break; } #endif #ifdef COMM_USART5 case COMM_USART5: { InitUsart5(baud, dat, parity, stop); // 串口5 RegisterModbusCommFunc(&g_modBusMCtrl[midx], Usart5SendData, Usart5GetData, Usart5CleanRsBuf, IsUsart5SendOver, USART5_485OutEn, USART5_485OutDis); break; } #endif #ifdef COMM_USART6 case COMM_USART6: { InitUsart6(baud, dat, parity, stop); // 串口6 RegisterModbusCommFunc(&g_modBusMCtrl[midx], Usart6SendData, Usart6GetData, Usart6CleanRsBuf, IsUsart6SendOver, USART6_485OutEn, USART6_485OutDis); break; } #endif default: { RegisterModbusCommFunc(&g_modBusMCtrl[midx], DefSendData, DefGetData, DefCleanRsBuf, DefIsSendOver, DefOutEn, DefOutDis); break; } } g_modBusMCtrl[midx].CommOutDis(); // 关闭发送 } //----------------------------------------------------------------- // 功能:发送一条MODBUS协议的命令 // 参数: // midx: 主站序号 // index: 站号: 1~247(十进制) // cmd: 命令码: 03H (读操作) // 06H (写操作) // 10H (写操作) // addr: 数据起始地址: 0000H~FFFFH // pData: 数据内容: 单位:字(读操作时内容为读取个数,写操作时为写入内容) // len: 数据长度,单位字,读操作时固定为1,写操作时为写入长度 // steps, 发送步骤 // 返回值: 0:发送正常 // -1: 参数错误 // -2: 发送超时 // 可以分4个步骤(1--4)发送, 如果步骤执行正确,返回步骤号码; // steps == -1, 非分步调用(同步调用) /* * 步骤1:打开发送允许 * 步骤2:数据发送 * 步骤3:等待发送完成 * 步骤4:关闭发送 */ int ModbusTx(int midx, u8 index, u8 cmd, u16 addr, u16 * pData, u16 len, int steps) { int i, j, timeout, result; u8 checksum, temp; // 和校验(ASCII) u16 checkcrc; // CRC 校验(RTU) u16 data; u8 pSDat[MDBSRXLEN_MAX]; // 待发送数据 if ((cmd != MODBUS_RD) && (cmd != MODBUS_WR) && (cmd != MODBUS_WR_MULTI)) { result = -1; return result; } if (pData == NULL || len == 0) { result = -1; return result; } if (midx < 0 || midx >= MODBUS_M_NUM) { result = -1; return result; } if (steps == 1 || steps == -1) { g_modBusMCtrl[midx].CommOutEn(); // 打开发送 if (steps == -1) { DelayUs(100); } } if (steps == 2 || steps == -1) { i = 0; result = 0; if (g_modBusMCtrl[midx].modBusMode != 0) // ASCII码模式 { checksum = 0; pSDat[i++] = ':'; //':' temp = HIHFBYTE(index); pSDat[i++] = RtuToAscii(temp); // IDX_H temp = LOHFBYTE(index); pSDat[i++] = RtuToAscii(temp); // IDX_L checksum += index; temp = HIHFBYTE(cmd); pSDat[i++] = RtuToAscii(temp); // CMD_H temp = LOHFBYTE(cmd); pSDat[i++] = RtuToAscii(temp); // CMD_L checksum += cmd; temp = HIHFBYTE(HIBYTE(addr)); pSDat[i++] = RtuToAscii(temp); // ADDR_HH temp = LOHFBYTE(HIBYTE(addr)); pSDat[i++] = RtuToAscii(temp); // ADDR_HL checksum += HIBYTE(addr); temp = HIHFBYTE(LOBYTE(addr)); pSDat[i++] = RtuToAscii(temp); // ADDR_LH temp = LOHFBYTE(LOBYTE(addr)); pSDat[i++] = RtuToAscii(temp); // ADDR_LL checksum += LOBYTE(addr); if (cmd == MODBUS_WR_MULTI) {//多字 发送 // 数据个数,单位字 temp = HIHFBYTE(HIBYTE(len)); pSDat[i++] = RtuToAscii(temp); // LEN_HH temp = LOHFBYTE(HIBYTE(len)); pSDat[i++] = RtuToAscii(temp); // LEN_HL checksum += HIBYTE(len); temp = HIHFBYTE(LOBYTE(len)); pSDat[i++] = RtuToAscii(temp); // LEN_LH temp = LOHFBYTE(LOBYTE(len)); pSDat[i++] = RtuToAscii(temp); // LEN_LL checksum += LOBYTE(len); // 数据区字节数 temp = HIHFBYTE(LOBYTE(len)<<1); pSDat[i++] = RtuToAscii(temp); // LEN_H temp = LOHFBYTE(LOBYTE(len)<<1); pSDat[i++] = RtuToAscii(temp); // LEN_L checksum += LOBYTE(len<<1); } for (j = 0; j < len; j++) { data = pData[j]; temp = HIHFBYTE(HIBYTE(data)); pSDat[i++] = RtuToAscii(temp); // DATA_HH temp = LOHFBYTE(HIBYTE(data)); pSDat[i++] = RtuToAscii(temp); // DATA_HL checksum += HIBYTE(data); temp = HIHFBYTE(LOBYTE(data)); pSDat[i++] = RtuToAscii(temp); // DATA_LH temp = LOHFBYTE(LOBYTE(data)); pSDat[i++] = RtuToAscii(temp); // DATA_LL checksum += LOBYTE(data); } checksum = ~checksum + 1; pSDat[i++] = RtuToAscii(HIHFBYTE(checksum)); // LRC_H pSDat[i++] = RtuToAscii(LOHFBYTE(checksum)); // LRC_L pSDat[i++] = '\r'; // CR pSDat[i++] = '\n'; // LF } else // RTU模式 { pSDat[i++] = index; // IDX pSDat[i++] = cmd; // CMD pSDat[i++] = HIBYTE(addr); // ADDR_H pSDat[i++] = LOBYTE(addr); // ADDR_L if (cmd == MODBUS_WR_MULTI) {//多字 发送 // 数据个数,单位字 pSDat[i++] = HIBYTE(len); // LEN_H pSDat[i++] = LOBYTE(len); // LEN_L // 数据区字节数 pSDat[i++] = LOBYTE(len)<<1; // LEN_L * 2 } for (j = 0; j < len; j++) { data = pData[j]; pSDat[i++] = HIBYTE(data); // DATA_H pSDat[i++] = LOBYTE(data); // DATA_L } checkcrc = ModbusCrc16(&pSDat[0], i); pSDat[i++] = HIBYTE(checkcrc); // CRC_H pSDat[i++] = LOBYTE(checkcrc); // CRC_L } g_modBusMCtrl[midx].ModBusCommSend(pSDat, i); } if (steps == 3) { if (g_modBusMCtrl[midx].IsModBusCommSendOver() != TRUE) { return 0; } } else if (steps == -1) // 同步发送 { timeout = (i*2 + 4) * g_modBusMCtrl[midx].modBusWait; // 超时时间,单位us((字节数*2 + 4) * 每个字节发送时长) do //等待发送完成 { if (g_modBusMCtrl[midx].IsModBusCommSendOver() == TRUE) { break; } DelayUs(1); if (timeout-- <= 0) { result = -2; break; } }while(1); DelayUs(g_modBusMCtrl[midx].modBusWait); // 等待最后一个字节发送完成 } if (steps == 4 || steps == -1) { g_modBusMCtrl[midx].ModBusCommCleanRsBuf(); // 清空已接收的数据 g_modBusMCtrl[midx].CommOutDis(); // 关闭发送 } if (steps != -1) { return steps; } return result; } //----------------------------------------------------------------- // 功能:接收一条MODBUS协议的应答 // 参数: // midx: 主站序号 // index: 本条应该接收的站号: 1~247(十进制) // cmd: 本条应该接收的命令码: 03H (读操作) // 06H (写操作) // 10H (写操作) // addr: 本条应该接收的数据起始地址: 0000H~FFFFH // *pData: 接收数据内容: 单位:字 // len: 本条应该接收的数据长度: 单位:字 // steps: 接收步骤 // 返回值: >0: 接收正常,返回值为接收到的数据长度 // -1: 参数错误 // -2: 接收超时 // -3: 接收错误 // -4:串口接收错误 // 可以分步骤接收 // steps == -1, 同步调用,直到收到数据或超时 // steps == 1, 异步调用标志,正确得到数据结果为长度 len, 0为没有数据,其他为错误 int ModbusRx(int midx, u8 index, u8 cmd, u16 addr, u16 * pData, u16 len, int steps) { int i, j, result, exlen, timeout; u8 pRDat[MDBSRXLEN_MAX]; // 待接收数据缓冲区 u16 checkcrc; // crc校验(RTU) u8 checksum; // 和校验(ASCII) u8 temp_h, temp_l, tempH, tempL; // if ((cmd != MODBUS_RD) && (cmd != MODBUS_WR) && (cmd != MODBUS_WR_MULTI)) { return -1; //参数错误 } if ((len > MODBUS_LENMAX) || (len == 0)) { return -1; //参数错误 } if (midx < 0 || midx >= MODBUS_M_NUM) { result = -1; return result; } if (g_modBusMCtrl[midx].modBusMode != 0) // ASCII码模式 { if (cmd == MODBUS_RD) // 读数据 { exlen = len * 4 + 11; //包长度 } else if (cmd == MODBUS_WR) // 写数据 { exlen = 17; //包长度 } else if (cmd == MODBUS_WR_MULTI) // 写多个字数据 { exlen = 17; //包长度 } else { exlen = 17; //包长度 } exlen -= 1; // 减去起始符 : } else // RTU 模式 { if (cmd == MODBUS_RD) // 读数据 { exlen = len * 2 + 5; //包长度 } else if (cmd == MODBUS_WR) // 写数据 { exlen = 8; //包长度 } else if (cmd == MODBUS_WR_MULTI) // 写多个字数据 { exlen = 8; //包长度 } else { exlen = 8; //包长度 } } if (steps == 1 || steps == -1) { memset(pRDat, 0, MDBSRXLEN_MAX); if (g_modBusMCtrl[midx].modBusMode != 0) // ASCII码模式 { timeout = exlen*2 + 400; // 超时时间 do { result = g_modBusMCtrl[midx].ModBusCommReceive(pRDat, 1); // 从缓冲区读取数据 if (result == 1) { if (pRDat[0] == ':') // 找到开始标志 { result = 0; break; } else { if (steps == 1) { result = 1; // 异步调用,返回执行步骤 break; } } } if (steps == -1) { DelayUs(g_modBusMCtrl[midx].modBusWait); if (timeout-- <= 0) { printf("1. call ModbusRx timeout\r\n"); result = -2; //接收超时 break; } } }while(1); if (result != 0) { return result; } } } if (steps != -1 && g_modBusMCtrl[midx].modBusMode == 0) // RTU 码模式 { steps = 2; } if (steps == 2 || steps == -1) { timeout = exlen*2 + 400; // 超时时间 do { result = g_modBusMCtrl[midx].ModBusCommReceive(pRDat, exlen); // 从缓冲区读取数据 if (result >= exlen) { if (g_modBusMCtrl[midx].modBusMode != 0) // ASCII码模式 { if (g_modBusMCtrl[midx].filterChk != 0) // 7位数据过滤校验位 { for (i = 0; i < result; i++) { pRDat[i] &= 0x7F; } } // 处理数据包 result = 0; i = 0; checksum = 0; if (pRDat[i] != RtuToAscii(HIHFBYTE(index))) // INDEX_H { result = -3; // 接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(index))) // INDEX_L { result = -3; // 接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); if (pRDat[i] != RtuToAscii(HIHFBYTE(cmd))) // CMD_H { result = -3; // 接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(cmd))) // CMD_L { result = -3; // 接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); if (cmd == MODBUS_RD) // 读数据 { if (pRDat[i] != RtuToAscii(HIHFBYTE(LOBYTE(len) << 1))) // LEN_H { result = -3; // 接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(LOBYTE(len) << 1))) // LEN_L { result = -3; // 接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); } else if (cmd == MODBUS_WR) // 写数据 { if (pRDat[i] != RtuToAscii(HIHFBYTE(HIBYTE(addr)))) // ADDR_HH { result = -3; //接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(HIBYTE(addr)))) // ADDR_HL { result = -3; //接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); if (pRDat[i] != RtuToAscii(HIHFBYTE(LOBYTE(addr)))) // ADDR_LH { result = -3; //接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(LOBYTE(addr)))) // ADDR_LL { result = -3; //接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); } else if (cmd == MODBUS_WR_MULTI) // 写多个字数据 { if (pRDat[i] != RtuToAscii(HIHFBYTE(HIBYTE(addr)))) // ADDR_HH { result = -3; //接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(HIBYTE(addr)))) // ADDR_HL { result = -3; //接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); if (pRDat[i] != RtuToAscii(HIHFBYTE(LOBYTE(addr)))) // ADDR_LH { result = -3; //接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(LOBYTE(addr)))) // ADDR_LL { result = -3; //接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); if (pRDat[i] != RtuToAscii(HIHFBYTE(HIBYTE(len)))) // LEN_HH { result = -3; //接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(HIBYTE(len)))) // LEN_HL { result = -3; //接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); if (pRDat[i] != RtuToAscii(HIHFBYTE(LOBYTE(len)))) // LEN_LH { result = -3; //接收错误 break; } temp_h = AsciiToRtu(pRDat[i++]); if (pRDat[i] != RtuToAscii(LOHFBYTE(LOBYTE(len)))) // LEN_LL { result = -3; //接收错误 break; } temp_l = AsciiToRtu(pRDat[i++]); checksum += MAKEBYTE(temp_l,temp_h); } if (cmd == MODBUS_RD || // 读数据 cmd == MODBUS_WR || // 写数据 0) { for (j = 0; j < len; j++) { temp_h = AsciiToRtu(pRDat[i++]); temp_l = AsciiToRtu(pRDat[i++]); tempH = MAKEBYTE(temp_l, temp_h); checksum += tempH; temp_h = AsciiToRtu(pRDat[i++]); temp_l = AsciiToRtu(pRDat[i++]); tempL = MAKEBYTE(temp_l, temp_h); checksum += tempL; pData[j] = MAKEWORD(tempL, tempH); } } checksum = ~checksum + 1; if (pRDat[i++] != RtuToAscii(HIHFBYTE(checksum))) // LRC_H { result = -3; //接收错误 break; } if (pRDat[i++] != RtuToAscii(LOHFBYTE(checksum))) // LRC_L { result = -3; //接收错误 break; } if (pRDat[i++] != '\r') // CR { // result = -3; //接收错误 break; } if (pRDat[i++] != '\n') // LF { //result = -3; //接收错误 break; } if (result == 0) { result = len; } break; } else // RTU 模式 { // 处理数据包 result = 0; i = 0; if (pRDat[i++] != index) // 从站地址 { result = -3; // 接收错误 break; } if (pRDat[i++] != cmd) { result = -3; // 接收错误 break; } if (cmd == MODBUS_RD) // 读数据 { if (pRDat[i++] != (LOBYTE(len) << 1)) // LEN { result = -3; // 接收错误 break; } } else if (cmd == MODBUS_WR) // 写数据 { if (pRDat[i++] != HIBYTE(addr)) // ADDR_H { result = -3; // 接收错误 break; } if (pRDat[i++] != LOBYTE(addr)) // ADDR_L { result = -3; // 接收错误 break; } } else if (cmd == MODBUS_WR_MULTI) // 写多个字数据 { if (pRDat[i++] != HIBYTE(addr)) // ADDR_H { result = -3; // 接收错误 break; } if (pRDat[i++] != LOBYTE(addr)) // ADDR_L { result = -3; // 接收错误 break; } if (pRDat[i++] != HIBYTE(len)) // LEN_H { result = -3; // 接收错误 break; } if (pRDat[i++] != LOBYTE(len)) // LEN_L { result = -3; // 接收错误 break; } } if (cmd == MODBUS_RD || // 读数据 cmd == MODBUS_WR || // 写数据 0) { for (j = 0; j < len; j++) { pData[j] = MAKEWORD(pRDat[i+1], pRDat[i]); i += 2; } } checkcrc = ModbusCrc16(&pRDat[0], i); if (pRDat[i++] != HIBYTE(checkcrc)) // LRC_H { result = -3; // 接收错误 break; } if (pRDat[i++] != LOBYTE(checkcrc)) // LRC_L { result = -3; // 接收错误 break; } if (result == 0) { result = len; } break; } } else if (result < 0) { if (result == -1) // 输入参数错误 { printf("para error\r\n"); } else if (result == -2) // 串口没有初始化 { printf("usart is not inited\r\n"); } else if (result == -3) // 接收缓冲区控制错误 { printf("usart receive buf ctrl error\r\n"); } else { } result = -4; break; } else if (result > 0) { printf("receive data len error\r\n"); result = -3; break; } else // result == 0 { } if (steps == -1) { // 等待接收完成 DelayUs(g_modBusMCtrl[midx].modBusWait); if (timeout-- <= 0) { printf("2. call ModbusRx timeout, index=%d\r\n", index); result = -2; //接收超时 break; } } else { result = 0; break; } }while(1); } if (result == -3) // 接收错误 { printf("Rx data error, index=%d\r\n", index); } return result; } //----------------------------------------------------------------- // 功能:发送一条MODBUS协议的命令,并等待回包 // 参数: // index: 站号: 1~247(十进制) // cmd: 命令码: 03H (读操作) // 06H (写操作) // addr: 数据起始地址: 0000H~FFFFH // pWrDat: 写入数据 // wLen: 写入长度 单位:字 // pRdBuf: 回包数据指针: // rLen: 读取(回包)数据长度: 单位:字 // 返回值: >=0:接收正常(无回包,则返回0;有回包,则返回数据长度) // -1: 参数错误 // -2: 接收超时 // -3: 接收错误 int ModbusComm(int midx, u8 index, u8 cmd, u16 addr, u16 * pWrDat, u16 wLen, u16 * pRdBuf, u16 rLen) { int result; u16 rdatabuf[MDBSRXLEN_MAX]; if (cmd != MODBUS_RD) // 20231027 { if (pWrDat == NULL || wLen == 0) { return -1; } } if (cmd == MODBUS_RD) { result = ModbusTx(midx, index, cmd, addr, &rLen, 1, -1); } else { result = ModbusTx(midx, index, cmd, addr, pWrDat, wLen, -1); } if (result == 0) { // 等待回包 if (index != 0 && ((index & 0x80) == 0 || cmd == MODBUS_RD) && 1) { if (pRdBuf == NULL) { result = ModbusRx(midx, index, cmd, addr, rdatabuf, rLen, -1); } else { result = ModbusRx(midx, index, cmd, addr, pRdBuf, rLen, -1); } } } return result; } //----------------------------------------------------------------- // 功能:16位数据读写 int ModbusComm16(int midx, u8 index, u8 cmd, u16 addr, u16 wrDat, u16 * pData) { int i,rst; for (i = 0; i < 3; i++) { rst = ModbusComm(midx, index, cmd, addr, &wrDat, 1, pData, 1); DelayMs(1); if (rst >= 0) { break; } } return rst; } //----------------------------------------------------------------- // 功能:32位数据读写 int ModbusComm32(int midx, u8 index, u8 cmd, u16 addr, u32 wrDat, u32 * pData) { int i,rst; if (cmd == MODBUS_WR) {//多字写入命令转换 cmd = MODBUS_WR_MULTI; } for (i = 0; i < 3; i++) { rst = ModbusComm(midx, index, cmd, addr, (u16*)(&wrDat), 2, (u16*)pData, 2); DelayMs(1); if (rst >= 0) { break; } } return rst; } int ModbusCommMulti(int midx, u8 index, u8 cmd, u16 addr, u16 * pWrDat, u8 wlen, u16 * pRdDat, u8 rlen) { int i,rst; if (cmd == MODBUS_WR) {//多字写入命令转换 cmd = MODBUS_WR_MULTI; } for (i = 0; i < 3; i++) { rst = ModbusComm(midx, index, cmd, addr, pWrDat, wlen, pRdDat, rlen); DelayMs(1); if (rst >= 0) { break; } } return rst; } //----------------------------------------------------------------- Rs485Ctrl g_rs485Ctrl; void InitRs485Ctrl(int rsvtimout) { memset(&g_rs485Ctrl, 0, sizeof(Rs485Ctrl)); // 读取超时时间 if (rsvtimout < 50) { g_rs485Ctrl.modrsvTimout = 50; } else if (rsvtimout > 500) { g_rs485Ctrl.modrsvTimout = 500; } else { g_rs485Ctrl.modrsvTimout = rsvtimout; } } void RegRsCmdProc(Resv485ExProc proc) { g_rs485Ctrl.resv485exproc = proc; } int AddRs485Cmd(Rs485Cmd * pCmd) { Rs485Ctrl * p485Ctrl = &g_rs485Ctrl; if (p485Ctrl != NULL && pCmd != NULL) { if (p485Ctrl->bufCmdNum < MAX_485CMD && p485Ctrl->bufTail < MAX_485CMD) { memcpy(&(p485Ctrl->cmdbuf[p485Ctrl->bufTail]), pCmd, sizeof(Rs485Cmd)); p485Ctrl->bufTail++; if (p485Ctrl->bufTail >= MAX_485CMD) { p485Ctrl->bufTail = 0; } p485Ctrl->bufCmdNum++; return p485Ctrl->bufCmdNum; } return -2; } return -1; } int GetRs485CmdBufLen(void) { return g_rs485Ctrl.bufCmdNum; } int Rs485Task(void) { // 分步骤执行 int rslt; u32 curIime; Rs485Cmd *pCmd; Rs485Ctrl * p485Ctrl = &g_rs485Ctrl; if (p485Ctrl == NULL) { return -1; } pCmd = &(p485Ctrl->cmdbuf[p485Ctrl->bufHead]); // 读取当前时间 curIime = GetUsSoftTimer(); if ((curIime - p485Ctrl->stepTime) > g_modBusMCtrl[pCmd->midx].modBusWait) { p485Ctrl->stepTime = curIime; if (p485Ctrl->working == 0 && p485Ctrl->bufCmdNum > 0 && p485Ctrl->steps == 0) { p485Ctrl->working = 1; p485Ctrl->steps = 1; } if (p485Ctrl->working == 0) { p485Ctrl->steps = 0; return 0; } if (p485Ctrl->steps > 0 && p485Ctrl->steps < 5) { if (pCmd->cmd == MODBUS_RD) { rslt = ModbusTx(pCmd->midx, pCmd->index, pCmd->cmd, pCmd->addr, &(pCmd->rlen), 1, p485Ctrl->steps); } else { rslt = ModbusTx(pCmd->midx, pCmd->index, pCmd->cmd, pCmd->addr, pCmd->wrdat, pCmd->wlen, p485Ctrl->steps); } if (rslt == p485Ctrl->steps) { p485Ctrl->steps++; } } else if (p485Ctrl->steps >= 5 && p485Ctrl->steps < p485Ctrl->modrsvTimout) { // 等待回包 if (pCmd->index != 0 && ((pCmd->index & 0x80) == 0 || pCmd->cmd == MODBUS_RD) && 1) { if (pCmd->cmd == MODBUS_RD) { rslt = ModbusRx(pCmd->midx, pCmd->index, pCmd->cmd, pCmd->addr, pCmd->rddat, pCmd->rlen, 1); } else { rslt = ModbusRx(pCmd->midx, pCmd->index, pCmd->cmd, pCmd->addr, pCmd->rddat, 1, 1); } if (rslt == pCmd->rlen) // 读到正确数据 { // 执行读到数据函数 if (p485Ctrl->resv485exproc != NULL) { p485Ctrl->resv485exproc(pCmd); } p485Ctrl->steps = p485Ctrl->modrsvTimout; } else { p485Ctrl->steps++; } } else { p485Ctrl->steps = p485Ctrl->modrsvTimout; } } else { p485Ctrl->steps++; } if (p485Ctrl->steps >= p485Ctrl->modrsvTimout) { if (p485Ctrl->bufCmdNum > 0) { p485Ctrl->bufCmdNum--; } p485Ctrl->steps = 0; p485Ctrl->working = 0; p485Ctrl->bufHead++; if (p485Ctrl->bufHead >= MAX_485CMD) { p485Ctrl->bufHead = 0; } } } return p485Ctrl->steps; } //----------------------------------------------------------------- #endif