⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uartwaitfunc.c

📁 Modbus串口通讯协议通讯源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    return  result;
}
/*******************************************************************************
函数名: SingleFrameWriteByteWait
描  述: 单帧写字节函数,执行该函数后将数据写入指定字节地址
输  入: byAddr         选用的下位机地址,如1,2等
        pabyByteInput   存放写入数据的首地址,该参数应传递数据格式的参数
        pszDecTag       写字节的信息TAG,详见通讯协议的方式
        dwSize          写字节的个数
输  出: 无
返回值: 写入正确返回发送字节数,包括帧头和结尾符,否则表示执行的错误代码,
*******************************************************************************/
static SingleFrameWriteByteWait(INT8U byAddr, const INT8U *pabyByteInput, const INT8S *pszDecTag, INT32U dwSize)
{
    STC_TAG_COMMAND stcTagCmd;    //定义操作变量stcTagCmd
    INT32S result = ECOM_NOERROR; //错误返回值
    INT32S iSendByteNum;         //实际发送字节数
    INT32S iRecvTagLen = 0;      //返回桢的字节数

    /**********************************************************
    pszRecv指向接收到的桢数据, 开辟12字节空间
    **********************************************************/
    INT8U* pszRecv = (INT8U *)malloc(12);

    /**********************************************************
    检验传入参数的正确性,dwSize乘2是因为发送的字节数据,加17是
    因为桢长还要包括前缀和后缀的长度,及tag的6字节
    **********************************************************/
    if ((pabyByteInput == NULL) || (dwSize * 2 + 17 > g_iMaxFrameSize))
    {
        result =  ECOM_BADPARA;   //检验传入参数的正确性;
        goto  SingleWriteByteError;     //错误返回
    }

    if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_WRITE))
    {
        result = ECOM_BADPARA;   //判断TAG是否有效,有效解码至stcTagCmd.stcTag;
        goto   SingleWriteByteError;
    }

    if (ECOM_NOERROR == result)  //如果参数无错,则发送数据桢;发送正确返回发送字节数
    {
        stcTagCmd.byRange = dwSize;

        iSendByteNum = SendWriteByteCommand(&stcTagCmd, byAddr, pabyByteInput);
    }

    if (iSendByteNum >= 0)       //数据桢发送正确,则接收数据桢
    {
        #ifndef  FORTESTONLY     //测试编译开关
          iRecvTagLen = GetModbusFrame(pszRecv);
        #else
          extern INT8U  testbuf[50];
          extern INT32S testsize;
          iRecvTagLen = testsize;
          pszRecv = testbuf;
        #endif
    }
    else
    {
        result = iSendByteNum;   //发送不正确,错误代码给result
        goto  SingleWriteByteError;
    }

    if (iRecvTagLen < 0)
    {
        result = iRecvTagLen;   //接收不正确,错误代码给result
        goto   SingleWriteByteError;
    }
    else                         //数据桢接收正确,则进行校验
    {
        result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_CHAR_WR, dwSize);
    }

    if (ECOM_NOERROR == result)  //校验正确,
    {
        free(pszRecv);          //释放开辟的资源
        return  iSendByteNum;
    }
    else
    {
        goto   SingleWriteByteError;
    }

