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

📄 uartwaitfunc.c

📁 Modbus串口通讯协议通讯源代码
💻 C
📖 第 1 页 / 共 5 页
字号:

*******************************************************************************/
#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 + -