📄 uartwaitfunc.c
字号:
*******************************************************************************/
#include "includes.h"
/*******************************************************************************
调用COM_SetUartPara函数时,可采用以下两个参数
DEF_UART_BAUD 表示串口默认波特率为9600 bit/s(比特/秒)
DEF_UART_MODE 表示串口默认为数据位8位,停止位1位及无校验位的模式
*******************************************************************************/
#define DEF_UART_BAUD B9600
#define DEF_UART_MODE BIT_8|STOP_1|P_NONE
extern INT32S g_iMaxFrameSize; //外部变量,每桢发送的最大字节长度,从':'起到'0x0a'
extern INT32S g_iComNumber;
extern INT32S g_iMaxOutTime; //工作过程中的等待时间
/*******************************************************************************
函数名: COM_OpenUart
描 述: 打开串口
输 入: port 选用的串口,如COM1,COM2等
输 出: 无
返回值: INT32S 类型,其值表示函数的执行结果,为0时则操作成功,否则表示执行的错误
代码,
*******************************************************************************/
INT32S WINAPI COM_OpenUart(const INT32S port)
{
g_iComNumber = port; //打开串口时给默认串口付初值
return sio_open(port);
}
/*******************************************************************************
函数名: COM_CloseUart
描 述: 关闭串口
输 入: port 选用的串口,如COM1,COM2等
输 出: 无
返回值: INT32S 类型,其值表示函数的执行结果,为0时则操作成功,否则表示执行的错误
代码,
*******************************************************************************/
INT32S WINAPI COM_CloseUart(const INT32S port)
{
if (port != g_iComNumber) //判断是否是先前打开的串口
{
return ECOM_BADPARA; //若不是则返回参数错误
}
return sio_close(port);
}
/*******************************************************************************
函数名: COM_SetUartPara
描 述: 设置串口的通讯参数
输 入: port 选用的串口,如COM1,COM2等
baud 选用串口的波特率,应采用动态链接库头文件中给出的数据,如B110,
B1200,B9600等
mode 选用串口的模式,应采用动态链接库头文件中给出的数据,并且将采
用的选型进行或操作,如选择模式为数据位8位,停止位1位及无校验
位的模式,则mode参数应为"BIT_8|STOP_1|P_NONE"
输 出: 无
返回值: INT32S 类型,其值表示函数的执行结果,为0时则操作成功,否则表示执行的错误
代码,
*******************************************************************************/
INT32S WINAPI COM_SetUartPara(const INT32S port, const INT32S baud, const INT32S mode)
{
if (port != g_iComNumber) //判断是否是先前打开的串口
{
return ECOM_BADPARA; //若不是则返回参数错误
}
return sio_ioctl(port, baud, mode);
}
/*******************************************************************************
函数名: COM_SetFrameSize
描 述: 设置最大帧长
输 入: port 选用的串口,如COM1,COM2等
dwMaxSize 最大帧长
输 出: 无
返回值: INT32S 类型,其值表示函数的执行结果,成功返回最大帧长,否则表示执行的错误
代码,
*******************************************************************************/
INT32S WINAPI COM_SetFrameSize(const INT32S port, const INT32S MaxSize)
{
if (MaxSize < 0 || port < 0)
return ECOM_BADPARA ;
else if (MaxSize < 18)
return ECOM_TOOSMALLSIZE ;
g_iComNumber = port; //打开串口时给默认串口付初值
g_iMaxFrameSize = MaxSize; //给默认最大帧长赋初值
return g_iMaxFrameSize;
}
/*******************************************************************************
函数名: COM_SetTimeOut
描 述: 设置最大等待时间
输 入: port 选用的串口,如COM1,COM2等
dwMaxOutTime 最大等待时间
输 出: 无
返回值: INT32S 类型,其值表示函数的执行结果,成功返回最大等待时间,否则表示执行的错误
代码,
*******************************************************************************/
INT32S WINAPI COM_SetTimeOut(const INT32S port, const INT32S OutTime)
{
if (OutTime < 0 || port < 0)
return ECOM_BADPARA;
g_iComNumber = port; //打开串口时给默认串口付初值
g_iMaxOutTime = OutTime; //为最大等待时间赋初值
return g_iMaxOutTime;
}
/*******************************************************************************
函数名: TagChange
描 述: Tag地址修改函数
输 入: DecTag 要修改的TAG
enumCmd 操作类型,如COMMAND_BIT_RD
输 出: DecTag 修改后的TAG
返回值:0 修改失败
1 修改成功
*******************************************************************************/
INT8U TagChange(INT8S *DecTag, EUartCommand enumCmd)
{
INT32S addr = -1;
INT32S bit = -1;
INT8S Range = toupper(DecTag[1]);
if (isdigit(Range))
{
sscanf(DecTag + 1, "%d.%d", &addr,&bit);
switch (enumCmd)
{
case COMMAND_BIT_RD:
addr = addr + (g_iMaxFrameSize - 9 + bit) / 8;
bit = (g_iMaxFrameSize - 9 + bit) % 8;
break;
case COMMAND_BIT_WR:
addr = addr + (g_iMaxFrameSize - 17 + bit) / 8;
bit = (g_iMaxFrameSize - 17 + bit) % 8;
}
sprintf(DecTag + 1, "%01d.%C", addr,bit + 0x30);
return TRUE;
}
else if (Range == 'B' || Range == 'W' || Range == 'D')
{
sscanf(DecTag + 2, "%d", &addr);
if (Range == 'B')
{
switch (enumCmd)
{
case COMMAND_CHAR_RD:
addr = addr + (g_iMaxFrameSize - 9) / 2;
break;
case COMMAND_CHAR_WR:
addr = addr + (g_iMaxFrameSize - 17) / 2;
}
sprintf(DecTag + 2, "%01d", addr);
return TRUE;
}
if (Range == 'W')
{
switch (enumCmd)
{
case COMMAND_SHORT_RD:
addr = addr + ((g_iMaxFrameSize - 9) / 4) * 2;
break;
case COMMAND_SHORT_WR:
addr = addr + ((g_iMaxFrameSize - 17) / 4) * 2;
}
sprintf(DecTag + 2, "%01d", addr);
return TRUE;
}
if (Range == 'D')
{
switch (enumCmd)
{
case COMMAND_LONG_RD:
addr = addr + ((g_iMaxFrameSize - 9) / 8) * 4;
break;
case COMMAND_LONG_WR:
addr = addr + ((g_iMaxFrameSize - 17) / 8) * 4;
}
sprintf(DecTag + 2, "%01d", addr);
return TRUE;
}
}
else
{
return FALSE;
}
}
/*******************************************************************************
函数名: SingleFrameReadBitWait
描 述: 单帧读位等待函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
pabyBitResult 返回读取位或位域的首地址,该参数应传递数据格式的参数
pszDecTag 读取位的信息TAG,详见通讯协议的方式
dwSize 读取的位的个数
输 出: pabyBitResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的位的个数,
否则表示执行的错误代码,
*******************************************************************************/
static SingleFrameReadBitWait(INT8U byAddr, INT8U *pabyBitResult, const INT8S *pszDecTag, INT32U dwSize)
{
STC_TAG_COMMAND stcTagCmd; //定义操作变量stcTagCmd
INT32S result = ECOM_NOERROR; //错误返回值
INT32S iRecvBitNum; //正确返回读取的位的个数
INT32S iRecvTagLen = 0; //返回桢的字节数
/**********************************************************
pszRecv指向接收到的桢数据, 加6是因为要包括地址,命令和校验码6
个字节的数据,加1是要增加字符串的结束符'\0',
再加1是为读1位却返回错误代码2字节特殊情况考虑
**********************************************************/
INT8U* pszRecv = (INT8U *)malloc(dwSize + 6 + 1 + 1);
/**********************************************************
检验传入参数的正确性,dwSize加9是因为桢长还要包括前缀和后缀
的长度
**********************************************************/
if ((pabyBitResult == NULL) || (dwSize + 9 > g_iMaxFrameSize))
{
result = ECOM_BADPARA; //检验传入参数的正确性;
goto SingleReadBitError; //错误返回
}
if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_READ))
{
result = ECOM_BADPARA; //判断TAG是否有效,有效解码至stcTagCmd.stcTag;
goto SingleReadBitError;
}
if (ECOM_NOERROR == result) //如果参数无错,则发送数据桢;发送正确返回发送字节数
{
stcTagCmd.byRange = dwSize;
result = SendReadBitCommand(&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 SingleReadBitError;
}
if (iRecvTagLen < 0)
{
result = iRecvTagLen; //接收不正确,错误代码给result
goto SingleReadBitError;
}
else //数据桢接收正确,则进行校验
{
result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_BIT_RD, dwSize);
}
if (result > 0) //校验正确,则获取最终的解码后数据
{
iRecvBitNum = GetFinalBitData(pabyBitResult, pszRecv, iRecvTagLen);
free(pszRecv); //释放开辟的资源
return iRecvBitNum;
}
else
{
goto SingleReadBitError;
}
SingleReadBitError:
free(pszRecv); //释放开辟的资源
return result;
}
/*******************************************************************************
读位通讯帧, 协议为MODBUS协议ASCII方式
协议组成(':' + 设备地址 + 功能代码(0x01) + 位TAG地址 + 读取位数 + LRC校验 + 结束符)
EXAMPLE: 设备地址 = 22(DEC), TAG = M38.6(DEC),读取连续5个位,
设正常通讯读出值为11010,若通讯错误,则设错误代码为16(DEC)
发送帧
帧头 设备地址 功能代码 TAG M38.6(DEC) = M60026(HEX) 读取位数 LRC校验
字节 _1__ ____2____ ____2____ ______________6______________ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x30 0x31 0x4E 0x36 0x30 0x30 0x32 0x36 0x30 0x35 0x38 0x38
ASC ':' '1' '6' '0' '1' 'M' '6' '0' '0' '2' '6' '0' '5' '8' '8'
结束符
____2____
HEX 0x0D 0x0A
ASC '\r' '\n'
正常返回帧
帧头 设备地址 功能代码 读取值(字节数为读取位数) LRC校验 结束符
字节 _1__ ____2____ ____2____ ___________5____________ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x30 0x31 0x31 0x31 0x30 0x31 0x30 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '0' '1' '1' '1' '0' '1' '0' '^' '^' '\r' '\n'
错误返回帧
帧头 设备地址 功能代码 错误代码 LRC校验 结束符
字节 _1__ ____2____ ____2____ ____2____ ____2____ ____2____
HEX 0x3A 0x31 0x36 0x38 0x31 0x31 0x30 0x^^ 0x^^ 0x0D 0x0A
ASC ':' '1' '6' '8' '1' '1' '0' '^' '^' '\r' '\n'
注意:0x^^代表实际运算的校验和, '^'表示对应的校验和的ASCII表达方式
*******************************************************************************/
/*******************************************************************************
函数名: COM_ReadBitWait
描 述: 读位等待函数,执行该函数后可立即返回执行结果
输 入: byAddr 选用的下位机地址,如1,2等
pabyBitResult 返回读取位或位域的首地址,存放值为16进制格式,如0x01,0x00
pszDecTag 读取位的信息TAG,如M38.6,详见通讯协议的方式
dwSize 读取的位的个数
输 出: pabyBitResult 存入读取的结果
返回值: INT32S 类型,其值表示函数的执行结果,为正数时表示读取的位的个数,
否则表示执行的错误代码,
*******************************************************************************/
INT32S WINAPI COM_ReadBitWait(INT8U byAddr, INT8U *pabyBitResult, const INT8S *pszDecTag, INT32U dwSize)
{
INT32S result = ECOM_NOERROR; //错误返回值
INT32S iRecvBitNum = 0; //正确返回读取的位的个数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -