基于STM32的ModbusRtu通信--终极Demo设计(二)

本文介绍了STM32微控制器上实现Modbus RTU通信的详细过程,包括主发从收的串口接收方案、CRC校验、数据封包与解析接口的详细代码示例,以及测试命令的注册与回调接口。通过这些内容,读者可以了解如何在STM32系统中构建有效的Modbus通信系统。
摘要由CSDN通过智能技术生成

在这里插入图片描述

[--------------点击下面,进入总目录索引--------------]
STM32系列精品Demo集 - 总目录


图示:MosbusRtu通信效果演示
在这里插入图片描述


一、方案设计


  • 1.1、Uart接收方案
        Modbus通信采用主发从收的方式进行通信,所以本示例Demo采用[主发从收->阻塞式->数据定长]的方案,方案实现细节参考3. STM32裸机串口接收方案

  • 1.2、通信接口方案设计

    ​ 本Demo大的方向上有两个接口,一是数据封包接口,二是数据解析接口,为了使接口更加清晰明了,每个功能都有各自独立的数据封包接口,所有的数据解析公用一个接口去做处理。

    //数据封包接口
    int ModbusRtuPacket01(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned short usRegNum, unsigned char *pucReqString, unsigned int *piNum);
    
    int ModbusRtuPacket02(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned short usRegNum, unsigned char *pucReqString, unsigned int *piNum);
    
    int ModbusRtuPacket03(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned short usRegNum, unsigned char *pucReqString, unsigned int *piNum);
    
    int ModbusRtuPacket04(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned short usRegNum, unsigned char *pucReqString, unsigned int *piNum);
    
    int ModbusRtuPacket05(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned char ucWriteValue,unsigned char *pucReqString, unsigned int *piNum);
    
    int ModbusRtuPacket06(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned short usRegValue,unsigned char *pucReqString, unsigned int *piNum);
    //数据解析接口
    int ModbusRtuResponse(char cModbusMode, int iReadDataLen, unsigned int uiTimeOutMs,unsigned char *pucSlaveId, unsigned char *pucFunction, unsigned char *pucData, int *iDataLen);
    

二、通信接口详解


2.1、CRC校验接口

static const unsigned char g_aucCrcLow[] =
{
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};

