1. MODBUS简介
MODBUS是一项应用层报文传输协议,用于在通过不同类型的总线或网络连接的设备之间的客户机/服务器通信。Modbus比其他通信协议使用的更广泛的主要原因是因为它公开发表并且无版权要求;而且易于部署和维护;对供应商来说,修改移动本地的比特或字节没有很多限制。
1.1 协议版本与内容
Modbus协议目前存在用于串口、以太网以及其他支持互联网协议的网络的版本。
大多数Modbus设备通信通过串口EIA-485物理层进行。对于串行连接,存在两个变种,它们在数值数据表示不同和协议细节上略有不同。MODBUS模式分为三类,一种模式是RTU(远程终端设备),另一种模式是ASCII(美国信息交换码),第三种模式为TCP(运行在以太网上的协议)。【Modbus RTU】是一种紧凑的,采用二进制表示数据的方式(Modbus协议上规定,且默认模式必须是RTU,ASCII作为选项),【Modbus ASCII】是一种人类可读的,冗长的表示方式。这两个变种都使用串行通信(serial communication)方式。对于通过TCP/IP(例如以太网)的连接,存在多个【Modbus/TCP】变种,这种方式不需要校验和计算。对于所有的这三种通信协议在数据模型和功能调用上都是相同的,只有封装方式是不同的。
1.2 通信和设备
Modbus协议是一个master/slave架构的协议。有一个节点是master节点,其他使用Modbus协议参与通信的节点是slave节点。每一个slave设备都有一个唯一的地址。在串行和MB+网络中,只有被指定为主节点的节点可以启动一个命令(在以太网上,任何一个设备都能发送一个Modbus命令,但是通常也只有一个主节点设备启动指令)。
一个ModBus命令包含了打算执行的设备的Modbus地址。所有设备都会收到命令,但只有指定位置的设备会执行及回应指令(地址0例外,指定地址0的指令是广播指令,所有收到指令的设备都会运行,不过不回应指令)。所有的Modbus命令包含了检查码,以确定到达的命令没有被破坏。基本的ModBus命令能指令一个RTU改变它的寄存器的某个值,控制或者读取一个I/O端口,以及指挥设备回送一个或者多个其寄存器中的数据。
1.3 MODBUS使用要点
通过以上叙述可知,使用Modubs需要时刻围绕以下几点:
Modbus是主从方式通信,不能同步进行通信;
主机不发送,总线上就没有数据通信;
设备必须要有RTU协议,这是Modbus协议上规定的;
基本流程如下
发送:从机的地址+功能码+寄存器的地址+寄存器地址的个数+校验码
回复:从机的地址+功能码+要发送给主机数据的字节数+数据+校验码
我司的easyeai-api软件开源库将复杂的报文格式、收发操作做了统一的封装,为客户提供简单便捷的调用方式实现Modubs通讯功能。
2. 快速上手
如果您初次阅读此文档,请阅读:《入门指南/源码管理及编程介绍/源码工程管理》,按需管理自己工程源码(注:此文档必看,并建议采用【远程挂载管理】方式,否则有代码丢失风险!!!)。
2.1 源码工程下载
先在PC虚拟机定位到nfs服务目录,再在目录中创建存放源码仓库的管理目录:
cd ~/nfsroot mkdir GitHub cd GitHub
再通过git工具,在管理目录内克隆远程仓库(需要设备能对外网进行访问)
git clone https://github.com/EASY-EAI/EASY-EAI-Toolkit-3576.git

注:
* 此处可能会因网络原因造成卡顿,请耐心等待。
* 如果实在要在gitHub网页上下载,也要把整个仓库下载下来,不能单独下载本实例对应的目录。
2.2 开发环境搭建
通过adb shell进入板卡开发环境,如下图所示。
通过以下命令,把nfs目录挂载上nfs服务器。
mount -t nfs -o nolock : /home/orin-nano/Desktop/nfs/

2.3 例程编译
然后定位到nfs的挂载目录,再在目录中创建存放源码仓库的管理目录:
cd /home/orin-nano/Desktop/nfs/GitHub
进入到对应的例程目录执行编译操作,具体命令如下所示:
cd EASY-EAI-Toolkit-3576/Demos/common-modbus/ ./build.sh