SingleWriteByteError:
    free(pszRecv);             //释放开辟的资源
    return  result;
}

 /*******************************************************************************
写字节通讯帧, 协议为MODBUS协议ASCII方式

协议组成(':' + 设备地址 + 功能代码(0x04) + 字节TAG地址 + 写入字节数 + 写入值
             + LRC校验 + 结束符)

EXAMPLE:  设备地址 = 22(DEC), TAG = MB14(DEC),写入连续4个字节,  写入值为十六进制
          {0x12, 0x31, 0x33, 0xA5},  若通讯错误,设错误代码为15(DEC)

发送帧
     帧头 设备地址  功能代码  TAG  MB14(DEC) = MB000E(HEX) 写入字节数
字节 _1__ ____2____ ____2____ ______________6______________ ____2____
HEX  0x3A 0x31 0x36 0x30 0x34 0x4E 0x42 0x30 0x30 0x30 0x45 0x30 0x34
ASC  ':'  '1'   '6'  '0' '4'   'M' 'B'  '0'   '0'  '0'  'E'   '0' '4'
      写入值(占用字节数为写入字节数 * 2)      LRC校验     结束符
     __________________8____________________  ____2____  ____2____
HEX  0x31 0x32 0x33 0x31 0x33 0x33 0x41 0x35  0x^^ 0x^^  0x0D 0x0A
ASC  '1'  '2'  '3'  '1'  '3'  '3'   'A'  '5'   '^'  '^'  '\r' '\n'

正常返回帧
     帧头 设备地址  功能代码   LRC校验     结束符
字节 _1__ ____2____ ____2____  ____2____   ____2____
HEX  0x3A 0x31 0x36 0x30 0x34  0x^^ 0x^^   0x0D 0x0A
ASC  ':'  '1'   '6'  '0' '4'   '^' '^'    '\r' '\n'

错误返回帧
     帧头 设备地址  功能代码  错误代码    LRC校验     结束符
字节 _1__ ____2____ ____2____ ____2____  ____2____   ____2____
HEX  0x3A 0x31 0x36 0x38 0x34 0x30 0x46  0x^^ 0x^^   0x0D 0x0A
ASC  ':'  '1'   '6'  '8' '4'   '0'  'F'   '^' '^'    '\r' '\n'

注意:0x^^代表实际运算的校验和, '^'表示对应的校验和的ASCII表达方式
*******************************************************************************/
/*******************************************************************************
函数名: COM_WriteByteWait
描  述: 写字节等待函数,执行该函数后将数据写入指定字节地址
输  入: byAddr         选用的下位机地址,如1,2等
        pabyByteInput   存放写入数据的首地址,参数以16进制格式输入,如0x12,0xAB
        pszDecTag       写字节的信息TAG,如MB18,详见通讯协议的方式
        dwSize          写字节的个数
输  出: 无
返回值: 写入正确返回ECOM_NOERROR,否则表示执行的错误代码,
*******************************************************************************/
INT32S WINAPI COM_WriteByteWait(INT8U byAddr, const INT8U *pabyByteInput,const INT8S *pszDecTag, INT32U dwSize)
{
    INT32S result = ECOM_NOERROR; //错误返回值
    INT32S iSendByteNum = 0;      //实际发送字节数

    INT32U dwWriteNum = 1;        //要写的次数
    INT32U dwWriteNumBak;
    INT32U dwSingleWriteSize;
    INT32S startadd;
    BOOL MultWrite = FALSE;


    /*存操作的tag,以便修改*/
    INT8S *DecTagBak = (INT8S *)malloc(10);
    sscanf(pszDecTag + 2, "%d", &startadd);
    sprintf(DecTagBak,"%C%C%01d",*pszDecTag, *(pszDecTag + 1), startadd);
    /**********************************************************
    检验传入参数的正确性
    **********************************************************/
    if (pabyByteInput == NULL)
    {
        result =  ECOM_BADPARA;             //检验传入参数的正确性;
        goto  WriteByteError;               //错误返回
    }
    if (g_iMaxFrameSize - 17 < 2)           //帧过小,不能完成单帧发送一个字节
    {
      result = ECOM_TOOSMALLSIZE;
      goto  WriteByteError;
    }
    if (dwSize * 2 + 17 > g_iMaxFrameSize)  //多帧写
    {
      MultWrite = TRUE;
      if (dwSize % ((g_iMaxFrameSize - 17) / 2))
        dwWriteNum = dwSize / ((g_iMaxFrameSize - 17) / 2) + 1;
      else
        dwWriteNum = dwSize / ((g_iMaxFrameSize - 17) / 2);
    }
    dwWriteNumBak = dwWriteNum;

    while (dwWriteNum != 0)
    {
      /*确定每帧写的个数*/
      if (MultWrite)
      {
        if (dwWriteNum > 1)      //多帧写
        {
          dwSingleWriteSize = (g_iMaxFrameSize - 17) / 2;
        }
        else                    //最后一次发写命令
        {
          dwSingleWriteSize = dwSize - (dwWriteNumBak - 1) * ((g_iMaxFrameSize - 17) / 2);
        }
      }
      else                      //单帧写
      {
        dwSingleWriteSize = dwSize;
      }
      /*调用单帧写函数*/
      result = SingleFrameWriteByteWait(byAddr, pabyByteInput + iSendByteNum, DecTagBak, dwSingleWriteSize);
      iSendByteNum = iSendByteNum + ((result - 17) / 2);

      if (result > 0)           //写正确,
      {
        if (MultWrite)
        {
          if (dwWriteNum > 1)   //调用TagChange()函数,更改TAG地址
          {
            result = TagChange(DecTagBak, COMMAND_CHAR_WR);
            if (result == 0)
            {
             result = ECOM_BADPARA;
             goto WriteByteError;
            }
          }
        }
        dwWriteNum--;
        result = ECOM_NOERROR;
      }
      else
      {
        goto   WriteByteError;
      }
    }                         //写字节结束
    free(DecTagBak);          //释放开辟的资源
    return  ECOM_NOERROR;

WriteByteError:
    free(DecTagBak);          //释放开辟的资源
    return  result;
}

