libmodbus使用说明

xiaoxiao2022-06-03  15

版权声明:转 https://blog.csdn.net/yoyo18520/article/details/79113700

Modbus协议

百度解释

Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一种通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一个控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

当在同一Modbus网络上通信时,此协议决定了每个控制器需要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。

此协议支持传统的RS-232、RS-422、RS-485和以太网设备。许多工业设备,包括PLC,DCS,智能仪表等都在使用Modbus协议作为他们之间的通信标准。

应用场景

项目中经常需要和各式各样的PLC进行通讯,开始的时候是三菱Q系列的5u,用的是SLMP协议,后面又对接了安川的PLC,指不定以后会用哪家的PLC,所以考虑到是不是应该换一个通用性比较强的接口协议,可以省去大量时间和精力。 网上搜了一下,发现Modbus算是比较通用的协议了,也搜到了很多资料,因为对C++ 比较熟悉,所以搜的都是C++ 的Modbus资源。正好找到了libmodbus这个开源库,通读了一遍代码,觉得很不错,很强大,所以有了这篇文章。

libmodbus配置

在官网下载了代码,用vs2013编译了一下,我自己编译生成的lib地址。还是很容易的。

编译: libmodbus/src/win32目录下的 modbus-9.sln 文件,直接用vs打开编译就可以了。

生成: libmodbus/src/win32目录下生成了 modbus.dll和modbus.lib文件

引用: 工程包含头文件:modbus.h modbus-rtu.h modbus-tcp.h modbus-version.h 库文件: modbus.lib 程序目录下放入文件: modbus.dll

libmodbus函数说明

引入到工程之后,就需要了解几个主要的函数了。

初始化与释放 /* 以TCP的方式创建libmobus实例 char *ip:连接的IP地址 int port: 连接的IP端口 */ modbus_t *modbus_new_tcp(const char *ip, int port); /* 以串口的方式创建libmobus实例 onst char *device:连接的串口号,类似是这样'\\\\.\\COM10' int baud: 波特率 char parity:奇偶校验 int data_bit:数据位 int stop_bit:停止位 */ modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit); /* 释放libmodbus实例,使用完libmodbus需要释放掉 modbus_t *ctx:libmodbus实例 */ void modbus_free(modbus_t *ctx); 12345678910111213141516171819202122 读取 /* 读取线圈状态,可读取多个连续线圈的状态 modbus_t *ctx:Modbus实例 int addr: 线圈地址 int nb:读取线圈的个数 uint8_t *dest: 传出的状态值 */ int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); /* 读取输入状态,可读取多个连续输入的状态 modbus_t *ctx:Modbus实例 int addr:输入地址 int nb:读取输入的个数 uint8_t *dest:传出的状态值 */ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); /* 读取输入寄存器的值,可读取多个连续输入输入寄存器 modbus_t *ctx:Modbus实例 int addr:输入地址 int nb:读取输入寄存器的个数 uint8_t *dest:传出的寄存器值 */ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); /* 读取保持寄存器的值,可读取多个连续输入保持寄存器 modbus_t *ctx:Modbus实例 int addr:输入地址 int nb:读取保持寄存器的个数 uint8_t *dest:传出的寄存器值 */ int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); 123456789101112131415161718192021222324252627282930313233343536 写入 /* 写入单个线圈的状态 modbus_t *ctx:Modbus实例 int addr:线圈地址 int status:线圈状态 */ int modbus_write_bit(modbus_t *ctx, int addr, int status); /* 写入多个连续线圈的状态 modbus_t *ctx:Modbus实例 int addr:线圈地址 int nb:线圈个数 const uint8_t *src:多个线圈状态 */ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src); /* 写入单个寄存器 modbus_t *ctx:Modbus实例 int addr:寄存器地址 int value:寄存器的值 */ int modbus_write_register(modbus_t *ctx, int addr, int value); /* 写入多个连续寄存器 int addr:寄存器地址 int nb:寄存器的个数 const uint16_t *src:多个寄存器的值 */ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src); 123456789101112131415161718192021222324252627282930313233 float 浮点数

libmodbus下处理浮点型真的是异常方便,我之前用的协议都是需要我自己转换的,在得到的寄存器的数据后,发现PLC的数解析的时候,可能分16位和32位的,拿16位举例,每4位一组就像ABCD,我们需要解析出来的是DCBA。 后来我发现了libmodbus里面有这两个函数

float modbus_get_float(const uint16_t *src); void modbus_set_float(float f, uint16_t *dest) 123

这个两个函数主要是将整型数据转换成float,和将float转换成整型的。 在用modbus_read_registers或者modbus_read_input_registers得到寄存器的值int16_t *dest,如果里面存的是浮点数,把dest当做参数传入到modbus_get_float里面,如果得到的值不对,你需要弄清楚PLC对应传出数据的模式是DCBA还是BADC,CDAB,ABCD。 libmodbus还提供了其他函数

modbus_get_float_abcd modbus_get_float_badc modbus_get_float_cdab modbus_get_float_dcba modbus_set_float_abcd modbus_set_float_badc modbus_set_float_cdab modbus_set_float_dcba

下图是我在工作中常用的三菱5u PLC Modbus对应寄存器线圈输入等的地址。

转载请注明原文地址: https://www.6miu.com/read-4915046.html

最新回复(0)