/* Table of CRC values for low-order byte */
static const unsigned char g_aucCrcHigh[] =
{
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
    0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
static int CrcError(unsigned char *pucBuf, int iLen)
{
    int i;
    unsigned char ucCrcHigh, ucCrcLow;
    unsigned char ucIndex = 0;

    if (NULL == pucBuf || iLen < 0)
    {
        ModbusUartPrintf("Wrong Parameter!");
        return DRIVER_ERROR_PARAMETER;
    }
    ucCrcHigh = 0xff;
    ucCrcLow  = 0xff;
    for (i = 0; i < iLen - 2; i++)
    {
        ucIndex   = ucCrcLow ^ pucBuf[i];
        ucCrcLow  = ucCrcHigh ^ g_aucCrcLow[ucIndex];
        ucCrcHigh = g_aucCrcHigh[ucIndex];
    }
    if ((ucCrcLow  != pucBuf[iLen - 2]) ||
            (ucCrcHigh != pucBuf[iLen - 1]))
    {
        ModbusUartPrintf("CRC Error!");
        return DRIVER_ERROR_MODBUS_CRC;
    }
    return DRIVER_SUCCESS;
}

2.2、数据组包接口示例(03)

/***********************************************************************
 * 函数名称: ModbusRtuPacket03
 * 功能描述: 组包读保持存器(A0)点的协议帧
 * 输入参数:
 * 输出参数:
 * 返 回 值:
 			iRspLen :Modbus从机应当响应的字节个数
 *  其   它:
 ***********************************************************************/
int ModbusRtuPacket03(unsigned char ucSlave, char cModbusMode, unsigned short usStartAddr, unsigned short usRegNum,
                      unsigned char *pucReqString, unsigned int *piNum)
{
    int iNum;
    int iRspLen = 0;
    if (NULL == pucReqString || NULL == piNum)
    {
        ModbusUartPrintf("Wrong Parameter!");
        return DRIVER_ERROR_PARAMETER;
    }

    if ((cModbusMode != MODBUS_RTU))    // only support RTU.
    {
        ModbusUartPrintf("Wrong Parameter!");
        return DRIVER_ERROR_MODBUS_MODE;
    }

    if (MODBUS_RTU == cModbusMode)
    {
        iNum = 0;
        pucReqString[iNum++] = ucSlave;
        pucReqString[iNum++] = READ_MUL_REG;
        pucReqString[iNum++] = usStartAddr >> 8;  //register start address (MSB)
        pucReqString[iNum++] = usStartAddr & 0xFF;     //(LSB)
        pucReqString[iNum++] = usRegNum >> 8;  //register number: number =usPointNum
        pucReqString[iNum++] = usRegNum & 0xFF;

        //insert CRC check code
        CrcInsert(pucReqString, iNum);
        iNum += 2;
    }

    *piNum = iNum;  //the packeted data length
    iRspLen = usRegNum * 2;
    return iRspLen + READ_PKG_RSP_LEN;
}

2.3、数据解析接口示例

int ModbusRtuResponse(char cModbusMode, int iReadDataLen, unsigned int uiTimeOutMs,
                      unsigned char *pucSlaveId, unsigned char *pucFunction, unsigned char *pucData, int *iDataLen)
{
    unsigned char *pucTmp = NULL;
    int iLen = 0, iByteCount, iData, iVal, iTmp;
    unsigned char aucBuffer[MODBUS_MAX_RESPONSE_LENGTH] = {0};
    int iSlave, iFunction;
    unsigned char ucSlave, ucFunction;
    unsigned char *pucStartBuf = NULL;

    // check parameter.
    if (NULL == pucSlaveId || NULL == pucFunction || NULL == pucData || NULL == iDataLen)
    {
        ModbusUartPrintf("Wrong Parameter!");
        return DRIVER_ERROR_PARAMETER;
    }
    if ((cModbusMode != MODBUS_ASCII) && (cModbusMode != MODBUS_RTU))
    {
        ModbusUartPrintf("Wrong Parameter!");
        return DRIVER_ERROR_MODBUS_MODE;
    }

    // init data.
    *iDataLen = 0;

    //read from device
    iTmp = ModbusUartDataRead(aucBuffer, iReadDataLen, uiTimeOutMs);
    if (iTmp < 0)
    {
        ModbusUartPrintf("DrivCommDeviceDataRead failed. and return=%d", iTmp);
        ControlUartIrqEnable(3, DISABLE);
        ModbusUartCleanCache();
        ControlUartIrqEnable(3, ENABLE);
        return iTmp;
    }

    aucBuffer[iTmp] = '\0';  //end the request string
    ModbusUartPrintf("Read(%d):", iTmp);
    //此处将modbus回过来的数据进行了打印。
    for (iLen = 0; iLen < iTmp; iLen++)
    {
        DataPrintf("0x%02X ", aucBuffer[iLen]);
    }
    DataPrintf("\r\n");

    if (MODBUS_ASCII == cModbusMode)
    {
        pucTmp = (unsigned char *) strchr((const char *) aucBuffer, ':');
        if (NULL == pucTmp)
        {
            ModbusUartPrintf("[Modbus]Modbus Wrong Data Format, not find ':'.");
            return DRIVER_ERROR_MODBUS_WRONG_DATA_FORMAT;
        }
        pucStartBuf = pucTmp;
        iLen = 0;
        iLen++;
        sscanf((char *) &pucTmp[iLen], "%02X", &iSlave);
        iLen += 2;
        sscanf((char *) &pucTmp[iLen], "%02X", &iFunction);
        iLen += 2;
        ModbusUartPrintf("[Modbus]iSlave:%d, iFunction:%d.", iSlave, iFunction);
        *pucSlaveId  = (unsigned char)iSlave;
        *pucFunction = (unsigned char)iFunction;
        switch (iFunction)
        {
            case 2:
            case 3: //  response :data-length  h-data l-date ...
            case 4:
                sscanf((char *) &pucTmp[iLen], "%02X", &iByteCount);
                iLen += 2;
                ModbusUartPrintf("[Modbus]iByteCount:%d.", iByteCount);
                for (iData = 0; iData < iByteCount; iData++)
                {
                    sscanf((const char *) &pucTmp[iLen], "%02X", &iVal);
                    iLen += 2;
                    pucData[iData] = iVal;
                }
                iTmp = LrcError((char *)pucStartBuf, iLen); //lrc check
                if (iTmp < 0)
                {
                    ModbusUartPrintf("[Modbus]LrcError check failed(%d).", iTmp);
                    return DRIVER_ERROR_MODBUS_LRC;
                }
                *iDataLen = iByteCount;
                break;

            case 5:  // for MX28A and AO4A.
            case 6:  //function code :0x06   response :h-addr l-addr h-data l-date
            case 16: //0x10:  response :h-addr l-addr h-register numner l-register number
                for (iData = 0; iData < 4; iData++)
                {
                    sscanf((const char *) &pucTmp[iLen], "%02X", &iVal);
                    iLen += 2;
                    pucData[iData] = iVal;
                }
                iTmp = LrcError((char *)pucStartBuf, iLen); //lrc check
                if (iTmp < 0)
                {
                    ModbusUartPrintf("[Modbus]LrcError check failed(%d).", iTmp);
                    /* [add by jiangfeng.zhang, 2021-07-01] :数据接收出错,清缓存*/
#if 1
                    ControlUartIrqEnable(3, DISABLE);
                    ModbusUartCleanCache();
                    ControlUartIrqEnable(3, ENABLE);
#endif
                    return DRIVER_ERROR_MODBUS_LRC;
                }
                *iDataLen = iByteCount;
                break;

            default:
                ModbusUartPrintf("[Modbus]Unsupport function(%d).", iFunction);
                return DRIVER_ERROR_MODBUS_UNSUPPORT_FUNCTION;
        }
    }
    else if (MODBUS_RTU == cModbusMode)
    {
        iLen       = 0;
        ucSlave     = aucBuffer[iLen++];

        ucFunction  = aucBuffer[iLen++];

        *pucSlaveId  = ucSlave;
        *pucFunction = ucFunction;
        switch (ucFunction)
        {
            //这块区分,当时读PLC,功能码为03 4 254: 数据处理分支。
            // 回的数据不包含设备地址,仅仅包含读取到的数据字节个数。
            case 1:
            case 2:
            case 3:
            case 4:
            case 254: // 0xFE
                iByteCount = aucBuffer[iLen++];
                memcpy(pucData, &aucBuffer[iLen], iByteCount); //ByteCount
                iLen += (iByteCount + 2); // with 2 bytes crc lens
                iTmp = CrcError(aucBuffer, iLen);  //crc check
                if (iTmp < 0)
                {
                    ModbusUartPrintf("[Modbus]LrcError check failed(%d).", iTmp);
                    return DRIVER_ERROR_MODBUS_LRC;
                }
                *iDataLen = iByteCount; // only return data lens
                break;

            //这块是写PLC,功能码为5 6 16,PLC回执的数据,回执数据里面包含了寄存器地址
            case 5:
            case 6:  //function code :0x06   response :h-addr l-addr h-data l-date
            case 16: //0x10:  response :h-addr l-addr h-register numner l-register number
                memcpy(pucData, &aucBuffer[iLen], 4);
                iLen += (4 + 2); // (data length)+2(crc)
                iTmp = CrcError(aucBuffer, 8);  //crc check
                if (iTmp < 0)
                {
                    ModbusUartPrintf("[Modbus]LrcError check failed(%d).", iTmp);
                    return DRIVER_ERROR_MODBUS_LRC;
                }
                *iDataLen = 4;
                break;
            case 0xB8:
                memcpy(pucData, &aucBuffer[iLen], 9);   //ByteCount + 2(CRC)
                iTmp = CrcError(aucBuffer, 11);         //crc check
                if (iTmp < 0)
                {
                    ModbusUartPrintf("[Modbus]LrcError check failed(%d).", iTmp);
                    return DRIVER_ERROR_MODBUS_LRC;
                }
                *iDataLen = 7;
                break;
            default:
                ModbusUartPrintf("[Modbus]Unsupport function(%d).", iFunction);
                return DRIVER_ERROR_MODBUS_UNSUPPORT_FUNCTION;
        }
    }

    return DRIVER_SUCCESS;
}

2.4、通信测试

/***********************************************************************
 * 函数名称: TestModbusRtu
 * 功能描述: Modbus Uart测试代码
 * 输入参数:
 * 输出参数:
 * 返 回 值:
 *  其   它:
 ***********************************************************************/
int TestModbusRtu(void)
{
    int iRet = 0;
    int iRspLen = 0;
    int iLen;
#define TEST_DEV_ID 0X01
    unsigned char ucSlaveId;
    unsigned char ucFunction;
    //发送数组
    unsigned char aucSendBuf[20];
    unsigned int  uiReqMsgLen = 0;
    //接收数据
    unsigned char aucRecvBuf[20];
    unsigned int  iRspMsgLen = 0;

    iRspLen = ModbusRtuPacket03(TEST_DEV_ID, MODBUS_RTU, 0X00, 1, aucSendBuf, &uiReqMsgLen);
    iRet = ModbusUartDataWrite(3, aucSendBuf, uiReqMsgLen);
    iRet = ModbusRtuResponse(
               MODBUS_RTU,
               iRspLen,  //设备地址+  功能码+字节数目+数据+crc = 1+1+1+2+2 = 7
               UART_READ_TIME_OUT,
               &ucSlaveId,
               &ucFunction,
               aucRecvBuf,
               &iRspMsgLen   // 数据域中除数据地址外数据位有几个字节。
           );

    for (iLen = 0; iLen < iRspMsgLen; iLen++)
    {
        DataPrintf("0x%02X ", aucRecvBuf[iLen]);
    }
    DataPrintf("\r\n");
}

三、注册LetterShell测试命令


3.1、注册OEM命令

/******************************************************************************
* 注册Modbus RTU测试指令
******************************************************************************/
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), modbus01, TestModbusFun01, modbus01 [slave id](1) address(2) regnum(2));
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), modbus02, TestModbusFun02, modbus02 [slave id](1) address(2) regnum(2));
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), modbus03, TestModbusFun03, modbus03 [slave id](1) address(2) regnum(2));
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), modbus04, TestModbusFun04, modbus04 [slave id](1) address(2) regnum(2));
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), modbus05, TestModbusFun05, modbus05 [slave id](1) address(2) writeValue(1));
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), modbus06, TestModbusFun06, modbus06 [slave id](1) address(2) writeValue(2));
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), unitmodbustest, TestModbusRtu,unitmodbustest in while(1));

