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

468 lines
8.9 KiB
C

#include "one2onecomm.h"
#include "delay.h"
#include "crc16.h"
#include "trigger.h"
//-----------------------------------------------------------------
// 控制数据结构
typedef struct
{
u16 modBusWait; // 通讯延时, 单位us
// 通讯函数指针
UsartSendData One2OneCommSend; // 发送数据
UsartGetData One2OneCommReceive; // 接收数据
IsUsartSendOver IsOne2OneCommSendOver; // 判断发送缓冲区是否为空
}One2OneCommCtrl;
// 控制结构
One2OneCommCtrl g_one2onecommCtrl;
#define MAX_ONE2ONE_CMD 10 // 最大支持的命令个数
typedef struct
{
One2OneCmd cmdbuf[MAX_ONE2ONE_CMD];
u8 sending; // =1,发送中
u8 bufCmdNum; // 命令个数 != 0, 有新命令
u8 bufHead;
u8 bufTail;
u8 steps;
ResvOne2OneExProc resvexproc; // 收到数据处理函数
u16 rsvTimout; // 读取超时时间, 单位为 100us
}One2OneCtrl;
One2OneCtrl g_one2oneCtrl;
//-----------------------------------------------------------------
// 功能:初始化一对一通讯
void InitOne2OneComm(int usart, BAUD_TypeDef baud, char dat, char parity, char stop);
int One2OneCommTx(u16 addr, u16 * pData, u8 len, int steps); // 功能:发送
int One2OneCommRx(u8 rDat); // 功能:接收
//-----------------------------------------------------------------
// 注册通讯函数
void RegisterOne2OneCommFunc(One2OneCommCtrl* pCtrl, UsartSendData send, UsartGetData get, IsUsartSendOver sdover)
{
pCtrl->One2OneCommSend = send;
pCtrl->One2OneCommReceive = get;
pCtrl->IsOne2OneCommSendOver = sdover;
}
/*-----------------------------------------------------------------
功能:初始化设备串口
usart; 串口通道
baud : 波特率
dat: 数据长度
parity: 校验位
stop: 停止位
*/
void InitOne2OneComm(int usart, BAUD_TypeDef baud, char dat, char parity, char stop)
{
memset(&g_one2onecommCtrl, 0, sizeof(One2OneCommCtrl));
// 延时
switch(baud)
{
// 根据波特率来计算 通讯延时, 单位us = 10000000 / baud
case B4800:
{
g_one2onecommCtrl.modBusWait = 2200;
break;
}
case B9600:
{
g_one2onecommCtrl.modBusWait = 1100;
break;
}
case B14400:
{
g_one2onecommCtrl.modBusWait = 750;
break;
}
case B19200:
{
g_one2onecommCtrl.modBusWait = 600;
break;
}
case B38400:
{
g_one2onecommCtrl.modBusWait = 300;
break;
}
case B57600:
{
g_one2onecommCtrl.modBusWait = 200;
break;
}
case B115200:
{
g_one2onecommCtrl.modBusWait = 100;
break;
}
case B230400:
{
g_one2onecommCtrl.modBusWait = 50;
break;
}
case B460800:
{
g_one2onecommCtrl.modBusWait = 25;
break;
}
case B921600:
{
g_one2onecommCtrl.modBusWait = 13;
break;
}
default:
{
break;
}
}
// 初始化串口
switch(usart)
{
#ifdef COMM_USART1
case COMM_USART1:
{
InitUsart1(baud, dat, parity, stop); // 串口1
RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart1SendData, Usart1GetData, IsUsart1SendOver);
break;
}
#endif
#ifdef COMM_USART2
case COMM_USART2:
{
InitUsart2(baud, dat, parity, stop); // 串口2
RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart2SendData, Usart2GetData, IsUsart2SendOver);
break;
}
#endif
#ifdef COMM_USART3
case COMM_USART3:
{
InitUsart3(baud, dat, parity, stop); // 串口3
RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart3SendData, Usart3GetData, IsUsart3SendOver);
break;
}
#endif
#ifdef COMM_USART4
case COMM_USART4:
{
InitUsart4(baud, dat, parity, stop); // 串口4
RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart4SendData, Usart4GetData, IsUsart4SendOver);
break;
}
#endif
#ifdef COMM_USART5
case COMM_USART5:
{
InitUsart5(baud, dat, parity, stop); // 串口5
RegisterOne2OneCommFunc(&g_one2onecommCtrl, Usart5SendData, Usart5GetData, IsUsart5SendOver);
break;
}
#endif
default:
{
break;
}
}
}
//-----------------------------------------------------------------
// 功能:发送
// 参数:
// addr: 数据起始地址: 0000H~FFFFH
// data: 数据内容: 单位:字
// len: 数据长度
// steps:-1,同步执行
// 1,发送数据
// 2,等待数据发送完成
// 返回值:
// >0:对应步骤执行完成
// 0:数据未发送完成
// -1: 参数错误
// -2: 发送超时
int One2OneCommTx(u16 addr, u16 * pData, u8 len, int steps)
{
int i, timeout, result;
u16 checkcrc; // CRC 校验
u16 data;
u8 pSDat[5+2*MAX_REG_WR]; // 待发送数据
i = 0;
if (pData == NULL || len > MAX_REG_WR)
{
return -1;
}
if (steps == 1 || steps == -1)
{
i = 0;
result = 0;
pSDat[i++] = HIBYTE(addr); // ADDR_H
pSDat[i++] = LOBYTE(addr); // ADDR_L
pSDat[i++] = len;
for (int j = 0; j < len; j++)
{
data = pData[j];
pSDat[i++] = HIBYTE(data); // DATA_H
pSDat[i++] = LOBYTE(data); // DATA_L
}
checkcrc = CalcCrc16(&pSDat[0], i);
pSDat[i++] = HIBYTE(checkcrc); // CRC_H
pSDat[i++] = LOBYTE(checkcrc); // CRC_L
g_one2onecommCtrl.One2OneCommSend(pSDat, i);
}
if (steps == 2)
{
if (g_one2onecommCtrl.IsOne2OneCommSendOver() != TRUE)
{
return 0;
}
}
else if (steps == -1)
{
timeout = (u8)(i*2) + 4; // 超时时间(每个字节发送时长*2*字节数 + 每个字节发送时长*4 )
do //等待发送完成
{
if (g_one2onecommCtrl.IsOne2OneCommSendOver() == TRUE)
{
break;
}
if (timeout-- <= 0)
{
result = -2;
break;
}
DelayUs(g_one2onecommCtrl.modBusWait);
}while(1);
}
if (steps != -1)
{
return steps;
}
return result;
}
//-----------------------------------------------------------------
int One2OneCommRx(u8 rDat)
{
int rst = -1;
u32 time;
static u32 timeBuf = 0;
static u8 rxDat[15+2*MAX_REG_WR]; // 待接收数据缓冲区
static u8 idx = 0; // 有效索引
static u8 num = 0; // 接收到字符数
u16 checkcrc = 0; // crc校验
One2OneCmd newCmd;
memset(&newCmd, 0, sizeof(One2OneCmd));
time = Get100UsSoftTimer(); // 100us
if (0 ||
((time - timeBuf) > g_one2oneCtrl.rsvTimout) || // 读取超时时间, 单位为 100us
(idx >= 15+2*MAX_REG_WR) || // 超长复位
0)
{// 重新接收数据包
if (num > 1)
{
printf("data begin, num=%d\r\n", num);
}
idx = 0;
num = 1;
}
else
{
num++;
}
timeBuf = time;
if (num < 7) // 接收未完成
{
rxDat[idx] = rDat;
//printf("num=%d, rxDat[%d] is 0x%x \r\n", num, idx, rxDat[idx]);
idx++;
}
else
{
rxDat[idx] = rDat;
if (num == rxDat[2]*2 + 5) // 接收完成
{
//校验数据是否正确
checkcrc = CalcCrc16(&rxDat[0], num-2);
if (rxDat[num-2] == HIBYTE(checkcrc) && rxDat[num-1] == LOBYTE(checkcrc))
{//crc校验正确
newCmd.addr = MAKEWORD(rxDat[1],rxDat[0]); // 数据地址
newCmd.rdlen = rxDat[2];
for (int i = 0; i < newCmd.rdlen; i++)
{
newCmd.rddat[i] = MAKEWORD(rxDat[i*2+4],rxDat[i*2+3]); //数据
}
// 执行外部函数
if (g_one2oneCtrl.resvexproc != NULL)
{
g_one2oneCtrl.resvexproc(&newCmd);
}
rst = 0;
}
else
{
printf("check crc error, calc crc:0x%x 0x%x, receive crc:0x%x 0x%x\r\n",
HIBYTE(checkcrc), LOBYTE(checkcrc), rxDat[num-2], rxDat[num-1]);
}
idx = 0;
num = 0; // 重新接收数据包
}
else
{
idx++;
}
}
return rst;
}
//-----------------------------------------------------------------
void InitOne2OneCtrl(int usart, BAUD_TypeDef baud, char dat, char parity, char stop, int rsvtimout)
{
InitOne2OneComm(usart, baud, dat, parity, stop);
memset(&g_one2oneCtrl, 0, sizeof(One2OneCtrl));
g_one2oneCtrl.rsvTimout = rsvtimout;
}
void RegOne2OneCmdProc(ResvOne2OneExProc proc)
{
g_one2oneCtrl.resvexproc = proc;
}
int AddOne2OneCmd(One2OneCmd * pCmd)
{
if (pCmd != NULL)
{
if (g_one2oneCtrl.bufCmdNum < MAX_ONE2ONE_CMD && g_one2oneCtrl.bufHead < MAX_ONE2ONE_CMD)
{
memcpy(&(g_one2oneCtrl.cmdbuf[g_one2oneCtrl.bufHead]), pCmd, sizeof(One2OneCmd));
g_one2oneCtrl.bufHead++;
if (g_one2oneCtrl.bufHead >= MAX_ONE2ONE_CMD)
{
g_one2oneCtrl.bufHead = 0;
}
g_one2oneCtrl.bufCmdNum++;
return g_one2oneCtrl.bufCmdNum;
}
printf("bufcmd full\r\n");
return -2;
}
printf("para error\r\n");
return -1;
}
void One2OneTask(void)
{
int rslt;
// 异步发送数据
if (g_one2oneCtrl.sending == 0 &&
g_one2oneCtrl.bufCmdNum > 0 &&
g_one2oneCtrl.steps == 0)
{
g_one2oneCtrl.sending = 1;
g_one2oneCtrl.steps = 1;
}
if (g_one2oneCtrl.sending != 0)
{
One2OneCmd *pCmd;
pCmd = &(g_one2oneCtrl.cmdbuf[g_one2oneCtrl.bufTail]);
if (g_one2oneCtrl.steps > 0 && g_one2oneCtrl.steps < 3)
{
rslt = One2OneCommTx(pCmd->addr, &pCmd->wrdat[0], pCmd->wrlen, g_one2oneCtrl.steps);
if (rslt == g_one2oneCtrl.steps)
{
g_one2oneCtrl.steps++;
}
}
else if (g_one2oneCtrl.steps == 3)
{
if (g_one2oneCtrl.bufCmdNum > 0)
{
g_one2oneCtrl.bufCmdNum--;
}
g_one2oneCtrl.steps = 0;
g_one2oneCtrl.sending = 0;
g_one2oneCtrl.bufTail++;
if (g_one2oneCtrl.bufTail >= MAX_ONE2ONE_CMD)
{
g_one2oneCtrl.bufTail = 0;
}
}
}
// 接收串口缓冲区内数据
u8 rDat;
int len;
do
{
len = g_one2onecommCtrl.One2OneCommReceive(&rDat, 1); // 从缓冲区读取数据
if (len == 1)
{// 接收到串口数据
rslt = One2OneCommRx(rDat);
if (rslt == 0)
{// 接收到一个数据包
break;
}
}
else
{
break;
}
}while(1);
}
//-----------------------------------------------------------------