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需要时刻围绕以下几点:
l Modbus是主从方式通信,不能同步进行通信;
l 主机不发送,总线上就没有数据通信;
l 设备必须要有RTU协议,这是Modbus协议上规定的;
l 基本流程如下
发送:从机的地址+功能码+寄存器的地址+寄存器地址的个数+校验码
回复:从机的地址+功能码+要发送给主机数据的字节数+数据+校验码
我司的easyeai-api软件开源库将复杂的报文格式、收发操作做了统一的封装,为客户提供简单便捷的调用方式实现Modubs通讯功能。
2. 快速上手
2.1 开发环境准备
如果您初次阅读此文档,请阅读《入门指南/开发环境准备/Easy-Eai编译环境准备与更新》,并按照其相关的操作,进行编译环境的部署。
在PC端Ubuntu系统中执行run脚本,进入EASY-EAI编译环境,具体如下所示。
cd ~/develop_environment ./run.sh 22042.2 源码下载以及例程编译
在EASY-EAI编译环境下创建存放源码仓库的管理目录:
cd /opt mkdir EASY-EAI-Toolkit cd EASY-EAI-Toolkit通过git工具,在管理目录内克隆远程仓库
git clone https://github.com/EASY-EAI/EASY-EAI-Toolkit-1126B.git注:
* 此处可能会因网络原因造成卡顿,请耐心等待。
* 如果实在要在gitHub网页上下载,也要把整个仓库下载下来,不能单独下载本实例对应的目录。
进入到对应的例程目录执行编译操作,具体命令如下所示:
cd EASY-EAI-Toolkit-1126B/Demos/netProtocol-modbus/ ./build.sh注:
* 由于依赖库部署在板卡上,因此交叉编译过程中必须保持/mnt挂载。
2.3 例程运行
通过串口调试或ssh调试,进入板卡后台,定位到例程部署的位置,如下所示:
cd /userdata/Demo/netProtocol-modbus运行例程命令如下所示:
./test-modbus_tcp_master & ./test-modbus_tcp_slave2.4 运行效果
TCP模式执行效果如下所示:
如果需要更换RTU模式可自行修改代码:
代码路径:EASY-EAI-Toolkit-1126B/Demos/netProtocol-modbus/test-modbus_tcp_slave.c
API的详细说明,以及API的调用(本例程源码),详细信息见下方说明。
3. MODBUS库函数说明
本章节介绍EASY EAI的MODBUS库函数的使用方法。
3.1 引用方式
EASY EAI api库位于本仓库的easyeai-api目录中。为方便客户在本地工程中直接调用我们的EASY EAI api库,此处列出工程中需要链接的库以及头文件等,方便用户直接添加。
API源代码路径为EASY-EAI-Toolkit-1126B/easyeai-api/netProtocol/modbus/。用户可通过源代码了解接口实现,甚至可对源码进行修改。
3.2 创建实例
以TCP方式创建Modbus实例,并初始化:
modbus_t* modbus_new_tcp(const char *ip, int port);具体介绍如下所示。
3.3 设置从机ID
设置从机ID的函数原型为:
void modbus_set_slave(modbus_t *ctx, int slave);具体介绍如下所示。
3.4 和从机进行连接
和从机建立连接的函数原型为:
void modbus_connect(modbus_t *ctx);具体介绍如下所示。
3.5 寄存器进行操作,功能码对应函数
3.5.1 读取线圈状态,可读取多个连续线圈的状态(对应功能码为0x01)
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);a具体介绍如下所示。
3.5.2 读取输入状态,可读取多个连续输入的状态(对应功能码为0x02)
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);具体介绍如下所示。
3.5.3 读取保持寄存器的值,可读取多个连续保持寄存器的值(对应功能码为0x03)
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);具体介绍如下所示。
3.5.4 读输入寄存器的值,可读取多个连续输入寄存器的值(对应功能码为0x04)
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);具体介绍如下所示。
3.5.5 写入单个线圈的状态(对应功能码为0x05)
int modbus_write_bit(modbus_t *ctx, int addr, int status);具体介绍如下所示。
3.5.6 写入多个连续线圈的状态(对应功能码为15)
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);具体介绍如下所示。
3.5.7 写入单个寄存器(对应功能码为0x06)
int modbus_write_register(modbus_t *ctx, int addr, int value);具体介绍如下所示。
3.5.8 写入多个连续寄存器(对应功能码为16)
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);具体介绍如下所示。
3.6 关闭套接字
关闭套接字函数原型为:
void modbus_close(modbus_t *ctx);具体介绍如下所示。
3.7 释放实例
和从机建立连接的函数原型为:
void modbus_free(modbus_t *ctx);具体介绍如下所示。
4. 使用实例
示例主机代码路径:
EASY-EAI-Toolkit-1126B/Demos/netProtocol-modbus/test-modbus_tcp_master.c。
示例从机代码路径:
EASY-EAI-Toolkit-1126B/Demos/netProtocol-modbus/test-modbus_tcp_slave.c。