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

📄 modbus_rtu.c

📁 ucos下的modbus-rtu处理程序,支持1,2,3,4,5,16,15,16 号功能码
💻 C
📖 第 1 页 / 共 2 页
字号:
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 2号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultDI(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, i, ui16Len;
    UCHAR ucTemp, ucByteNo, ucBitNo;
    tagMODREAD *tagpModRead;
    tagMODREADRESP *tagpModReadResp;
    
    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpModRead = (tagMODREAD *)ucpRevcBuff;            //接收缓冲区
    tagpModReadResp = (tagMODREADRESP *)ucpSendBuff;    //应答缓冲区
    
    tagpModReadResp -> ucSta = tagpModRead -> ucSta;    //站号
    tagpModReadResp -> ucFun = tagpModRead -> ucFun;    //功能码
    
    //寄存器起始地址
    ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
    if (ui16Temp >= DICOUNT) return (ADR_ERR);                      	//寄存器超出范围

    //寄存器数量	
    ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
    if ((ui16Len + ui16Temp) > DICOUNT) return(ADR_ERR);                //寄存器超出范围
    
    //返回数据字节数
    tagpModReadResp -> ucByteCnt = ui16Len / 8;
    if ((ui16Len % 8) != 0)
    {
        tagpModReadResp -> ucByteCnt += 1;
    }
    
    //内容处理
    i = 0;
    while (i < ui16Len)
    {
        //取寄存器位值
        ucByteNo = ui16Temp / 8;
        ucBitNo = ui16Temp % 8;
        ucTemp = ((ucDiReg[ucByteNo] >> ucBitNo) & 0x01);
        
        if ((i % 8) == 0)
        {
            tagpModReadResp -> ucMess[i / 8] = 0x00;
        }
        
        //填充到发送缓冲
        tagpModReadResp -> ucMess[i / 8] |= (ucTemp << (i % 8));

        i++;
        ui16Temp++;
    }
    
    //计算CRC
    ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
    
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
    tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;
    
    //发送缓冲长度
    *ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
    
    return (NO_ERR);
}

//****************************************************************************
//函数名称: Write_SingleCoil
//函数功能: 写单个线圈
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 5号功能码
//修改历史:
//****************************************************************************
UCHAR Write_SingleCoil(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, ui16Val;
    UCHAR ucByteNo, ucBitNo;
    tagWRSINGAL *tagpWrSingal;

    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpWrSingal = (tagWRSINGAL *)ucpRevcBuff;      //接收缓冲区
    
    //寄存器地址
    ui16Temp = tagpWrSingal -> ucAdrHi * 256ul + tagpWrSingal -> ucAdrLo;
    
    if (ui16Temp >= DOCOUNT) return (ADR_ERR);      //地址超出范围
        
    //寄存器值
    ui16Val = tagpWrSingal -> ucDatHi * 256ul + tagpWrSingal -> ucDatLo;
    
    if (ui16Val != 0x0000 && ui16Val != 0xff00) return (VAL_ERR);   //非法值
        
    //置线圈
    ucByteNo = ui16Temp / 8;
    ucBitNo = ui16Temp % 8;
    
    if (ui16Val == 0x00)
    {//OFF
        ucDoReg[ucByteNo] &= ~(0x01 << ucBitNo);
    }
    else
    {//ON
        ucDoReg[ucByteNo] |= (0x01 << ucBitNo);
    }
    
    memcpy((char *)ucpSendBuff, (char *)ucpRevcBuff, 8);
    
    //发送缓冲长度
    *ucpLen = 8;

    return (NO_ERR);
}

//****************************************************************************
//函数名称: Write_MultCoil
//函数功能: 写多个线圈
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 15号功能码
//修改历史:
//****************************************************************************
UCHAR Write_MultCoil(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, ui16Len, i;
    UCHAR ucTemp, ucByteNo, ucBitNo;
    tagWRMULTE *tagpWrMulte;
    tagMODREAD *tagpModRead;
    
    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpWrMulte = (tagWRMULTE *)ucpRevcBuff;        //接收缓冲区
    tagpModRead = (tagMODREAD *)ucpSendBuff;        //应答缓冲区
    
    tagpModRead -> ucSta = tagpWrMulte -> ucSta;    //站号
    tagpModRead -> ucFun = tagpWrMulte -> ucFun;    //功能码
    tagpModRead -> ucStarAdrHi = tagpWrMulte -> ucStarAdrHi; //起始寄存器
    tagpModRead -> ucStarAdrLo = tagpWrMulte -> ucStarAdrLo;
    tagpModRead -> ucCntHi = tagpWrMulte -> ucCntHi;         //寄存器数量
    tagpModRead -> ucCntLo = tagpWrMulte -> ucCntLo;
    
    //起始寄存器
    ui16Temp = tagpWrMulte -> ucStarAdrHi * 256ul + tagpWrMulte -> ucStarAdrLo;
    
    if (ui16Temp >= DOCOUNT) return (ADR_ERR);      //寄存器超出范围

    //寄存器数量
    ui16Len = tagpWrMulte -> ucCntHi * 256ul + tagpWrMulte -> ucCntLo;
    
    if ((ui16Temp + ui16Len) > DOCOUNT) return (ADR_ERR);   //寄存器超出范围
        
    //置DO
    i = 0;
    while (i < ui16Len)
    {
        //取寄存器位值
        ucTemp = ((tagpWrMulte -> ucMess[i / 8]) >> (i % 8)) & 0x01;
        
        ucByteNo = ui16Temp / 8;
        ucBitNo = ui16Temp % 8;

        //置DO
        if (ucTemp == 0x00)
        {//OFF
            ucDoReg[ucByteNo] &= ~(0x01 << ucBitNo);
        }
        else
        {//ON
            ucDoReg[ucByteNo] |= (0x01 << ucBitNo);
        }

        i++;
        ui16Temp++;
    }
    
    //计算CRC
    ui16Temp = CRC16((UCHAR *)tagpModRead, 6);
    
    tagpModRead -> ucCrcHi = ui16Temp / 256;
    tagpModRead -> ucCrcLo = ui16Temp;
    
    //发送缓冲长度
    *ucpLen = 8;
    
    return (NO_ERR);
}

