问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
CSDN
1.
https://blog.csdn.net/weixin_46284302/article/details/140127414

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通讯成功

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号