libmodbus 开源库地址:https://github.com/stephane/libmodbus
安装必要的软件 sudo apt-get install pkg-config autoconf automake make libtool
编译 libmodbus ./autogen.sh && ./configure --prefix=/usr && && make && sudo make install
测试代码编译需要使用 pkg-config,例如:
gcc random-test-server.c -o random-test-server `pkg-config --libs --cflags libmodbus`
/*
函数作用:创建一个 modbus_t 结构
参数说明:
ip 指定该客户端要建立连接的服务器的IP地址。NULL值可用于侦听服务器模式下的任何地址
port TCP端口。将端口设置MODBUS_TCP_DEFAULT_PORT为使用默认端口 (502)。使用大于或等于1024的端口号很方便,因为不需要管理员权限。
返回值:
如果成功,该函数应返回一个指向modbus_t结构的指针。否则,它将返回NULL并将errno设置为以下定义的值之一。
*/
modbus_t *modbus_new_tcp(const char *ip, int port);
示例代码:
modbus_t *ctx;
ctx = modbus_new_tcp("127.0.0.1", 1502);
if (ctx == NULL) {
fprintf(stderr, "Unable to allocate libmodbus context\n");
return -1;
}
/*
函数作用:连接到一个 Modbus TCP 服务器
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
返回值:
成功:该函数应返回0
失败:将返回-1,并将errno设置为基础平台的系统调用所定义的值之一。
*/
int modbus_connect(modbus_t *ctx);
示例代码:
modbus_t *ctx;
ctx = modbus_new_tcp("127.0.0.1", 502);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
/*
函数作用:关闭 modbus 连接
*/
void modbus_close(modbus_t *ctx);
/*
函数作用:释放 modbus_t 环境
*/
void modbus_free(modbus_t *ctx);
/*
函数作用:读取线圈状态,使用功能码 0x01。地址范围:0区(00001-09999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 起始地址
nb 地址长度
dest 读取结果(必须注意分配足够的内存以将结果存储在dest中,注意数据类型为 uint8_t)
返回值:
如果成功,该函数应返回读取位数。否则它将返回-1并设置errno
*/
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
示例代码:
int i, rc;
uint8_t bit_reg[32];
memset(bit_reg, 0, sizeof(bit_reg));
rc = modbus_read_bits(mb, 0, 10, bit_reg);
if(rc == -1)
{
printf("%s\n", modbus_strerror(errno));
}
for(i = 0; i < rc; i++)
{
printf("reg[%d]=%d\t(0x%X)\n", i, bit_reg[i], bit_reg[i]);
}
/*
函数作用:读取离散量输入,使用功能码 0x02,地址范围:1区(10001-19999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 起始地址
nb 地址长度
dest 读取结果(必须注意分配足够的内存以将结果存储在dest中,注意数据类型为 uint8_t)
返回值:
如果成功,该函数应返回读取位数。否则它将返回-1并设置errno
*/
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
示例代码:
int i, rc;
uint8_t bit_reg[32];
memset(bit_reg, 0, sizeof(bit_reg));
rc = modbus_read_input_bits(mb, 0, 10, bit_reg);
if(rc == -1)
{
printf("%s\n", modbus_strerror(errno));
}
for(i = 0; i < rc; i++)
{
printf("reg[%d]=%d\t(0x%X)\n", i, bit_reg[i], bit_reg[i]);
}
/*
函数作用:读取保持寄存器,使用功能码 0x03,地址范围:4区(40001-49999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 起始地址
nb 地址长度
dest 读取结果(必须注意分配足够的内存以将结果存储在dest中,注意数据类型为 uint16_t)
返回值:
如果成功,该函数应返回读取位数。否则它将返回-1并设置errno
*/
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
示例代码:
int i, rc;
uint16_t tab_reg[32];
memset(tab_reg, 0, sizeof(tab_reg));
rc = modbus_read_input_bits(mb, 0, 10, tab_reg);
if(rc == -1)
{
printf("%s\n", modbus_strerror(errno));
}
for(i = 0; i < rc; i++)
{
printf("reg[%d]=%d\t(0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
/*
函数作用:读取输入寄存器,使用功能码 0x04,地址范围:3区(30001-39999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 起始地址
nb 地址长度
dest 读取结果(必须注意分配足够的内存以将结果存储在dest中,注意数据类型为 uint16_t)
返回值:
如果成功,该函数应返回读取位数。否则它将返回-1并设置errno
*/
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
示例代码:
int i, rc;
uint16_t tab_reg[32];
memset(tab_reg, 0, sizeof(tab_reg));
rc = modbus_read_input_registers(mb, 0, 10, tab_reg);
if(rc == -1)
{
printf("%s\n", modbus_strerror(errno));
}
for(i = 0; i < rc; i++)
{
printf("reg[%d]=%d\t(0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
/*
函数说明:写单个线圈,使用功能码 0x05,地址范围:0区(00001-09999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 线圈地址
status 线圈状态。(线圈状态只有 ON 和 OFF 两种值,所以 status 传入非 0 值,线圈状态被设置为 ON,status 传入 0 值,线圈状态被设置为 OFF)
返回值:
如果成功,该函数应返回1。否则它将返回-1并设置errno。
*/
int modbus_write_bit(modbus_t *ctx, int addr, int status);
示例代码:
for(i = 0; i < 10; i++)
{
rc = modbus_write_bit(mb, i, 1);
if(rc == -1)
{
printf("addr %d write failed\n", i);
}
sleep(1);
}
/*
函数作用:写单个保持寄存器,使用功能码 0x06,地址范围:4区(40001-49999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 线圈地址
value 要设置的寄存器值
*/
int modbus_write_register(modbus_t *ctx, int addr, const uint16_t value);
示例代码:
for(i = 0; i < 10; i++)
{
rc = modbus_write_register(mb, i, i*16);
if(rc == -1)
{
printf("addr %d write failed\n", i);
}
sleep(1);
}
/*
函数作用:写多个线圈,使用功能码 0x0F,地址范围:0区(00001-09999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 起始地址
nb 地址长度
src 存储要设置的线圈值的数组
返回值:
如果成功,该函数应返回已写入的位数。否则它将返回-1并设置errno。
*/
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
示例代码:
const uint8_t src8_t[10] = {0, 1, 1, 0, 1, 0, 1, 0, 1, 1};
rc = modbus_write_bits(mb, 0, 10, src8_t);
if(rc == -1)
{
printf("write bits failed, %s\n", modbus_strerror(errno));
}
/*
函数作用:写多个保持寄存器,使用功能码 0x10,地址范围:4区(40001-49999)
参数说明:
ctx modbus_new_tcp 创建的 modbus_t 结构体
addr 起始地址
nb 地址长度
src 存储要设置的寄存器值的数组
返回值:
如果成功,该函数应返回已写寄存器的数量。否则它将返回-1并设置errno。
*/
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
示例代码:
const uint16_t src16_t[10] = {100, 200, 179, 213, 3254, 322, 432, 311, 442, 797};
rc = modbus_write_registers(mb, 0, 10, src16_t);
if(rc == -1)
{
printf("write registers failed, %s\n", modbus_strerror(errno));
}