📄 uartwaitfunc.c
字号:
要增加字符串的结束符'\0'
**********************************************************/
INT8U* pszRecv = (INT8U *)malloc(dwSize * 4 + 6 + 1);
/**********************************************************
检验传入参数的正确性,dwSize乘4是因为字节返回时需要占据两个
数据,加9是因为桢长还要包括前缀和后缀的长度
**********************************************************/
if ((pawWordResult == NULL) || (dwSize * 4 + 9 > g_iMaxFrameSize))
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto SingleReadWordError;
}
if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_READ))
{
result = ECOM_BADPARA; //首先检验TAG正确,若正确解码至stcTagCmd.stcTag;
goto SingleReadWordError;
}
if (ECOM_NOERROR == result) //如果参数无错,则发送数据桢
{
stcTagCmd.byRange = dwSize;
result = SendReadWordCommand(&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 SingleReadWordError;
}
if (iRecvTagLen < 0)
{
result = iRecvTagLen; //接收不正确,错误代码给result
goto SingleReadWordError;
}
else //数据桢接收正确,则进行校验
{
result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_SHORT_RD, dwSize);
}
if (result > 0) //数据桢校验正确,则获取最终的解码后数据
{
iRecvWordNum = GetFinalWordData(pawWordResult, pszRecv, iRecvTagLen);
free(pszRecv); //释放开辟的资源
return iRecvWordNum; //返回接受的字个数
}
else
{
goto SingleReadWordError;
}
SingleReadWordError:
free(pszRecv); //释放开辟的资源
return result;
}
/*******************************************************************************
读字通讯帧, 协议为MODBUS协议ASCII方式
协议组成(':' + 设备地址 + 功能代码(0x05) + 字TAG地址 + 读取字数 + LRC校验 + 结束符)
EXAMPLE: 设备地址 = 22(DEC), TAG = MW22(DEC), MW22占用MB22和MB23两个字节,
设读取连续2个字(读取值为MW22、MW24) 设MW22 = 0x1314, MW24 = 0x3245,
若通讯错误,设错误代码为15(DEC)
发送帧
帧头 设备地址 功能代码 TAG MW22(DEC) = MW0016(HEX) 读取字数 LRC校验
字节 _1__ ____2____ ____2____ ______________6______________ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x30 0x35 0x4E 0x57 0x30 0x30 0x31 0x36 0x30 0x32 0x^^ 0x^^
ASC ':' '1' '6' '0' '5' 'M' 'W' '0' '0' '1' '6' '0' '2' '^' '^'
结束符
____2____
HEX 0x0D 0x0A
ASC '\r' '\n'
正常返回帧
帧头 设备地址 功能代码 读取值(占用字节数 = 读取字数 * 4)
字节 _1__ ____2____ ____2____ ___________________8____________________
HEX 0x3A 0x31 0x36 0x30 0x35 0x31 0x33 0x31 0x34 0x33 0x32 0x34 0x35
ASC ':' '1' '6' '0' '5' '1' '3' '1' '4' '3' '2' '4' '5'
LRC校验 结束符
字节 ____2____ ____2____
HEX 0x^^ 0x^^ 0x0D 0x0A
ASC '^' '^' '\r' '\n'
错误返回帧
帧头 设备地址 功能代码 错误代码 LRC校验 结束符
字节 _1__ ____2____ ____2____ ____2____ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x38 0x35 0x30 0x46 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '8' '5' '0' 'F' '^' '^' '\r' '\n'
注意:0x^^代表实际运算的校验和, '^'表示对应的校验和的ASCII表达方式
*******************************************************************************/
/*******************************************************************************
函数名: COM_ReadWordWait
描 述: 读字等待函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
pawWordResult 返回读取字或字区间的首地址,以16进制存放,如0x131A
pszDecTag 读取字的信息TAG,如MW22,详见通讯协议的方式
dwSize 读取的字的个数
输 出: pawResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的字的个数,
否则表示执行的错误代码,
*******************************************************************************/
INT32S WINAPI COM_ReadWordWait(INT8U byAddr, INT16U *pawWordResult,const INT8S *pszDecTag, INT32U dwSize)
{
INT32S result = ECOM_NOERROR; //记录返回值
INT32S iRecvWordNum = 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 (pawWordResult == NULL)
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto ReadWordError;
}
if (dwSize * 4 + 9 > g_iMaxFrameSize) //多帧读
{
MultRead = TRUE;
if (dwSize % ((g_iMaxFrameSize - 9) / 4))
dwReadNum = dwSize / ((g_iMaxFrameSize - 9) / 4) + 1;
else
dwReadNum = dwSize / ((g_iMaxFrameSize - 9) / 4);
}
dwReadNumBak = dwReadNum;
while (dwReadNum != 0)
{
/*确定每帧读的个数*/
if (MultRead)
{
if (dwReadNum > 1)
{
dwSingleReadSize = (g_iMaxFrameSize - 9) / 4;
}
else //最后一次发读命令
{
dwSingleReadSize = dwSize - (dwReadNumBak - 1) * ((g_iMaxFrameSize - 9) / 4);
}
}
else //单帧读
{
dwSingleReadSize = dwSize;
}
/*调用单帧读函数*/
result = SingleFrameReadWordWait(byAddr, pawWordResult + iRecvWordNum, DecTagBak, dwSingleReadSize);
iRecvWordNum = iRecvWordNum + result;
if (result > 0) //读正确,修改相应TAG地址
{
if (MultRead)
{
if (dwReadNum > 1) //调用TagChange()函数,更改TAG地址
{
result = TagChange(DecTagBak, COMMAND_SHORT_RD);
if (result == 0)
{
result = ECOM_BADPARA;
goto ReadWordError;
}
}
}
dwReadNum--;
result = ECOM_NOERROR;
}
else
{
goto ReadWordError;
}
}
free(DecTagBak); //释放开辟的资源
return iRecvWordNum; //返回接受的字个数
ReadWordError:
free(DecTagBak); //释放开辟的资源
return result;
}
/*******************************************************************************
函数名: SingleFrameReadDWordWait
描 述: 读双字等待函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
padwDWordResult 返回读取字或字区间的首地址,该参数应传递数据格式的参数
pszDecTag 读取字的信息TAG,详见通讯协议的方式
dwSize 读取的字的个数
输 出: padwResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的双字的个数,
否则表示执行的错误代码,
*******************************************************************************/
static SingleFrameReadDWordWait(INT8U byAddr, INT32U *padwDWordResult, const INT8S *pszDecTag, INT32U dwSize)
{
STC_TAG_COMMAND stcTagCmd; //定义操作变量stcTagCmd
INT32S result = ECOM_NOERROR; //记录返回值
INT32S iRecvDWordNum; //记录读取的双字的个数
INT32S iRecvTagLen = 0; //返回桢的字节数
/**********************************************************
用来存储接收到的桢数据,dwSize乘8是因为双字返回时需要占据八个
数据, 加6是因为要包括地址,命令和校验码6个字节的数据,加1是
要增加字符串的结束符'\0'
**********************************************************/
INT8U* pszRecv = (INT8U *)malloc(dwSize * 8 + 6 + 1);
/**********************************************************
检验传入参数的正确性,dwSize乘8是因为字节返回时需要占据两个
数据,加9是因为桢长还要包括前缀和后缀的长度
**********************************************************/
if ((padwDWordResult == NULL) || (dwSize * 8 + 9 > g_iMaxFrameSize))
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto SingleReadDWordError;
}
if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_READ))
{
result = ECOM_BADPARA; //首先检验TAG正确,若正确解码至stcTagCmd.stcTag;
goto SingleReadDWordError;
}
if (ECOM_NOERROR == result) //如果参数无错,则发送数据桢
{
stcTagCmd.byRange = dwSize;
result = SendReadDWordCommand(&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 SingleReadDWordError;
}
if (iRecvTagLen < 0)
{
result = iRecvTagLen; //接收不正确,错误代码给result
goto SingleReadDWordError;
}
else //数据桢接收正确,则进行校验
{
result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_LONG_RD, dwSize);
}
if (result > 0) //数据桢校验正确,则获取最终的解码后数据
{
iRecvDWordNum = GetFinalDWordData(padwDWordResult, pszRecv, iRecvTagLen);
free(pszRecv); //释放开辟的资源
return iRecvDWordNum; //返回接受的字个数
}
else
{
goto SingleReadDWordError;
}
SingleReadDWordError:
free(pszRecv); //释放开辟的资源
return result;
}
/*******************************************************************************
读双字通讯帧, 协议为MODBUS协议ASCII方式
协议组成(':' + 设备地址 + 功能代码(0x07) + 双字TAG地址 + 读取双字数 + LRC校验 + 结束符)
EXAMPLE: 设备地址 = 22(DEC), TAG = MD22(DEC), MD22占用MB22和MB23,MB24,MB26共四个字节,
设读取连续1个双字,设MD22 = 0x13143245,
若通讯错误,设错误代码为15(DEC)
发送帧
帧头 设备地址 功能代码 TAG MW22(DEC) = MW0016(HEX) 读取字数 LRC校验
字节 _1__ ____2____ ____2____ ______________6______________ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x30 0x37 0x4E 0x44 0x30 0x30 0x31 0x36 0x30 0x31 0x^^ 0x^^
ASC ':' '1' '6' '0' '7' 'M' 'D' '0' '0' '1' '6' '0' '1' '^' '^'
结束符
____2____
HEX 0x0D 0x0A
ASC '\r' '\n'
正常返回帧
帧头 设备地址 功能代码 读取值(占用字节数 = 读取双字数 * 8)
字节 _1__ ____2____ ____2____ ___________________8____________________
HEX 0x3A 0x31 0x36 0x30 0x37 0x31 0x33 0x31 0x34 0x33 0x32 0x34 0x35
ASC ':' '1' '6' '0' '7' '1' '3' '1' '4' '3' '2' '4' '5'
LRC校验 结束符
字节 ____2____ ____2____
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -