optical/NxFuncs/modbus/modbus_m.c
2025-09-04 09:45:08 +08:00

1248 lines
25 KiB
C
Raw Permalink 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_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