3.2、LetterShll测试命令的回调接口

/***********************************************************************
 * 函数名称: TestModbusFun03
 * 功能描述: 读AO
 * 输入参数: 命令字(1) + slaveid(1)+start address(2)+regnum(2)  = 6
 * 输出参数:
 * 返 回 值:
 *  其   它:
 ***********************************************************************/
int TestModbusFun03(int argc, char *agrv[])
{
    int iRet = 0;
    int iRspLen = 0;
    int iLen;
    unsigned char ucSlaveId;
    unsigned char ucFunction;
    //发送数组
    unsigned char aucSendBuf[20];
    unsigned int  uiReqMsgLen = 0;
    //接收数据
    unsigned char aucRecvBuf[20];
    unsigned int  iRspMsgLen = 0;
    unsigned short usStartAddress = 0;
    unsigned short usRegNum = 0;
    unsigned char  ucTemData_H = 0;
    unsigned char  ucTemData_L = 0;

    if (argc != 6)
    {
        ModuleShellPrintf("[user read ao]:\r\n               modbus03  + slaveid(1) + start address(2) + regnum(2).\r\n");
        ModuleShellPrintf("[exzample]:\r\n               [modbus03] [01] [00 00] [00 01].\r\n\r\n\r\n");
        return -1;
    }
    else
    {
        iRet = ZipStrToHex(agrv[1], strlen(agrv[1]), &ucSlaveId);
        if (iRet < 0)
        {
            return -1;
        }
        iRet = ZipStrToHex(agrv[2], strlen(agrv[2]), &ucTemData_H);
        if (iRet < 0)
        {
            return -1;
        }
        iRet = ZipStrToHex(agrv[3], strlen(agrv[3]), &ucTemData_L);
        if (iRet < 0)
        {
            return -1;
        }
        usStartAddress = ((ucTemData_H << 8) & 0XFF00) | (ucTemData_L);
        iRet = ZipStrToHex(agrv[4], strlen(agrv[4]), &ucTemData_H);
        if (iRet < 0)
        {
            return -1;
        }
        iRet = ZipStrToHex(agrv[5], strlen(agrv[5]), &ucTemData_L);
        if (iRet < 0)
        {
            return -1;
        }
        usRegNum = ((ucTemData_H << 8) & 0XFF00) | (ucTemData_L);
        ModuleShellPrintf("[read ao][slaveid]:0x%x [start address]:0x%x [regnum]:0x%x.\r\n\r\n", ucSlaveId, usStartAddress, usRegNum);
    }
    /***********************************************************************************************/
    iRspLen = ModbusRtuPacket03(ucSlaveId, MODBUS_RTU, usStartAddress, usRegNum, aucSendBuf, &uiReqMsgLen);

    iRet = ModbusUartDataWrite(3, aucSendBuf, uiReqMsgLen);

    iRet = ModbusRtuResponse(
               MODBUS_RTU,
               iRspLen,  //设备地址+  功能码+字节数目+数据+crc = 1+1+1+2+2 = 7
               UART_READ_TIME_OUT,
               &ucSlaveId,
               &ucFunction,
               aucRecvBuf,
               &iRspMsgLen   // 数据域中除数据地址外数据位有几个字节。
           );

    for (iLen = 0; iLen < iRspMsgLen; iLen++)
    {
        ModuleShellPrintf("0x%02X ", aucRecvBuf[iLen]);
    }
    if (iRspMsgLen <= 0)
    {
        ModuleShellPrintf("[ERROR] no response \r\n");
    }
    ModuleShellPrintf("\r\n\r\n\r\n");
    /***********************************************************************************************/
    return 0;
}

附录:Demo源码

https://gitee.com/jiangfengzhang/stm32-f4-uart-recv-demo
在这里插入图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值