1248 lines
25 KiB
C
1248 lines
25 KiB
C
|
||
#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
|
||
|