//****************************************************************************
//函数名称: Write_SingleAO
//函数功能: 写单个保寄存器
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 6号功能码
//修改历史:
//****************************************************************************
UCHAR Write_SingleAO(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, ui16Val;
    tagWRSINGAL *tagpWrSingal;

    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpWrSingal = (tagWRSINGAL *)ucpRevcBuff;          //接收缓冲区
    
    //寄存器地址
    ui16Temp = tagpWrSingal -> ucAdrHi * 256ul + tagpWrSingal -> ucAdrLo;
    
    if (ui16Temp >= AOCOUNT) return (ADR_ERR);          //地址超出范围
        
    //寄存器值
    ui16Val = tagpWrSingal -> ucDatHi * 256ul + tagpWrSingal -> ucDatLo;

   	//if (ui16Val > 4095) return (VAL_ERR);   //非法值
  	      
    //写寄存器
    ui16AoReg[ui16Temp] = ui16Val;
    	
    memcpy((char *)ucpSendBuff, (char *)ucpRevcBuff, 8);
    
    //发送缓冲长度
    *ucpLen = 8;
    
    return (NO_ERR);
}

//****************************************************************************
//函数名称: Write_MultAO
//函数功能: 写多保持寄存器
//输入参数: UCHAR *ucpRevcBuff      接收缓冲
//          UCHAR *ucpSendBuff      发送缓冲
//          UCHAR *ucpLen           发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2007.05.13
//创 建 人: 罗德良
//参考文档:
//说    明: Modbus 16号功能码
//修改历史:
//****************************************************************************
UCHAR Write_MultAO(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
    UINT16 ui16Temp, ui16Len, i, ui16Val;
    tagWRMULTE *tagpWrMulte;
    tagMODREAD *tagpModRead;
    
    if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
    {
        return (CALL_ERR);
    }
    
    tagpWrMulte = (tagWRMULTE *)ucpRevcBuff;        //接收缓冲区
    tagpModRead = (tagMODREAD *)ucpSendBuff;        //应答缓冲区
    
    tagpModRead -> ucSta = tagpWrMulte -> ucSta;    //站号
    tagpModRead -> ucFun = tagpWrMulte -> ucFun;    //功能码
    tagpModRead -> ucStarAdrHi = tagpWrMulte -> ucStarAdrHi; //起始寄存器
    tagpModRead -> ucStarAdrLo = tagpWrMulte -> ucStarAdrLo;
    tagpModRead -> ucCntHi = tagpWrMulte -> ucCntHi;         //寄存器数量
    tagpModRead -> ucCntLo = tagpWrMulte -> ucCntLo;
    
    //起始寄存器
    ui16Temp = tagpWrMulte -> ucStarAdrHi * 256ul + tagpWrMulte -> ucStarAdrLo;
    
    if (ui16Temp >= AOCOUNT) return (ADR_ERR);      //寄存器超出范围

    //寄存器数量
    ui16Len = tagpWrMulte -> ucCntHi * 256ul + tagpWrMulte -> ucCntLo;
    
    if ((ui16Temp + ui16Len) > AOCOUNT) return (ADR_ERR);   //寄存器超出范围
        
    //置DO
    i = 0;
    while (i < ui16Len)
    {
        //取寄存器值
        ui16Val = tagpWrMulte -> ucMess[i * 2] * 256ul +
                  tagpWrMulte -> ucMess[i *2 + 1];
        
       	//if (ui16Val > 4095) return (VAL_ERR);           //寄存器值非法
		
        ui16AoReg[ui16Temp] = ui16Val;      //置寄存器
		
		if (ui16Temp == AO_OUT_ADR)
		{//AO0校正
			Write_AO(0, 0);
		}
		else if (ui16Temp == (AO_OUT_ADR + 1) )
		{//AO1校正
			Write_AO(1, 0);
		}
			
        i++;
        ui16Temp++;
    }
    
    //计算CRC
    ui16Temp = CRC16((UCHAR *)tagpModRead, 6);
    
    tagpModRead -> ucCrcHi = ui16Temp / 256;
    tagpModRead -> ucCrcLo = ui16Temp;
    
    //发送缓冲长度
    *ucpLen = 8;
    
    return (NO_ERR);
}

⌨️ 快捷键说明

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