一、libmodbus简介
libmodbus是一个快速且可移植的Modbus库,支持传统的RS-232、RS-422、RS-485和以太网设备。
二、安装libmodbus
- Linux、MacOS、FreeBSD、WIN32等可直接通过包管理器安装
libmodbus
- 源码编译安装:
libmodbus官网下载:https://libmodbus.org/releases/libmodbus-3.1.6.tar.gz
github下载:https://github.com/stephane/libmodbus.git
//进入解压目录
cd libmodbus-3.1.6
//配置编译选项(以ARM为例,--build为系统构架 --host为编译对应系统工具链,--prefix为输出目录,选项均是可选的)
./configure --build=i686 --host=arm-linux --enable-static --prefix=[install path]/
//编译安装
make && make install
三、简单示例
- RTU master
#include
#include
#include
#include "modbus.h"
int main(void)
{
int i = 0;
int regs = 0;
modbus_t *ctx = NULL;
uint16_t tab_reg[64] = {0};
//打开端口: 端口,波特率,校验位,数据位,停止位
ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
//设置从机地址
modbus_set_slave(ctx, 1);
//设置串口模式(可选)
modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
//设置RTS(可选)
modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
//建立连接
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
//设置应答延时(可选)
modbus_set_response_timeout(ctx, 0, 1000000);
while (1)
{
memset(tab_reg, 0, sizeof(tab_reg));
//读寄存器设置:寄存器地址、数量、数据缓冲
regs = modbus_read_registers(ctx, 0, 20, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
continue;
}
printf("[%4d][read num = %d]", num++, regs);
for (i = 0; i < 20; ++i)
{
printf("<%#x>", tab_reg[i]);
}
printf("\n");
sleep(1);
}
}
- RTU-Master流程总结:
- 初始化 modbus 指针
- 设置从站ID
- 建立连接
- 读取保持寄存器/输入寄存器/离散输入/线圈输入
- 写单个寄存器/多个寄存器/多位数据
- 关闭连接
- RTU slave
#include
#include
#include
#include
#include
#include "modbus.h"
int main(void)
{
int i = 0;
int rc = 0;
modbus_t *ctx = NULL;
modbus_mapping_t *mb_mapping = NULL;
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
//打开端口: 端口,波特率,校验位,数据位,停止位
ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
//设置从机地址
modbus_set_slave(ctx, 1);
//设置串口模式
//modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
//设置RTS
//modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
//建立连接
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
mb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0,
MODBUS_MAX_READ_REGISTERS, 0);
if (mb_mapping == NULL) {
fprintf(stderr, "Failed to allocate the mapping: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
//初始化几个寄存器
mb_mapping->tab_registers[0] = 1;
mb_mapping->tab_registers[1] = 2;
mb_mapping->tab_registers[2] = 3;
mb_mapping->tab_registers[3] = 4;
mb_mapping->tab_registers[4] = 5;
mb_mapping->tab_registers[5] = 6;
while (1)
{
memset(query, 0, sizeof(query));
rc = modbus_receive(ctx, query);
if (rc > 0) {
modbus_reply(ctx, query, rc, mb_mapping);
} else if (rc == -1) {
//Connection closed by the client or error
break;
}
}
printf("Quit the loop: %s\n", modbus_strerror(errno));
modbus_mapping_free(mb_mapping);
if (s != -1) {
close(s);
}
modbus_close(ctx);
modbus_free(ctx);
}
RTU-Slave流程总结:
- 初始化 modbus 指针;
- 设置从站ID;
- modbus_mapping_new初始化寄存器,返回一个modbus_mapping_t 指针;
- 建立连接;
- 调用 modbus_receive 函数判断串口的接收数据,负责接收处理及回复。
- TCP master
#include
#include
#include
#include
#include
#include
#include "modbus.h"
void main(void)
{
int i;
int regs = 0;
int num = 0;
modbus_t *ctx = NULL;
uint16_t tab_reg[64] = {0};
ctx = modbus_new_tcp("127.0.0.1",8000);
modbus_set_slave(ctx, 1);
modbus_connect(ctx);
modbus_set_response_timeout(ctx, 0, 1000000);
while (1)
{
memset(tab_reg, 0, sizeof(tab_reg));
regs = modbus_read_registers(ctx, 0, 20, tab_reg);
printf("[%4d][read num = %d]", num++, regs);
for (i = 0; i < 20; i++)
{
printf("<%#x>", tab_reg[i]);
}
printf("\n");
sleep(1);
}
modbus_close(ctx);
modbus_free(ctx);
}
- TCP slave
#include
#include
#include
#include
#include
#include
#include "modbus.h"
int main(void)
{
int i = 0;
int rc = 0;
modbus_t *ctx = NULL;
modbus_mapping_t *mb_mapping = NULL;
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
//打开端口: ip, port
ctx = modbus_new_tcp("127.0.0.1", 8000);
//设置从机地址
modbus_set_slave(ctx, 1);
//建立连接
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
mb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0,
MODBUS_MAX_READ_REGISTERS, 0);
if (mb_mapping == NULL) {
fprintf(stderr, "Failed to allocate the mapping: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
//初始化几个寄存器
mb_mapping->tab_registers[0] = 1;
mb_mapping->tab_registers[1] = 2;
mb_mapping->tab_registers[2] = 3;
mb_mapping->tab_registers[3] = 4;
mb_mapping->tab_registers[4] = 5;
mb_mapping->tab_registers[5] = 6;
while (1)
{
memset(query, 0, sizeof(query));
rc = modbus_receive(ctx, query);
if (rc > 0) {
modbus_reply(ctx, query, rc, mb_mapping);
} else if (rc == -1) {
//Connection closed by the client or error
break;
}
}
printf("Quit the loop: %s\n", modbus_strerror(errno));
modbus_mapping_free(mb_mapping);
if (s != -1) {
close(s);
}
modbus_close(ctx);
modbus_free(ctx);
}