2.4 例程运行及效果
进入Release目录,执行下方命令,运行示例程序:
cd Release ./test-modbus_tcp_master & ./test-modbus_tcp_slave
TCP模式执行效果如下所示:
如果需要更换RTU模式可自行修改代码
代码路径:EASY-EAI-Toolkit-3576/Demos/common-modbus/ test-modbus_tcp_slave.c
API的详细说明,以及API的调用(本例程源码),详细信息见下方说明。
3. MODBUS库函数说明
本章节介绍EASY EAI的MODBUS库函数的使用方法。
3.1 引用方式
EASY EAI api库位于本仓库的easyeai-api目录中。为方便客户在本地工程中直接调用我们的EASY EAI api库,此处列出工程中需要链接的库以及头文件等,方便用户直接添加。
描述 | CMake写法 | Makefile写法 |
api.cmake | ${common_root}/modbus/api.cmake | 无 |
头文件目录 | ${MODBUS_INCLUDE_DIRS} | -I ../../easyeai-api/common/modbus |
源文件目录 | ${MODBUS_SOURCE_DIRS} | ../../easyeai-api/common/modbus |
库文件目录 | 无 | 无 |
库链接参数 | ${MODBUS_LIBS} | 无 |
API源代码路径为EASY-EAI-Toolkit-3576/easyeai-api/common/modbus/。用户可通过源代码了解接口实现,甚至可对源码进行修改。
3.2 创建实例
以TCP方式创建Modbus实例,并初始化:
modbus_t* modbus_new_tcp(const char *ip, int port);
具体介绍如下所示。
函数名:modbus_new_tcp() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 |
ip:ip地址 port:端口号 |
返回值 |
成功:Modbus实例 失败:NULL |
注意事项 | 无 |
3.3 设置从机ID
设置从机ID的函数原型为:
void modbus_set_slave(modbus_t *ctx, int slave);
具体介绍如下所示。
函数名:modbus_set_slave() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 |
ctx:Modbus实例 slave:从机ID |
返回值 |
成功:0 失败:-1 |
注意事项 | 无 |
3.4 和从机进行连接
和从机建立连接的函数原型为:
void modbus_connect(modbus_t *ctx);
具体介绍如下所示。
函数名: modbus_connect() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx:Modbus实例 |
返回值 |
成功:0 失败:-1 |
注意事项 | 无 |
3.5 寄存器进行操作,功能码对应函数
3.5.1 读取线圈状态,可读取多个连续线圈的状态(对应功能码为0x01)
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
具体介绍如下所示。
函数名: modbus_read_bits() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :寄存器起始地址 | |
nb :寄存器个数 | |
dest :得到的状态值 | |
返回值 | 无 |
注意事项 | 无 |
3.5.2 读取输入状态,可读取多个连续输入的状态(对应功能码为0x02)
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
具体介绍如下所示。
函数名: modbus_read_input_bits() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :寄存器起始地址 | |
nb :寄存器个数 | |
dest :得到的状态值 | |
返回值 | 成功:返回nb的值 |
注意事项 | 无 |
3.5.3 读取保持寄存器的值,可读取多个连续保持寄存器的值(对应功能码为0x03)
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
函数名: modbus_read_registers() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :寄存器起始地址 | |
nb :寄存器个数 | |
dest :得到的寄存器的值 | |
返回值 |
成功:读到寄存器的个数 失败:-1 |
注意事项 | 无 |
3.5.4 读输入寄存器的值,可读取多个连续输入寄存器的值(对应功能码为0x04)
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
具体介绍如下所示。
函数名: modbus_read_input_registers() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :寄存器起始地址 | |
nb :寄存器个数 | |
dest :得到的寄存器的值 | |
返回值 |
成功:读到寄存器的个数 失败:-1 |
注意事项 | 无 |
3.5.5 写入单个线圈的状态(对应功能码为0x05)
int modbus_write_bit(modbus_t *ctx, int addr, int status);
具体介绍如下所示。
函数名:modbus_write_bit() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :线圈地址 | |
status:线圈状态 | |
返回值 |
成功:0 失败:-1 |
注意事项 | 无 |
3.5.6 写入多个连续线圈的状态(对应功能码为15)
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
具体介绍如下所示。
函数名: modbus_write_bits() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :线圈地址 | |
nb :线圈个数 | |
src:多个线圈状态 | |
返回值 |
成功:0 失败:-1 |
注意事项 | 无 |
3.5.7 写入单个寄存器(对应功能码为0x06)
int modbus_write_register(modbus_t *ctx, int addr, int value);
具体介绍如下所示。
函数名:modbus_write_register() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :寄存器地址 | |
value :寄存器的值 | |
返回值 |
成功:0 失败:-1 |
注意事项 | 无 |
3.5.8 写入多个连续寄存器(对应功能码为16)
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
具体介绍如下所示。
函数名: modbus_write_registers() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx :Modbus实例 |
addr :寄存器地址 | |
nb :寄存器的个数 | |
src:多个寄存器的值 | |
返回值 |
成功:0 失败:-1 |
注意事项 | 无 |
3.6 关闭套接字
关闭套接字函数原型为:
void modbus_close(modbus_t *ctx);
具体介绍如下所示。
函数名: modbus_close() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx:Modbus实例 |
返回值 | 无 |
注意事项 | 无 |
3.7 释放实例
和从机建立连接的函数原型为:
void modbus_free(modbus_t *ctx);
具体介绍如下所示。
函数名: modbus_free() | |
头文件 | easyeai-api/common/modbus/modbus.h |
输入参数 | ctx:Modbus实例 |
返回值 | 无 |
注意事项 | 无 |
4. 使用实例
示例主机代码路径EASY-EAI-Toolkit-3576/Demos/common-modbus/ test-modbus_tcp_master.c。
示例从机代码路径EASY-EAI-Toolkit-3576/Demos/common-modbus/ test-modbus_tcp_slave.c。
-
MODBUS
+关注
关注
28文章
2159浏览量
79857 -
服务器
+关注
关注
13文章
9826浏览量
88224 -
开发板
+关注
关注
25文章
5725浏览量
105623 -
rk3576
+关注
关注
1文章
185浏览量
807
发布评论请先 登录
基于RK3576开发板的MIPI-DSI使用

评论