前题

项目需要使用到 Modbus 协议,不想自己写一个协议栈,虽然 Modbus 协议比较简单。

可用的 Modbus 协议栈

libModubs


freeModubs

开源代码。官网地址为:https://www.embedded-solutions.at/en/freemodbus/。可以从 github 中下载,https:///cwalter-at/freemodbus

emModubs

segger 公司的。商业代码。不出钱是没法用的。https://www.segger.com/downloads/emmodbus/

个人选择

emModbus,商业代码。穷逼买不起,放弃。
freeModbus以前用过,但是好久没有更新了,放弃。最近更新是三年前。
libModbus还在正常维护。最新版本是 3.1.6,更新日期为 2019 年 9 月。

编译 libModbus

环境

Win10系统,编译器为 Visual Studio 2019。没有使用 MSYS2 或者 CYGWin 来编译。

生成 sln

这个不是我手动生成的,老版本里有。从老版本中拷贝过来即可。对应的文件在 libmodbus-3.1.6/src/win32 这个目录。

编译 DLL

错误1:缺少 config.h

将 libmodbus-3.1.6 目录下 拷贝过来,改名为 即可。

错误2:LNK111

如下:

freemodbus 支持广播模式吗_#include


是因为设置的版本号为 1.0.0 导致的语法错误。

解决方案

删除版本号就可以解决问题。在设置(项目>设置>链接器)上删除“版本”条目。如下图。

freemodbus 支持广播模式吗_Modbus_02


删除上图中的 1.0.0,即可解决这个问题。

结果

freemodbus 支持广播模式吗_libModbus_03


如上图所示,modbus.dll 和 modbus.lib 就生成成功。

测试libModbus

必须软件

Modbus Master

推荐使用 Modbus Poll 软件。

Modbus Slave

推荐使用 Modbus Slave 软件。

虚拟串口

如果没有现成的 Modbus 设备或者第二台计算机。那么虚拟串口就是必须的。

推荐使用:vspd虚拟串口软件。该软件可以虚拟出配对的两个串口。这样我们就可以运行 Modbus 软件来测试了。

软件安装好,运行起来如下图:

freemodbus 支持广播模式吗_Modbus_04


如上图,我的工控机有物理串口 freemodbus 支持广播模式吗_物联网_05

虚拟串口测试
Modbus Master

freemodbus 支持广播模式吗_Modbus_06


如上图,打开 COM9,配置为 9600 N 8 1,使用 Modbus RTU 协议。

Modbus Slave

freemodbus 支持广播模式吗_物联网_07


如上图,使用 COM10,9600 N 8 1,Modbus RTU 协议。

这样就可以发现两个软件成功开始通信。

freemodbus 支持广播模式吗_libModbus_08

Modbus Master 测试

VSDP + Modbus Poll + 自己的程序作为一个主机。这样我们只需要向串口发送 03 00 00 00 0A C5 CD 这个指令就可以了。

添加 Modbus Master RTU 项目

在 Visual Studio 2019 中选择“文件”->“新建”->“项目”。选择 C++ 空项目。配置如下图所示:

freemodbus 支持广播模式吗_物联网_09


项目建立后。如下图所示。

freemodbus 支持广播模式吗_#include_10

RTU代码

在 RTU_Master 中添加一个空白的 cpp 文件,名字为 rtu_master.cpp,并加入到项目中。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
//#include <windows.h>
#include "modbus.h"

#pragma comment(lib, "modbus.lib")
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[]) {
    modbus_t* ctx;
    int rc;
    uint16_t tab_reg[64];

    //打开
    ctx = modbus_new_rtu("COM9", 9600, 'N', 8, 1);
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n",
            modbus_strerror(errno));
        modbus_free(ctx);

    }
    //打开调试模式
    modbus_set_debug(ctx, 1);
    modbus_set_response_timeout(ctx, 1, 0);//设置响应时间

    //设置从机地址
    modbus_set_slave(ctx, 1);
    for (int i = 1; i <= 100; i++) {
        rc = modbus_read_registers(ctx, 0x00, 0x0A, tab_reg);
        //rc = modbus_read_input_registers(ctx, 0x00, 0x0A, tab_reg);
        if (rc == -1) {
            fprintf(stderr, "%s\n", modbus_strerror(errno));
            return -1;
        }
        //输出结果
        for (int j = 0; j < rc; j++) {
            printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
        }
        Sleep(1000);
    }

    //关闭设备
    modbus_close(ctx);
    modbus_free(ctx);

    return 0;
}
配置头文件路径

这个程序中,我们需要使用到 modbus.h。所以需要指定对应的路径。如下图所示。

freemodbus 支持广播模式吗_Modbus_11

配置库文件路径

这个程序中,我们需要使用到 modbus.lib。所以需要指定对应的路径。如下图所示。

freemodbus 支持广播模式吗_物联网_12

配置DLL文件路径

这个程序中,我们需要使用到 modbus.dll。所以需要指定对应的路径。如下图所示。

freemodbus 支持广播模式吗_#include_13

运行结果

freemodbus 支持广播模式吗_#include_14


上图的数据解码有问题。先不管了。

添加 Modbus Master TCP 项目
TCP代码
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
//#include <windows.h>
#include "modbus.h"
#ifdef _WIN32
# include <winsock2.h>
#else
# include <sys/socket.h>
#endif

#pragma comment(lib, "modbus.lib")
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[]) {
    modbus_t* ctx;
    int rc;
    uint16_t tab_reg[64];

    //打开
    ctx = modbus_new_tcp("127.0.0.1", 1502);
    //打开调试模式
    modbus_set_debug(ctx, 1);
    modbus_set_response_timeout(ctx, 1, 0);//设置响应时间
    //设置从机地址
    modbus_set_slave(ctx, 1);

    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n",
            modbus_strerror(errno));
        modbus_free(ctx);
    }

#if 0
    int server_socket = modbus_tcp_listen(ctx, 1);
    if (server_socket == -1) {
        fprintf(stderr, "Unable to listen TCP: %s\n",
            modbus_strerror(errno));
        modbus_free(ctx);
    }
    //modbus_tcp_accept(ctx, &server_socket);
#endif

    for (int i = 1; i <= 100; i++) {
        rc = modbus_read_registers(ctx, 0x00, 0x0A, tab_reg);
        //rc = modbus_read_input_registers(ctx, 0x00, 0x0A, tab_reg);
        if (rc == -1) {
            fprintf(stderr, "%s\n", modbus_strerror(errno));
            return -1;
        }
        //输出结果
        for (int j = 0; j < rc; j++) {
            printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
        }
        Sleep(1000);
    }

    //if (server_socket != -1) {
        //close(server_socket);
    //}

    //关闭设备
    modbus_close(ctx);
    modbus_free(ctx);

    return 0;
}
运行结果

freemodbus 支持广播模式吗_freemodbus 支持广播模式吗_15


上图的数据解码有问题。先不管了。

Modbus Slave 测试

待补充。今天先测试到这里,还有别的事情需要去搬砖。