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

📄 uartwaitfunc.c

📁 Modbus串口通讯协议通讯源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
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 + -