Linux终端命令行图形化Modbus调试工具

前言

之前经常使用mbpoll在Linux命令行下调试modbus,用久了发现其实并不方便,因为每次携带的参数太多,使用的时候老是忘记怎么使用,经常需要去翻笔记,于是决定自己开发一款Linux命令行版本的Modbus调试工具,方便调试。

项目开源地址:https://gitee.com/chen-dongyu123/modbus_tools

Linux终端命令行图形化Modbus调试助手

  1. 连接ModbusTcp服务器
    在这里插入图片描述

  2. 连接Modbus串口

    在这里插入图片描述

  3. 查询和写入寄存器,先在菜单栏上选择寄存器类型,然后可以根据从机地址,起始寄存器地址,结束寄存器地址读取范围类的寄存器数据,支持单个数据写入寄存器

    在这里插入图片描述

  4. 查询结果

    在这里插入图片描述
    该工具完全支持无鼠标键盘操作,Esc可以关闭页面,Tab键切换输入框,上下左右键可用来上下滚动表格。

Modbus客户端重点代码实现

  1. 创建客户端基类,主要有以下几个方法

    #pragma once
    #include <vector>
    #include <string>
    #include "libmodbus/src/modbus.h"
    
    class ModbusBaseClient
    {
    public:
        ModbusBaseClient() = default;
        ~ModbusBaseClient();
    
        bool isConnected();
        // 线圈寄存器(功能码0x01,可读可写)
        std::vector<int> readCoilValues(int slaveId, int addr, int cnt);
        bool writeCoilValue(int slaveId, int addr, int value);
        // 离散输入寄存器(功能码0x02,只读)
        std::vector<int> readDiscreteInputValues(int slaveId, int addr, int cnt);
        // 保持寄存器(功能码0x03,可读可写)
        std::vector<int> readHoldRegisterValues(int slaveId, int addr, int cnt);
        bool writeHoldRegisterValue(int slaveId, int addr, int value);
        // 输入寄存器(功能码0x04,只读)
        std::vector<int> readInputRegisterValues(int slaveId, int addr, int cnt);
    
        // 根据地址范围读取寄存器,起始地址-结束地址
        std::vector<int> readRangeCoilValues(int slaveId, int startAddr, int endAddr);
        std::vector<int> readRangeDiscreteInputValues(int slaveId, int startAddr, int endAddr);
        std::vector<int> readRangeHoldRegisterValues(int slaveId, int startAddr, int endAddr);
        std::vector<int> readRangeInputRegisterValues(int slaveId, int startAddr, int endAddr);
    
    protected:
        modbus_t *_ctx{nullptr};
        bool _isConnected{false};
    };
    
  2. 客户端基类实现

    #include "modbus_base_client.h"
    #include "log.h"
    
    bool ModbusBaseClient::isConnected()
    {
        return _isConnected;
    }
    
    ModbusBaseClient::~ModbusBaseClient()
    {
        if (_ctx != nullptr)
        {
            modbus_close(_ctx);
            modbus_free(_ctx);
        }
    }
    
    std::vector<int> ModbusBaseClient::readCoilValues(int slaveId, int addr, int cnt)
    {
        modbus_set_slave(_ctx, slaveId);
        uint8_t dest[cnt];
        memset(dest, 0, cnt * sizeof(uint8_t));
        int rc = modbus_read_bits(_ctx, addr, cnt, dest);
        if (rc == -1)
        {
            LOG_ERROR(fmt::format("readCoilValues failed, {}", modbus_strerror(errno)));
            return {};
        }
        std::vector<int> result;
        for (const auto &val : dest)
        {
            result.push_back(static_cast<int>(val));
        }
        return result;
    }
    
    bool ModbusBaseClient::writeCoilValue(int slaveId, int addr, int value)
    {
        modbus_set_slave(_ctx, slaveId);
        int rc = modbus_write_bit(_ctx, addr, value);
        if (rc == -1)
        {
            LOG_ERROR(fmt::format("writeCoilValue failed, {}", modbus_strerror(errno)));
            return false;
        }
        else
        {
            return true;
        }
    }
    
    std::vector<int> ModbusBaseClient::readDiscreteInputValues(int slaveId, int addr, int cnt)
    {
        modbus_set_slave(_ctx, slaveId);
        uint8_t dest[cnt];
        memset(dest, 0, cnt * sizeof(uint8_t));
        int rc = modbus_read_input_bits(_ctx, addr, cnt, dest);
        if (rc == -1)
        {
            LOG_ERROR(fmt::format("readDiscreteInputValues failed, {}", modbus_strerror(errno)));
            return {};
        }
        std::vector<int> result;
        for (const auto &val : dest)
        {
            result.push_back(static_cast<int>(val));
        }
        return result;
    }
    
    std::vector<int> ModbusBaseClient::readHoldRegisterValues(int slaveId, int addr, int cnt)
    {
        modbus_set_slave(_ctx, slaveId);
        uint16_t dest[cnt];
        memset(dest, 0, cnt * sizeof(uint16_t));
        int rc = modbus_read_registers(_ctx, addr, cnt, dest);
        if (rc == -1)
        {
            LOG_ERROR(fmt::format("readHoldRegisterValues failed, {}", modbus_strerror(errno)));
            return {};
        }
        std::vector<int> result;
        for (const auto &val : dest)
        {
            result.push_back(static_cast<int>(val));
        }
        return result;
    }
    
    std::vector<int> ModbusBaseClient::readInputRegisterValues(int slaveId, int addr, int cnt)
    {
        modbus_set_slave(_ctx, slaveId);
        uint16_t dest[cnt];
        memset(dest, 0, cnt * sizeof(uint16_t));
        int rc = modbus_read_input_registers(_ctx, addr, cnt, dest);
        if (rc == -1)
        {
            LOG_ERROR(fmt::format("readInputRegisterValues failed, {}", modbus_strerror(errno)));
            return {};
        }
        std::vector<int> result;
        for (const auto &val : dest)
        {
            result.push_back(static_cast<int>(val));
        }
        return result;
    }
    
    bool ModbusBaseClient::writeHoldRegisterValue(int slaveId, int addr, int value)
    {
        modbus_set_slave(_ctx, slaveId);
        int rc = modbus_write_register(_ctx, addr, value);
        if (rc == -1)
        {
            LOG_ERROR(fmt::format("writeHoldRegisterValue failed, {}", modbus_strerror(errno)));
            return false;
        }
        else
        {
            return true;
        }
    }
    
    std::vector<int> ModbusBaseClient::readRangeCoilValues(int slaveId, int startAddr, int endAddr)
    {
        modbus_set_slave(_ctx, slaveId);
        int cnt = endAddr - startAddr + 1;
        int num = cnt % 100 == 0 ? cnt / 100 : cnt / 100 + 1;
        std::vector<int> result;
        for (int i = 0; i < num; i++)
        {
            int addr = startAddr + i * 100;
            int cnt = 100;
            if (i == num - 1)
            {
                cnt = endAddr - addr + 1;
            }
            uint8_t dest[cnt];
            memset(dest, 0, cnt * sizeof(uint8_t));
            int rc = modbus_read_bits(_ctx, addr, cnt, dest);
            if (rc == -1)
            {
                LOG_ERROR(fmt::format("readCoilValues failed, {}", modbus_strerror(errno)));
                return {};
            }
            for (const auto &val : dest)
            {
                result.push_back(static_cast<int>(val));
            }
        }
        return result;
    }
    std::vector<int> ModbusBaseClient::readRangeDiscreteInputValues(int slaveId, int startAddr, int endAddr)
    {
        modbus_set_slave(_ctx, slaveId);
        int cnt = endAddr - startAddr + 1;
        int num = cnt % 100 == 0 ? cnt / 100 : cnt / 100 + 1;
        std::vector<int> result;
        for (int i = 0; i < num; i++)
        {
            int addr = startAddr + i * 100;
            int cnt = 100;
            if (i == num - 1)
            {
                cnt = endAddr - addr + 1;
            }
            uint8_t dest[cnt];
            memset(dest, 0, cnt * sizeof(uint8_t));
            int rc = modbus_read_input_bits(_ctx, addr, cnt, dest);
            if (rc == -1)
            {
                LOG_ERROR(fmt::format("readDiscreteInputValues failed, {}", modbus_strerror(errno)));
                return {};
            }
            for (const auto &val : dest)
            {
                result.push_back(static_cast<int>(val));
            }
        }
        return result;
    }
    
    std::vector<int> ModbusBaseClient::readRangeHoldRegisterValues(int slaveId, int startAddr, int endAddr)
    {
        modbus_set_slave(_ctx, slaveId);
        int cnt = endAddr - startAddr + 1;
        int num = cnt % 100 == 0 ? cnt / 100 : cnt / 100 + 1;
        std::vector<int> result;
        for (int i = 0; i < num; i++)
        {
            int addr = startAddr + i * 100;
            int cnt = 100;
            if (i == num - 1)
            {
                cnt = endAddr - addr + 1;
            }
            uint16_t dest[cnt];
            memset(dest, 0, cnt * sizeof(uint16_t));
            int rc = modbus_read_registers(_ctx, addr, cnt, dest);
            if (rc == -1)
            {
                LOG_ERROR(fmt::format("readDiscreteInputValues failed, {}", modbus_strerror(errno)));
                return {};
            }
            for (const auto &val : dest)
            {
                result.push_back(static_cast<int>(val));
            }
        }
        return result;
    }
    
    std::vector<int> ModbusBaseClient::readRangeInputRegisterValues(int slaveId, int startAddr, int endAddr)
    {
        modbus_set_slave(_ctx, slaveId);
        int cnt = endAddr - startAddr + 1;
        int num = cnt % 100 == 0 ? cnt / 100 : cnt / 100 + 1;
        std::vector<int> result;
        for (int i = 0; i < num; i++)
        {
            int addr = startAddr + i * 100;
            int cnt = 100;
            if (i == num - 1)
            {
                cnt = endAddr - addr + 1;
            }
            uint16_t dest[cnt];
            memset(dest, 0, cnt * sizeof(uint16_t));
            int rc = modbus_read_input_registers(_ctx, addr, cnt, dest);
            if (rc == -1)
            {
                LOG_ERROR(fmt::format("readDiscreteInputValues failed, {}", modbus_strerror(errno)));
                return {};
            }
            for (const auto &val : dest)
            {
                result.push_back(static_cast<int>(val));
            }
        }
        return result;
    }
    
  3. ModbusTcp客户端

    #pragma once
    #include <iostream>
    #include <vector>
    #include "modbus_base_client.h"
    #include "libmodbus/src/modbus-tcp.h"
    
    class ModbusTcpClient : public ModbusBaseClient
    {
    public:
        ModbusTcpClient(const std::string ip, int port);
        ~ModbusTcpClient() = default;
    
    public:
        std::string ip;
        int port;
    };
    

    实现

    #include "modbus_tcp_client.h"
    #include "log.h"
    
    ModbusTcpClient::ModbusTcpClient(const std::string ip, int port) : ip(ip), port(port)
    {
        _ctx = modbus_new_tcp(ip.c_str(), port);
        if (_ctx == nullptr)
        {
            _isConnected = false;
            LOG_ERROR("Unable to create the libmodbus context");
            return;
        }
    
        if (modbus_connect(_ctx) == -1)
        {
            LOG_ERROR(fmt::format("Connection failed, {}", modbus_strerror(errno)));
            modbus_free(_ctx);
            _ctx = nullptr;
            _isConnected = false;
            return;
        }
        _isConnected = true;
        LOG_INFO("Connected to Modbus Tcp server");
    }
    
  4. Modbus串口

    #pragma once
    #include <iostream>
    #include <vector>
    #include "modbus_base_client.h"
    #include "libmodbus/src/modbus-rtu.h"
    
    class ModbusRtuClient : public ModbusBaseClient
    {
    public:
        ModbusRtuClient(const std::string &port, int baudRate, int byteSize, char parity, int stopBits);
        ModbusRtuClient() : ModbusRtuClient("/ttyUSB0", baudRate, byteSize, parity, stopBits){}; // 委托构造
        ~ModbusRtuClient() = default;
    
    public:
        std::string port{"/ttyUSB0"}; // 端口
        int baudRate{9600};           // 波特率
        int byteSize{8};              // 数据位
        char parity{'N'};             // 奇偶校验
        int stopBits{1};              // 停止位
    };
    

    实现

    #include "modbus_rtu_client.h"
    #include "log.h"
    
    ModbusRtuClient::ModbusRtuClient(const std::string &port, int baudRate, int byteSize, char parity, int stopBits) : port(port), baudRate(baudRate), byteSize(byteSize), parity(parity), stopBits(stopBits)
    {
        _ctx = modbus_new_rtu(port.c_str(), baudRate, parity, byteSize, stopBits); // 使用9600-N-8,1个停止位
        if (_ctx == nullptr)
        {
            _isConnected = false;
            LOG_ERROR("Unable to create the libmodbus context");
            return;
        }
    
        if (modbus_connect(_ctx) == -1)
        {
            _isConnected = false;
            LOG_ERROR(fmt::format("Connection failed: {0}", modbus_strerror(errno)));
            modbus_free(_ctx);
            _ctx = nullptr;
            return;
        }
        _isConnected = true;
        LOG_INFO("Connected to Modbus Serial server");
    }
    
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Python中可以使用第三方库modbus_tk来创建modbus服务端。modbus_tk是一个用于Modbus通信的Python库,它提供了简化和封装了modbus协议的功能。使用modbus_tk,开发者可以轻松地创建modbus服务端。 要创建一个modbus服务端,首先需要安装modbus_tk库。可以使用pip工具在Python环境中安装modbus_tk库,命令如下: ``` pip install modbus_tk ``` 安装完成后,可以在Python脚本中导入modbus_tk库并使用它提供的函数和类来创建modbus服务端。下面是一个简单的示例: ```python from modbus_tk import modbus_tcp, modbus_rtu # 创建一个modbus TCP服务端 server = modbus_tcp.TcpServer(address='localhost', port=502) server.start() # 创建一个modbus RTU服务端 server = modbus_rtu.RtuServer(port='/dev/ttyUSB0') server.start() # 在服务端上注册一个数据地址范围 server.add_slave(1, address=0x00) # 启动服务端,开始监听客户端请求 server.start() ``` 在上面的代码中,我们首先导入了modbus_tk库中的modbus_tcpmodbus_rtu模块。然后,我们通过创建TcpServer对象和RtuServer对象来创建modbus TCP和RTU服务端。可以根据需要指定地址和端口号。接下来,我们使用add_slave方法在服务端上注册一个数据地址范围,这样客户端就可以访问该范围内的数据。最后,我们调用start方法启动服务端,开始监听客户端的请求。 通过以上步骤,我们就可以在Python中创建一个modbus服务端了。可以根据具体的需求来进一步配置和扩展服务端的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MC皮蛋侠客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值