libmodbus使用说明

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编译了一下,我自己编译生成的libCSDN下载地址(2分)Gitee下载地址(免积分)。还是很容易的。

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

  • 生成:
    libmodbus/src/win32目录下生成了
    modbus.dllmodbus.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);
  • 读取
/* 
  读取线圈状态,可读取多个连续线圈的状态
  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);

  • 写入
/*
  写入单个线圈的状态
  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);

  • 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)

这个两个函数主要是将整型数据转换成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对应寄存器线圈输入等的地址。
三菱5u Modbus对应的地址

  • 31
    点赞
  • 169
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值