/*******************************************************************************
函数名: SingleFrameWriteWordWait
描  述: 单帧写字函数,执行该函数后将数据写入指定字地址
输  入: byAddr         选用的下位机地址,如1,2等
        pawWordInput    存放写入数据的首地址,该参数应传递数据格式的参数
        pszDecTag       写字的信息TAG,详见通讯协议的方式
        dwSize          写字的个数
输  出: 无
返回值: 写入正确返回发送字节数,包括帧头和结束符,否则表示执行的错误代码,
*******************************************************************************/
static SingleFrameWriteWordWait(INT8U byAddr, const INT16U *pawWordInput, const INT8S *pszDecTag, INT32U dwSize)
{
    STC_TAG_COMMAND stcTagCmd;    //定义操作变量stcTagCmd
    INT32S result = ECOM_NOERROR; //错误返回值
    INT32S iSendWordNum;         //实际发送字数
    INT32S iRecvTagLen = 0;      //返回桢的字节数

    /**********************************************************
    pszRecv指向接收到的桢数据, 开辟12字节空间
    **********************************************************/
    INT8U* pszRecv = (INT8U *)malloc(12);

    /**********************************************************
    检验传入参数的正确性,dwSize乘4是因为发送的字数据,加17是
    因为桢长还要包括前缀和后缀的长度,及tag的6字节
    **********************************************************/
    if ((pawWordInput == NULL) || (dwSize * 4 + 17 > g_iMaxFrameSize))
    {
        result =  ECOM_BADPARA;         //检验传入参数的正确性;
        goto  SingleWriteWordError;     //错误返回
    }

    if (!IsDecodeSuccess(pszDecTag, &(stcTagCmd.stcTag), TAG_COMMAND_WRITE))
    {
        result = ECOM_BADPARA;   //判断TAG是否有效,有效解码至stcTagCmd.stcTag;
        goto   SingleWriteWordError;
    }

    if (ECOM_NOERROR == result)  //如果参数无错,则发送数据桢;发送正确返回发送字节数
    {
        stcTagCmd.byRange = dwSize;

        iSendWordNum = SendWriteWordCommand(&stcTagCmd, byAddr, pawWordInput);
    }

    if (iSendWordNum >= 0)       //数据桢发送正确,则接收数据桢
    {
        #ifndef  FORTESTONLY     //测试编译开关
          iRecvTagLen = GetModbusFrame(pszRecv);
        #else
          extern INT8U  testbuf[50];
          extern INT32S testsize;
          iRecvTagLen = testsize;
          pszRecv = testbuf;
        #endif
    }
    else
    {
        result = iSendWordNum;   //发送不正确,错误代码给result
        goto  SingleWriteWordError;
    }

    if (iRecvTagLen < 0)
    {
        result = iRecvTagLen;   //接收不正确,错误代码给result
        goto   SingleWriteWordError;
    }
    else                         //数据桢接收正确,则进行校验
    {
        result = ModbusFrameCheck(pszRecv, iRecvTagLen, byAddr, COMMAND_SHORT_WR, dwSize);
    }

    if (ECOM_NOERROR == result)  //校验正确,
    {
        free(pszRecv);          //释放开辟的资源
        return  iSendWordNum;
    }
    else
    {
        goto   SingleWriteWordError;
    }

SingleWriteWordError:
    free(pszRecv);             //释放开辟的资源
    return  result;
}
/*******************************************************************************
写字通讯帧, 协议为MODBUS协议ASCII方式

协议组成(':' + 设备地址 + 功能代码(0x06) + 字TAG地址 + 写入字数 + 写入值
             + LRC校验 + 结束符)

EXAMPLE:  设备地址 = 22(DEC), TAG = MW14(DEC),写入连续2个字,  写入值为十六进制
          {0x1231, 0x33A5},  若通讯错误,设错误代码为15(DEC)

发送帧
     帧头 设备地址  功能代码  TAG  MW14(DEC) = MW000E(HEX) 写入字数
字节 _1__ ____2____ ____2____ ______________6______________ ____2____
HEX  0x3A 0x31 0x36 0x30 0x36 0x4E 0x57 0x30 0x30 0x30 0x45 0x30 0x32
ASC  ':'  '1'   '6'  '0' '6'   'M' 'W'  '0'   '0'  '0'  'E'   '0' '2'
      写入值(占用字节数 = 写入字数 * 4 )      LRC校验     结束符
     __________________8____________________ 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -