利用RS485实现Modbus通信的完整步骤

利用RS485实现Modbus通信的完整步骤

1. 关于Modbus

Modbus是一种通用的工业通信协议,广泛应用于自动化领域中设备之间的通信。它最初由Modicon(现在的施耐德电气)于1979年开发,是一个开放标准的协议。

在 OSI 模型中,Modbus 通常被归类为应用层协议,可以说RS485 是 OSI 模型中的物理层实现,负责电气和机械特性,Modbus 则通常处于 OSI 模型的应用层,负责定义数据传输的结构、规则和协议。

Modbus协议支持多种通信介质和网络,包括RS232、RS485、TCP/IP,通常用于建立主从结构的通信,主站发送请求(查询)给从站,从站响应请求并返回数据。

协议类型

  • Modbus RTU:基于串行通信,通常使用RS-232或RS-485接口。
  • Modbus ASCII:基于ASCII编码的串行通信协议。
  • Modbus TCP:基于TCP/IP网络通信的协议,以太网为基础。

一主多从

2. 交叉编译libmodbus

由于我们需要使用libmodbus这个库,而我将在ARM开发板上运行,所以需要下载libmodbus的库进行交叉编译

2.1 下载libmodbus

github libmodbus

我这里下载了最新的3.1.10

解压

tar -zxvf libmodbus-3.1.10.tar.gz

2.2 配置编译环境

解压后进入libmodbus-3.1.10目录

./configure --host=arm-linux-gnueabihf --prefix=/usr/local/arm-libmodbus

如果你没有安装ARM的交叉编译工具,则

sudo apt install gcc-arm-linux-gnueabihf

2.3 编译并安装库

make
sudo make install

3. 复制编译好的文件到ARM板

在板子上运行引用到libmobus的库还需要将编译好的库文件和头文件复制到ARM板上

3.1 打包库文件

进入/usr/local/arm-libmodbus目录打包

cd /usr/local/arm-libmodbus
sudo tar czvf arm-libmodbus.tar.gz lib include

3.2 安装库

将压缩包丢到板子上后进行解压

tar xzvf arm-libmodbus.tar.gz

复制文件

sudo cp -r lib/* /usr/lib/
sudo cp -r include/* /usr/include/

此时库安装完毕

4. C程序测试Modbus RTU

Modbus协议定义了数据的帧格式,包括地址、功能码、数据区域和校验等部分

如果直接使用RS485通信,没有固定的数据格式和通信流程,需要自行处理数据帧的校验、错误检测和恢复等问题

前面准备工作已经做完了,接下来写个C程序来测试使用Modbus RTU,使用RS485接口

我下面的代码特地将波特率抽了出来放在一个头文件中,你也可以直接写死或者进行外部传参

4.1 master.c

#include <stdio.h>
#include <modbus.h>
#include <errno.h>
#include "config.h"

int main()
{
    modbus_t *ctx;
    uint16_t tab_reg[32];

    // 创建新的 RTU,波特率设置为 115200
    ctx = modbus_new_rtu("/dev/ttyACM0", BAUD_RATE, 'N', 8, 1);

    // 设置 Modbus 从机 ID 为 1
    modbus_set_slave(ctx, 1);

    // 连接到 Modbus 从机
    if (modbus_connect(ctx) == -1)
    {
        fprintf(stderr, "连接失败: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

    // 从地址 0 开始读取 10 个寄存器
    if (modbus_read_registers(ctx, 0, 10, tab_reg) == -1)
    {
        fprintf(stderr, "读取失败: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

    for (int i = 0; i < 10; i++)
    {
        printf("寄存器 %d: %d\n", i, tab_reg[i]);
    }

    // 关闭连接并释放 Modbus
    modbus_close(ctx);
    modbus_free(ctx);
    return 0;
}

4.2 slave.c

#include <stdio.h>
#include <modbus.h>
#include <errno.h>
#include "config.h"

int main()
{
    modbus_t *ctx;
    modbus_mapping_t *mb_mapping;

    // 创建新的 RTU,波特率设置为 115200
    ctx = modbus_new_rtu("/dev/ttyACM0", BAUD_RATE, 'N', 8, 1);

    // 设置 Modbus 从机 ID 为 1
    modbus_set_slave(ctx, 1);

    // 连接到 Modbus 主机
    if (modbus_connect(ctx) == -1)
    {
        fprintf(stderr, "连接失败: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

    // 分配 Modbus 映射(100 个保持寄存器)
    mb_mapping = modbus_mapping_new(0, 0, 100, 0);
    if (mb_mapping == NULL)
    {
        fprintf(stderr, "映射失败: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

    while (1)
    {
        uint8_t query[MODBUS_RTU_MAX_ADU_LENGTH];
        // 从 Modbus 主机接收查询
        int rc = modbus_receive(ctx, query);

        if (rc > 0)
        {
            // 回复查询
            modbus_reply(ctx, query, rc, mb_mapping);
        }
        else if (rc == -1)
        {
            fprintf(stderr, "接收失败: %s\n", modbus_strerror(errno));
            break;
        }
    }

    // 释放 Modbus
    modbus_mapping_free(mb_mapping);
    modbus_close(ctx);
    modbus_free(ctx);
    return 0;
}

4.3 config.h

放置配置的头文件,注意头文件保护符

#ifndef CONFIG_H
#define CONFIG_H

#define BAUD_RATE 115200

#endif // CONFIG_H

4.4 Makefile

写个简单的Makefile方便编译

CC = arm-linux-gnueabihf-gcc
CFLAGS = -Wall -I/usr/local/arm-libmodbus/include/modbus
LDFLAGS = -L/usr/local/arm-libmodbus/lib -lmodbus

all: master slave

master: master.o
	$(CC) -o master master.o $(LDFLAGS)

slave: slave.o
	$(CC) -o slave slave.o $(LDFLAGS)

master.o: master.c config.h
	$(CC) $(CFLAGS) -c master.c -o master.o

slave.o: slave.c config.h
	$(CC) $(CFLAGS) -c slave.c -o slave.o

clean:
	rm -f master slave *.o

4.5 运行结果

使用chmod +x [file]给文件权限,运行成功你可以看到以下信息,代表基于RS485的Modbus通讯成功

如果只是简单测试通讯,那么到这里就可以了。


相关文章:

RS-485串口通信:简易指南与代码示例

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值