📄 uartwaitfunc.c
字号:
INT32U dwReadNum = 1; //要读的次数
INT32U dwReadNumBak;
INT32U dwSingleReadSize;
INT32S startadd,startbit;
BOOL MultRead = FALSE;
/*存操作的tag,以便修改*/
INT8S *DecTagBak = (INT8S *)malloc(10);
sscanf(pszDecTag + 1, "%d.%d", &startadd,&startbit);
sprintf(DecTagBak,"%C%01d.%C",*pszDecTag,startadd,startbit + 0x30);
/**********************************************************
检验传入参数的正确性,
**********************************************************/
if (pabyBitResult == NULL)
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto ReadBitError; //错误返回
}
if (dwSize + 9 > g_iMaxFrameSize) //多帧读
{
MultRead = TRUE;
if (dwSize % (g_iMaxFrameSize - 9))
dwReadNum = dwSize / (g_iMaxFrameSize - 9) + 1;
else
dwReadNum = dwSize / (g_iMaxFrameSize - 9);
}
dwReadNumBak = dwReadNum;
while (dwReadNum != 0)
{
/*确定每帧读的个数*/
if (MultRead)
{
if (dwReadNum > 1)
{
dwSingleReadSize = g_iMaxFrameSize - 9;
}
else //最后一次发读命令
{
dwSingleReadSize = dwSize - (dwReadNumBak - 1) * (g_iMaxFrameSize - 9);
}
}
else //单帧读
{
dwSingleReadSize = dwSize;
}
/*调用单帧读函数*/
result = SingleFrameReadBitWait(byAddr, pabyBitResult + iRecvBitNum, DecTagBak, dwSingleReadSize);
iRecvBitNum = iRecvBitNum + result;
if (result > 0) //读正确,修改相应DecTagBak
{
if (MultRead)
{
if (dwReadNum > 1) //调用TagChange()函数,更改TAG地址
{
result = TagChange(DecTagBak, COMMAND_BIT_RD);
if (result == 0)
{
result = ECOM_BADPARA;
goto ReadBitError;
}
}
}
dwReadNum--;
result = ECOM_NOERROR;
}
else //读错误,错误代码给result,错误返回
{
goto ReadBitError;
}
} //读位结束
free(DecTagBak);
return iRecvBitNum; //正确返回读取位个数
ReadBitError:
free(DecTagBak);
return result;
}
/*******************************************************************************
函数名: SingleFrameReadByteWait
描 述: 单帧读字节函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
pabyByteResult 返回读取字节或字节区间的首地址,该参数应传递数据格式的参数
pszDecTag 读取字节的信息TAG,详见通讯协议的方式
dwSize 读取的字节的个数
输 出: pabyByteResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的字节的个数,
否则表示执行的错误代码,
*******************************************************************************/
static SingleFrameReadByteWait(INT8U byAddr, INT8U *pabyByteResult, const INT8S *pszDecTag, INT32U dwSize)
{
STC_TAG_COMMAND stcTagCmd; //定义操作变量stcTagCmd
INT32S result = ECOM_NOERROR; //记录错误返回值
INT32S iRecvByteNum; //记录读取的字节的个数
INT32S iRecvTagLen = 0; //返回桢的字节数
/**********************************************************
用来存储接收到的桢数据,dwSize乘2是因为字节返回时需要占据两个
数据, 加6是因为要包括地址,命令和校验码6个字节的数据,加1是
要增加字符串的结束符'\0'
**********************************************************/
INT8U* pszRecv = (INT8U *)malloc(dwSize * 2 + 6 + 1);
/**********************************************************
检验传入参数的正确性,dwSize乘2是因为字节返回时需要占据两个
数据,加9是因为桢长还要包括前缀和后缀的长度
**********************************************************/
if ((pabyByteResult == NULL) || (dwSize * 2 + 9 > g_iMaxFrameSize))
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto SingleReadByteError;
}
if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_READ))
{
result = ECOM_BADPARA; //判断TAG是否有效,有效解码至stcTagCmd.stcTag;
goto SingleReadByteError;
}
if (ECOM_NOERROR == result) //如果参数无错,则发送数据桢
{
stcTagCmd.byRange = dwSize;
result = SendReadByteCommand(&stcTagCmd, byAddr);
}
if (result >= 0) //数据桢发送正确,则接收数据桢
{
#ifndef FORTESTONLY //测试编译开关
iRecvTagLen = GetModbusFrame(pszRecv);
#else
extern INT8U testbuf[50];
extern INT32S testsize;
iRecvTagLen = testsize;
pszRecv = testbuf;
#endif
}
else
{
goto SingleReadByteError;
}
if (iRecvTagLen < 0)
{
result = iRecvTagLen; //接收不正确,错误代码给result
goto SingleReadByteError;
}
else //数据桢接收正确,则进行校验
{
result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_CHAR_RD, dwSize);
}
if (result > 0) //数据桢校验正确,则获取最终的解码后数据
{
iRecvByteNum = GetFinalByteData(pabyByteResult, pszRecv, iRecvTagLen);
free(pszRecv); //释放开辟的资源
return iRecvByteNum; //返回接受的字节个数
}
else
{
goto SingleReadByteError;
}
SingleReadByteError:
free(pszRecv); //释放开辟的资源
return result;
}
/*******************************************************************************
读字节通讯帧, 协议为MODBUS协议ASCII方式
协议组成(':' + 设备地址 + 功能代码(0x03) + 字节TAG地址 + 读取字节数 + LRC校验 + 结束符)
EXAMPLE: 设备地址 = 22(DEC), TAG = MB14(DEC),读取连续5个字节,
设正常情况下返加的5个值为十六进制{0x13, 0x12, 0x31, 0x33, 0xA5},
若通讯错误,设错误代码为15(DEC)
发送帧
帧头 设备地址 功能代码 TAG MB14(DEC) = MB000E(HEX) 读取字节数 LRC校验
字节 _1__ ____2____ ____2____ ______________6______________ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x30 0x33 0x4E 0x42 0x30 0x30 0x30 0x45 0x30 0x35 0x^^ 0x^^
ASC ':' '1' '6' '0' '3' 'M' 'B' '0' '0' '0' 'E' '0' '5' '^' '^'
结束符
____2____
HEX 0x0D 0x0A
ASC '\r' '\n'
正常返回帧
帧头 设备地址 功能代码 读取值(占用字节数为读取字节数 * 2)
字节 _1__ ____2____ ____2____ ________________________10________________________
HEX 0x3A 0x31 0x36 0x30 0x33 0x31 0x33 0x31 0x32 0x33 0x31 0x33 0x33 0x41 0x35
ASC ':' '1' '6' '0' '3' '1' '3' '1' '2' '3' '1' '3' '3' 'A' '5'
LRC校验 结束符
字节 ____2____ ____2____
HEX 0x^^ 0x^^ 0x0D 0x0A
ASC '^' '^' '\r' '\n'
错误返回帧
帧头 设备地址 功能代码 错误代码 LRC校验 结束符
字节 _1__ ____2____ ____2____ ____2____ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x38 0x33 0x30 0x46 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '8' '3' '0' 'F' '^' '^' '\r' '\n'
注意:0x^^代表实际运算的校验和, '^'表示对应的校验和的ASCII表达方式
*******************************************************************************/
/*******************************************************************************
函数名: COM_ReadByteWait
描 述: 读字节等待函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
pabyByteResult 返回读取字节或字节区间的首地址,以16进制格式存放,如0x1F
pszDecTag 读取字节的信息TAG,如MB14,详见通讯协议的方式
dwSize 读取的字节的个数
输 出: pabyByteResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的字节的个数,
否则表示执行的错误代码,
*******************************************************************************/
INT32S WINAPI COM_ReadByteWait(INT8U byAddr, INT8U *pabyByteResult, const INT8S *pszDecTag, INT32U dwSize)
{
INT32S result = ECOM_NOERROR; //记录错误返回值
INT32S iRecvByteNum = 0; //记录读取的字节的个数
INT32U dwReadNum = 1; //要读的次数
INT32U dwReadNumBak;
INT32U dwSingleReadSize;
INT32S startadd; //起始偏移地址
BOOL MultRead = FALSE;
/*存操作的tag,以便修改*/
INT8S *DecTagBak = (INT8S *)malloc(10);
sscanf(pszDecTag + 2, "%d", &startadd);
sprintf(DecTagBak,"%C%C%01d",*pszDecTag, *(pszDecTag + 1), startadd);
/**********************************************************
检验传入参数的正确性,
**********************************************************/
if (pabyByteResult == NULL)
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto ReadByteError;
}
if (dwSize * 2 + 9 > g_iMaxFrameSize) //多帧读
{
MultRead = TRUE;
if (dwSize % ((g_iMaxFrameSize - 9) / 2))
dwReadNum = dwSize / ((g_iMaxFrameSize - 9) / 2) + 1;
else
dwReadNum = dwSize / ((g_iMaxFrameSize - 9) / 2);
}
dwReadNumBak = dwReadNum;
while (dwReadNum != 0)
{
/*确定每帧读的个数*/
if (MultRead)
{
if (dwReadNum > 1)
{
dwSingleReadSize = (g_iMaxFrameSize - 9) / 2;
}
else //最后一次发读命令
{
dwSingleReadSize = dwSize - (dwReadNumBak - 1) * ((g_iMaxFrameSize - 9) / 2);
}
}
else //单帧读
{
dwSingleReadSize = dwSize;
}
/*调用单帧读函数*/
result = SingleFrameReadByteWait(byAddr, pabyByteResult + iRecvByteNum, DecTagBak, dwSingleReadSize);
iRecvByteNum = iRecvByteNum + result;
if (result > 0) //读正确,修改相应TAG地址
{
if (MultRead)
{
if (dwReadNum > 1) //调用TagChange()函数,更改TAG地址
{
result = TagChange(DecTagBak, COMMAND_CHAR_RD);
if (result == 0)
{
result = ECOM_BADPARA;
goto ReadByteError;
}
}
}
dwReadNum--;
result = ECOM_NOERROR;
}
else
{
goto ReadByteError;
} //读字节结束
}
free(DecTagBak); //释放开辟的资源
return iRecvByteNum; //返回接受的字节个数
ReadByteError:
free(DecTagBak); //释放开辟的资源
return result;
}
/*******************************************************************************
函数名: SingleFrameReadWordWait
描 述: 单帧读字函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
pawWordResult 返回读取字或字区间的首地址,该参数应传递数据格式的参数
pszDecTag 读取字的信息TAG,详见通讯协议的方式
dwSize 读取的字的个数
输 出: pawResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的字的个数,
否则表示执行的错误代码
*******************************************************************************/
static SingleFrameReadWordWait(INT8U byAddr, INT16U *pawWordResult, const INT8S *pszDecTag, INT32U dwSize)
{
STC_TAG_COMMAND stcTagCmd; //定义操作变量stcTagCmd
INT32S result = ECOM_NOERROR; //记录返回值
INT32S iRecvWordNum; //记录读取的字的个数
INT32S iRecvTagLen = 0; //返回桢的字节数
/**********************************************************
用来存储接收到的桢数据,dwSize乘4是因为字返回时需要占据四个
数据, 加6是因为要包括地址,命令和校验码6个字节的数据,加1是
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -