当前位置:   article > 正文

使用libmodbus库在相同IP地址和端口上实现多个从机_libmodbus tcpd多个

libmodbus tcpd多个

前言

之前用Python写过Modbus服务端,用的是pymodbus库,但这个库里面使用的是协程,小弟水平不够,有些hold不住,所以决定用C++把之前那块代码给重构了

使用libmodbus库

  1. 将源代码拉下来放到项目里面,源代码下载地址:https://github.com/stephane/libmodbus

  2. 编译源代码,先执行./autogen.sh,再执行./configure

    在这里插入图片描述

  3. 编写CMakeLists.txt,链接的时候加入modbus库,这里是我的一个例子

    set(TARGET modbus_tcp_server_test)
    
    file(GLOB_RECURSE SRC *.cpp)
    
    include_directories(${PROJECT_SOURCE_DIR}/src)
    
    add_executable(${TARGET} ${SRC} ${PROJECT_SOURCE_DIR}/src/server/modbus_tcp_server.cpp)
    
    target_include_directories(${TARGET} PUBLIC 
        ${GTEST_INCLUDE_DIRS})
    message("project source dir: ${PROJECT_SOURCE_DIR}")
    target_link_libraries(${TARGET} PUBLIC gtest gtest_main pthread modbus)  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

实现modbus服务端

  1. 先定义modbus_tcp_server.h文件,将modbus_server封装成类,定义以下这些接口

    #pragma once
    #include <iostream>
    #include <vector>
    #include <mutex>
    #include "libmodbus/src/modbus-tcp.h"
    
    class ModbusTcpServer
    {
    public:
        ModbusTcpServer(int port, int slaveCount, bool debug);//端口号,从机个数,是否开启调试
        ~ModbusTcpServer();
        // 判断从机地址,寄存器地址是否合法
        bool isAddressValid(int slaveId, int address);
        // 线圈寄存器
        void setCoilValue(int slaveId, int address, uint8_t value);
        uint8_t getCoilValue(int slaveId, int address);
        // 离散输入寄存器
        void setDiscreteInputValue(int slaveId, int address, uint8_t value);
        uint8_t getDiscreteInputValue(int slaveId, int address);
        // 输入寄存器
        void setInputRegisterValue(int slaveId, int address, uint16_t value);
        uint16_t getInputRegisterValue(int slaveId, int address);
        // 保持寄存器
        void setHoldRegisterValue(int slaveId, int address, uint16_t value);
        uint16_t getHoldRegisterValue(int slaveId, int address);
        void recieveMessages();
        void start();
    
    private:
        modbus_t *_ctx;
        uint16_t *_registers; // 假设所有寄存器的值都是0
        int _slaveCount;
        std::mutex _slavemutex;
        int _errCount{0};
        int _modbusSocket{-1};
        std::vector<modbus_mapping_t *> _mappingList;
        bool _initialized{false};
        /*Mapping*/
        int _numBits{65535};
        int _numInputBits{65535};
        int _numRegisters{65535};
        int _numInputRegisters{65535};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
  2. 构造函数实现

    ModbusTcpServer::ModbusTcpServer(int port, int slaveCount, bool debug)
    {
        this->_slaveCount = slaveCount;
        _ctx = modbus_new_tcp("10.8.0.126", port);	//ip地址+端口号
        modbus_set_debug(_ctx, debug);
        if (_ctx == nullptr)
        {
            LOG_DEBUG("初始化ModbusServer错误!");
            throw -1;
        }
        if (_modbusSocket < 0)
        {
            _modbusSocket = modbus_tcp_listen(_ctx, 1);
        }
        // 设置从机0-slaveCount的地址映射
        for (int i = 0; i <= slaveCount; ++i)
        {
            /*设置线圈, 离散输入, 输入寄存器, 保持寄存器个数(数组元素个数))*/
            modbus_mapping_t *_mapping = modbus_mapping_new(_numBits, _numInputBits, _numInputRegisters, _numRegisters);
            _mappingList.push_back(_mapping);
            if (_mapping == nullptr)
            {
                LOG_ERROR("初始化ModbusMap失败!");
                modbus_free(_ctx);
                _initialized = false;
                return;
            }
        }
        _initialized = true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
  3. 析构函数实现

    ModbusTcpServer::~ModbusTcpServer()
    {
        // 清理资源
        modbus_close(_ctx);
        modbus_free(_ctx);
        for (auto &mapping : _mappingList)
        {
            modbus_mapping_free(mapping);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  4. 接收消息处理函数(重点)

    之前我在网上搜遍资料,都没有找到一个ip和端口号设置多个从机的教程,后面又看了一整天libmodbus的源码,发现源码里根本就没有处理多个从机地址的情况。最后我发现是要自己手动处理接收到报文里的从机地址,否则所有回复的报文都是一台从机的情况。

    这里支持多个主站连接的代码参考了这篇博客:https://blog.csdn.net/qq_38158479/article/details/120928043

    void ModbusTcpServer::recieveMessages()
    {
        // 初始化
        uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
        fd_set reads, cpy_reads;
        FD_ZERO(&reads);
        FD_SET(_modbusSocket, &reads);
        int fdMax = _modbusSocket;
        while (true)
        {
            memset(query, 0, sizeof(query));
            cpy_reads = reads;
            int fdNum = select(fdMax + 1, &cpy_reads, 0, 0, 0);
            if (fdNum == -1)
                break;
            else if (fdNum == 0)
                continue;
            for (int i = 0; i < fdMax + 1; i++)
            {
                if (FD_ISSET(i, &cpy_reads))
                {
                    if (i == _modbusSocket)
                    {
                        int clntSock = modbus_tcp_accept(_ctx, &_modbusSocket);
                        if ((_modbusSocket == -1) || (clntSock == -1))
                        {
                            LOG_ERROR("accept error!");
                            std::cerr << modbus_strerror(errno) << std::endl;
                            continue;
                        }
                        FD_SET(clntSock, &reads);
                        if (fdMax < clntSock)
                            fdMax = clntSock;
                    }
                    else
                    {
                        int ret = modbus_receive(_ctx, query);
                        if (ret == 0)
                        {
                            _errCount = 0;
                            continue;
                        }
                        else if (ret > 0)
                        {
                            _errCount = 0;
                            uint8_t slave = query[6]; // 获取收到问询的从机号
                            if (slave <= static_cast<uint8_t>(_slaveCount))
                            {
                                // 只回复当前从机的报文,从机号不符合就不回复
                                modbus_set_slave(_ctx, slave);
                                modbus_reply(_ctx, query, sizeof(query), _mappingList[slave]);
                            }
                        }
                        else
                        {
                            modbus_set_error_recovery(_ctx, MODBUS_ERROR_RECOVERY_NONE);
                            modbus_set_error_recovery(_ctx, MODBUS_ERROR_RECOVERY_LINK);
                            modbus_close(_ctx);
                            FD_CLR(i, &reads);
                            LOG_ERROR("报文错误,服务端断开连接!");
                            close(i);
                            _errCount++;
                        }
                        if (_errCount > 5)
                        {
                            _initialized = false;
                            break;
                        }
                    }
                }
            }
        }
        _initialized = false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
  5. 启动服务

    void ModbusTcpServer::start()
    {
        std::thread loop([this]()
                         {
            while (true)
            {
                if (_initialized)
                {
                    recieveMessages();
                }
                else
                {
                    _initialized = true;
                }
            } });
        // 将线程放在后台运行,防止阻塞主线程
        loop.detach();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  6. 判断从机地址和寄存器地址是否合法

    bool ModbusTcpServer::isAddressValid(int slaveId, int address)
    {
        if (slaveId < 0 || slaveId > _slaveCount)
        {
            LOG_ERROR(fmt::format("从机号错误, 从机号: {}!", slaveId));
            return false;
        }
        if (address > (_numRegisters - 1))
        {
            LOG_ERROR(fmt::format("寄存器地址错误, 寄存器地址: {}!", address));
            return true;
        }
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  7. 读写线圈寄存器

    void ModbusTcpServer::setCoilValue(int slaveId, int address, uint8_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _mappingList[slaveId]->tab_bits[address] = value;
    }
    
    uint8_t ModbusTcpServer::getCoilValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
            return 0;
        return _mappingList[slaveId]->tab_bits[address];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  8. 读写离散输入寄存器

    void ModbusTcpServer::setDiscreteInputValue(int slaveId, int address, uint8_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _mappingList[slaveId]->tab_input_bits[address] = value;
    }
    
    uint8_t ModbusTcpServer::getDiscreteInputValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
            return 0;
        return _mappingList[slaveId]->tab_input_bits[address];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  9. 读写输入寄存器

    void ModbusTcpServer::setInputRegisterValue(int slaveId, int address, uint16_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _mappingList[slaveId]->tab_registers[address] = value;
    }
    
    uint16_t ModbusTcpServer::getInputRegisterValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
    
            return 0;
        return _mappingList[slaveId]->tab_registers[address];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  10. 读写保持寄存器

    void ModbusTcpServer::setHoldRegisterValue(int slaveId, int address, uint16_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _slavemutex.lock();
        _mappingList[slaveId]->tab_registers[address] = value;
        _slavemutex.unlock();
    }
    
    uint16_t ModbusTcpServer::getHoldRegisterValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
            return 0;
        return _mappingList[slaveId]->tab_registers[address];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  11. modbus_tcp_server.cpp所有代码

    #include "modbus_tcp_server.h"
    #include <cstring>
    #include "log.h"
    
    ModbusTcpServer::ModbusTcpServer(int port, int slaveCount, bool debug)
    {
        this->_slaveCount = slaveCount;
        _ctx = modbus_new_tcp("10.8.0.126", port);
        // 设置从机地址
        modbus_set_slave(_ctx, 1);
        modbus_set_debug(_ctx, debug);
        if (_ctx == nullptr)
        {
            LOG_DEBUG("初始化ModbusServer错误!");
            throw -1;
        }
        if (_modbusSocket < 0)
        {
            _modbusSocket = modbus_tcp_listen(_ctx, 1);
        }
        // 设置从机0-slaveCount的地址映射
        for (int i = 0; i <= slaveCount; ++i)
        {
            /*设置线圈, 离散输入, 输入寄存器, 保持寄存器个数(数组元素个数))*/
            modbus_mapping_t *_mapping = modbus_mapping_new(_numBits, _numInputBits, _numInputRegisters, _numRegisters);
            _mappingList.push_back(_mapping);
            if (_mapping == nullptr)
            {
                LOG_ERROR("初始化ModbusMap失败!");
                modbus_free(_ctx);
                _initialized = false;
                return;
            }
        }
        _initialized = true;
    }
    
    ModbusTcpServer::~ModbusTcpServer()
    {
        // 清理资源
        modbus_close(_ctx);
        modbus_free(_ctx);
        for (auto &mapping : _mappingList)
        {
            modbus_mapping_free(mapping);
        }
    }
    
    bool ModbusTcpServer::isAddressValid(int slaveId, int address)
    {
        if (slaveId < 0 || slaveId > _slaveCount)
        {
            LOG_ERROR(fmt::format("从机号错误, 从机号: {}!", slaveId));
            return false;
        }
        if (address > (_numRegisters - 1))
        {
            LOG_ERROR(fmt::format("寄存器地址错误, 寄存器地址: {}!", address));
            return true;
        }
        return true;
    }
    
    void ModbusTcpServer::setCoilValue(int slaveId, int address, uint8_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _mappingList[slaveId]->tab_bits[address] = value;
    }
    
    uint8_t ModbusTcpServer::getCoilValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
            return 0;
        return _mappingList[slaveId]->tab_bits[address];
    }
    
    void ModbusTcpServer::setDiscreteInputValue(int slaveId, int address, uint8_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _mappingList[slaveId]->tab_input_bits[address] = value;
    }
    
    uint8_t ModbusTcpServer::getDiscreteInputValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
            return 0;
        return _mappingList[slaveId]->tab_input_bits[address];
    }
    
    void ModbusTcpServer::setInputRegisterValue(int slaveId, int address, uint16_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _mappingList[slaveId]->tab_registers[address] = value;
    }
    
    uint16_t ModbusTcpServer::getInputRegisterValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
    
            return 0;
        return _mappingList[slaveId]->tab_registers[address];
    }
    
    void ModbusTcpServer::setHoldRegisterValue(int slaveId, int address, uint16_t value)
    {
        if (!isAddressValid(slaveId, address))
            return;
        _slavemutex.lock();
        _mappingList[slaveId]->tab_registers[address] = value;
        _slavemutex.unlock();
    }
    
    uint16_t ModbusTcpServer::getHoldRegisterValue(int slaveId, int address)
    {
        if (!isAddressValid(slaveId, address))
            return 0;
        return _mappingList[slaveId]->tab_registers[address];
    }
    
    void ModbusTcpServer::recieveMessages()
    {
        // 初始化
        uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
        fd_set reads, cpy_reads;
        FD_ZERO(&reads);
        FD_SET(_modbusSocket, &reads);
        int fdMax = _modbusSocket;
        while (true)
        {
            memset(query, 0, sizeof(query));
            cpy_reads = reads;
            int fdNum = select(fdMax + 1, &cpy_reads, 0, 0, 0);
            if (fdNum == -1)
                break;
            else if (fdNum == 0)
                continue;
            for (int i = 0; i < fdMax + 1; i++)
            {
                if (FD_ISSET(i, &cpy_reads))
                {
                    if (i == _modbusSocket)
                    {
                        int clntSock = modbus_tcp_accept(_ctx, &_modbusSocket);
                        if ((_modbusSocket == -1) || (clntSock == -1))
                        {
                            LOG_ERROR("accept error!");
                            std::cerr << modbus_strerror(errno) << std::endl;
                            continue;
                        }
                        FD_SET(clntSock, &reads);
                        if (fdMax < clntSock)
                            fdMax = clntSock;
                    }
                    else
                    {
                        int ret = modbus_receive(_ctx, query);
                        if (ret == 0)
                        {
                            _errCount = 0;
                            continue;
                        }
                        else if (ret > 0)
                        {
                            _errCount = 0;
                            uint8_t slave = query[6]; // 获取收到问询的从机子号
                            if (slave <= static_cast<uint8_t>(_slaveCount))
                            {
                                modbus_set_slave(_ctx, slave);
                                modbus_reply(_ctx, query, sizeof(query), _mappingList[slave]);
                            }
                        }
                        else
                        {
                            modbus_set_error_recovery(_ctx, MODBUS_ERROR_RECOVERY_NONE);
                            modbus_set_error_recovery(_ctx, MODBUS_ERROR_RECOVERY_LINK);
                            modbus_close(_ctx);
                            FD_CLR(i, &reads);
                            LOG_ERROR("报文错误,服务端断开连接!");
                            close(i);
                            _errCount++;
                        }
                        if (_errCount > 5)
                        {
                            _initialized = false;
                            break;
                        }
                    }
                }
            }
        }
        _initialized = false;
    }
    void ModbusTcpServer::start()
    {
        std::thread loop([this]()
                         {
            while (true)
            {
                if (_initialized)
                {
                    recieveMessages();
                }
                else
                {
                    _initialized = true;
                }
            } });
        loop.detach();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212

单元测试

  1. 使用gtest进行单元测试,测试代码如下

    #include "server/modbus_tcp_server.h"
    #include "gtest/gtest.h"
    
    class ModbusTcpServerTest : public testing::Test
    {
    public:
        std::unique_ptr<ModbusTcpServer> server;
    
    protected:
        virtual void SetUp()
        {
            try
            {
                server = std::make_unique<ModbusTcpServer>(5020, 10, true); // 创建Modbus服务器实例,监听端口5020,配置10台从机
                server->start();                                            // 启动服务器
            }
            catch (const std::exception &e)
            {
                std::cerr << "Exception: " << e.what() << std::endl;
            }
        }
    };
    
    TEST_F(ModbusTcpServerTest, TestSetRegisterValue)
    {
        server->setHoldRegisterValue(1, 1, 100);
        ASSERT_EQ(100, server->getHoldRegisterValue(1, 1));
        
        server->setInputRegisterValue(1, 1, 200);
        ASSERT_EQ(200, server->getInputRegisterValue(1, 1));
        
        server->setCoilValue(1, 1, 1);
        ASSERT_TRUE(server->getCoilValue(1, 1));
        
        server->setDiscreteInputValue(1, 1, 1);
        ASSERT_TRUE(server->getDiscreteInputValue(1, 1));
    }
    
    int main()
    {
        testing::InitGoogleTest();
        return RUN_ALL_TESTS();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
  2. 测试结果
    在这里插入图片描述

使用网络调试助手测试

​ 为了判断我们多从机是否设置成功,我们可以用网络调试助手手发报文测试

  1. 为了让服务一直运行,我们可以把启动服务里的detach改成join,让其阻塞主线程
    在这里插入图片描述

  2. 用网络调试助手连接modbus服务端
    在这里插入图片描述

  3. 设置从机地址1,输入寄存器地址1的值为1

    报文格式:00 00 00 00 00 06 01 06 00 01 00 01

    重点看后面7位

    06:后面有6个值

    01:从机地址为1

    06:功能码,写输入寄存器

    00 01:输入寄存器的地址,4位16进制数,转换成10进制就是0-65535

    00 01:寄存器值,范围与上面寄存器地址范围相同
    在这里插入图片描述

    使用06功能码的时候,回复的值是一大串数据,这个没有影响

  4. 读取从机地址1,输入寄存器地址1的值,判断刚才手发的报文是否成功将值写入

    报文格式:00 00 00 00 00 06 01 03 00 01 00 01

    在这里插入图片描述

    报文回复的后四位为00 01,值为1,说明值被成功写入了

  5. 读取从机地址2,输入寄存器地址1的值,判断之前的写命令是否干扰了其他从机

    报文格式:00 00 00 00 00 06 02 03 00 01 00 01

    在这里插入图片描述

    报文回复的后四位为00 00,值为0,说明之前的写命令没有干扰其他从机

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/971463
推荐阅读
相关标签
  

闽ICP备14008679号