📄 uartwaitfunc.c
字号:
HEX 0x^^ 0x^^ 0x0D 0x0A
ASC '^' '^' '\r' '\n'
错误返回帧
帧头 设备地址 功能代码 错误代码 LRC校验 结束符
字节 _1__ ____2____ ____2____ ____2____ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x38 0x37 0x30 0x46 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '8' '7' '0' 'F' '^' '^' '\r' '\n'
注意:0x^^代表实际运算的校验和, '^'表示对应的校验和的ASCII表达方式
*******************************************************************************/
/*******************************************************************************
函数名: COM_ReadDWordWait
描 述: 读双字等待函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
padwDWordResult 返回读取字或字区间的首地址,16进制格式存放,如0x1213ABCD
pszDecTag 读取字的信息TAG,如,MD16,详见通讯协议的方式
dwSize 读取的字的个数
输 出: padwResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的双字的个数,
否则表示执行的错误代码,调用GetErrMsg可获得详细的错误信息
*******************************************************************************/
INT32S WINAPI COM_ReadDWordWait(INT8U byAddr, INT32U *padwDWordResult, const INT8S *pszDecTag, INT32U dwSize)
{
INT32S result = ECOM_NOERROR; //记录返回值
INT32S iRecvDWordNum = 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 (padwDWordResult == NULL)
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto ReadDWordError;
}
if (dwSize * 8 + 9 > g_iMaxFrameSize) //多帧读
{
MultRead = TRUE;
if (dwSize % ((g_iMaxFrameSize - 9) / 8))
dwReadNum = dwSize / ((g_iMaxFrameSize - 9) / 8) + 1;
else
dwReadNum = dwSize / ((g_iMaxFrameSize - 9) / 8);
}
dwReadNumBak = dwReadNum;
while (dwReadNum != 0)
{
/*确定每帧读的个数*/
if (MultRead)
{
if (dwReadNum > 1)
{
dwSingleReadSize = (g_iMaxFrameSize - 9) / 8;
}
else //最后一次发读命令
{
dwSingleReadSize = dwSize - (dwReadNumBak - 1) * ((g_iMaxFrameSize - 9) / 8);
}
}
else //单帧读
{
dwSingleReadSize = dwSize;
}
/*调用单帧读函数*/
result = SingleFrameReadDWordWait(byAddr, padwDWordResult + iRecvDWordNum, DecTagBak, dwSingleReadSize);
iRecvDWordNum = iRecvDWordNum + result;
if (result > 0) //读正确,修改相应TAG地址
{
if (MultRead)
{
if (dwReadNum > 1) //调用TagChange()函数,更改TAG地址
{
result = TagChange(DecTagBak, COMMAND_LONG_RD);
if (result == 0)
{
result = ECOM_BADPARA;
goto ReadDWordError;
}
}
}
dwReadNum--;
result = ECOM_NOERROR;
}
else
{
goto ReadDWordError;
}
} //读结束
free(DecTagBak); //释放开辟的资源
return iRecvDWordNum; //返回接受的字个数
ReadDWordError:
free(DecTagBak); //释放开辟的资源
return result;
}
/*******************************************************************************
函数名: SingleFrameWriteBitWait
描 述: 单帧写位函数,执行该函数后将数据写入指定位地址
输 入: byAddr 选用的下位机地址,如1,2等
pabyBitInput 存放写入数据的首地址,该参数应传递数据格式的参数
pszDecTag 写位的信息TAG,详见通讯协议的方式
dwSize 写位的个数
输 出: 无
返回值: 写入正确返回发送字节数,包括帧头和结尾符,否则表示执行的错误代码,
*******************************************************************************/
static SingleFrameWriteBitWait(INT8U byAddr, const INT8U *pabyBitInput, const INT8S *pszDecTag, INT32U dwSize)
{
STC_TAG_COMMAND stcTagCmd; //定义操作变量stcTagCmd
INT32S result = ECOM_NOERROR; //错误返回值]
INT32S iSendBitNum; //实际发送字节数
INT32S iRecvTagLen = 0; //返回桢的字节数
/**********************************************************
pszRecv指向接收到的桢数据, 开辟12字节空间
**********************************************************/
INT8U* pszRecv = (INT8U *)malloc(12);
/**********************************************************
检验传入参数的正确性,dwSize加17是因为桢长还要包括前缀和后缀
的长度,及tag的6字节
**********************************************************/
if ((pabyBitInput == NULL) || (dwSize + 17 > g_iMaxFrameSize))
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto SingleWriteBitError; //错误返回
}
if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_WRITE))
{
result = ECOM_BADPARA; //判断TAG是否有效,有效解码至stcTagCmd.stcTag;
goto SingleWriteBitError;
}
if (ECOM_NOERROR == result) //如果参数无错,则发送数据桢;发送正确返回发送字节数
{
stcTagCmd.byRange = dwSize;
iSendBitNum = SendWriteBitCommand(&stcTagCmd, byAddr, pabyBitInput);
}
if (iSendBitNum >= 0) //数据桢发送正确,则接收数据桢
{
#ifndef FORTESTONLY //测试编译开关
iRecvTagLen = GetModbusFrame(pszRecv);
#else
extern INT8U testbuf[50];
extern INT32S testsize;
iRecvTagLen = testsize;
pszRecv = testbuf;
#endif
}
else
{
result = iSendBitNum; //发送不正确,错误代码给result
goto SingleWriteBitError;
}
if (iRecvTagLen < 0)
{
result = iRecvTagLen; //接收不正确,错误代码给result
goto SingleWriteBitError;
}
else //数据桢接收正确,则进行校验
{
result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_BIT_WR, dwSize);
}
if (ECOM_NOERROR == result) //校验正确,
{
free(pszRecv); //释放开辟的资源
return iSendBitNum;
}
else
{
goto SingleWriteBitError;
}
SingleWriteBitError:
free(pszRecv); //释放开辟的资源
return result;
}
/*******************************************************************************
写位通讯帧, 协议为MODBUS协议ASCII方式
协议组成 (':' + 设备地址 + 功能代码(0x0F) + 位TAG地址 + 写入位数 + 写入位数据
+ LRC校验 + 结束符)
EXAMPLE: 设备地址 = 22(DEC), TAG = M38.6(DEC),连续写4个位, 写入值分别为1001
若通讯错误,则设错误代码为16(DEC)
发送帧
帧头 设备地址 功能代码 TAG M38.6(DEC) = M60026(HEX) 写入位数
字节 _1__ ____2____ ____2____ ______________6______________ ____2____
HEX 0x3A 0x31 0x36 0x30 0x46 0x4E 0x36 0x30 0x30 0x32 0x36 0x30 0x34
ASC ':' '1' '6' '0' 'F' 'M' '6' '0' '0' '2' '6' '0' '4'
数据(字节数为写入位数) LRC校验 结束符
_________4_________ ____2____ ____2____
HEX 0x31 0x30 0x30 0x31 0x^^ 0x^^ 0x0D 0x0A
ASC '1' '0' '0' '1' '^' '^' '\r' '\n'
正常返回帧
帧头 设备地址 功能代码 LRC校验 结束符
字节 _1__ ____2____ ____2____ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x30 0x46 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '0' 'F' '^' '^' '\r' '\n'
错误返回帧
帧头 设备地址 功能代码 错误代码 LRC校验 结束符
字节 _1__ ____2____ ____2____ ____2____ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x38 0x46 0x31 0x30 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '8' 'F' '1' '0' '^' '^' '\r' '\n'
注意:0x^^代表实际运算的校验和, '^'表示对应的校验和的ASCII表达方式
*******************************************************************************/
/*******************************************************************************
函数名: COM_WriteBitWait
描 述: 写位等待函数,执行该函数后将数据写入指定位地址
输 入: byAddr 选用的下位机地址,如1,2等
pabyBitInput 存放写入数据的首地址,参数以16进制格式输入,如0x00,0x01
pszDecTag 写位的信息TAG,十进制格式,如M38.5,详见通讯协议的方式
dwSize 写位的个数
输 出: 无
返回值: 写入正确返回ECOM_NOERROR,否则表示执行的错误代码,
*******************************************************************************/
INT32S WINAPI COM_WriteBitWait(INT8U byAddr, const INT8U *pabyBitInput, const INT8S *pszDecTag, INT32U dwSize)
{
INT32S result = ECOM_NOERROR; //错误返回值
INT32S iSendBitNum = 0; //实际发送字节数
INT32U dwWriteNum = 1; //要写的次数
INT32U dwWriteNumBak;
INT32U dwSingleWriteSize;
INT32S startadd,startbit;
BOOL MultWrite = FALSE;
/*存操作的tag,以便修改*/
INT8S *DecTagBak = (INT8S *)malloc(10);
sscanf(pszDecTag + 1, "%d.%d", &startadd,&startbit);
sprintf(DecTagBak,"%C%01d.%C",*pszDecTag,startadd,startbit + 0x30);
/**********************************************************
检验传入参数的正确性
**********************************************************/
if (pabyBitInput == NULL)
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto WriteBitError; //错误返回
}
if (g_iMaxFrameSize - 17 < 1) //帧过小,不能完成单帧发送一个位
{
result = ECOM_TOOSMALLSIZE;
goto WriteBitError;
}
if (dwSize + 17 > g_iMaxFrameSize) //多帧写
{
MultWrite = TRUE;
if (dwSize % (g_iMaxFrameSize - 17))
dwWriteNum = dwSize / (g_iMaxFrameSize - 17) + 1;
else
dwWriteNum = dwSize / (g_iMaxFrameSize - 17);
}
dwWriteNumBak = dwWriteNum;
while (dwWriteNum != 0)
{
/*确定每帧写的个数*/
if (MultWrite)
{
if (dwWriteNum > 1) //多帧写
{
dwSingleWriteSize = g_iMaxFrameSize - 17;
}
else //发最后一次写命令
{
dwSingleWriteSize = dwSize - (dwWriteNumBak - 1) * (g_iMaxFrameSize - 17);
}
}
else //单帧写
{
dwSingleWriteSize = dwSize;
}
/*调用单帧写函数*/
result = SingleFrameWriteBitWait(byAddr, pabyBitInput + iSendBitNum, DecTagBak, dwSingleWriteSize);
iSendBitNum = iSendBitNum + (result - 17);
if (result > 0) //单帧写正确,修改相应TAG地址,
{
if (MultWrite)
{
if (dwWriteNum > 1) //调用TagChange()函数,更改TAG地址
{
result = TagChange(DecTagBak, COMMAND_BIT_WR);
if (result == 0)
{
result = ECOM_BADPARA;
goto WriteBitError;
}
}
}
dwWriteNum--;
result = ECOM_NOERROR;
}
else
{
goto WriteBitError;
}
} //写位结束
free(DecTagBak); //释放开辟的资源
return ECOM_NOERROR;
WriteBitError:
free(DecTagBak); //释放开辟的资源
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -