- libmodbus 支持 RTU 方式和 TCP/IP 方式;
- 传感器使用的是modbus RTU方式
- 构造RTU数据帧,并且响应 modbus 请求的一方是 server/slave,而发出请求的一方是 client/master,并且双方通信总是由 client/master 一方发起。所以温湿度传感器是server/slave一方
1. TCP/IP 方式
1.创建一个 modbus_t 类型的 context
// modbus_t *modbus_new_tcp(const char *ip, int port);
modbus_t *ctx;
ctx = modbus_new_tcp("192.168.2.212", 1502);
modbus_set_debug(ctx, TRUE); // 是否显示调试信息
2.建立连接
// int modbus_connect(modbus_t *ctx);
modbus_connect(ctx);
3.设置超时时间:(这一步不一定需要)
struct timeval t;
t.tv_sec = 0;
t.tv_usec = 1000000;//1000ms
modbus_set_response_timeout(ctx,&t);
4.读写寄存器的值
/* SINGLE REGISTER */
// int modbus_write_register(modbus_t *ctx, int addr, int value);
// int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
rc = modbus_write_register(ctx, addr, tab_rq_registers[0]);
if (rc != 1) {
// error
} else {
rc = modbus_read_registers(ctx, addr, 1, tab_rp_registers);
if (rc != 1) {
// error
} else {
// if error
}
}
5.释放并关闭modbus
modbus_close(ctx);
modbus_free(ctx);
2. RTU
1.创建一个modbus_t类型的context,用来打开串口:
// modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);
modbus_t *ctx;
ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 1);
modbus_set_slave(ctx, 0x01); // 设置 slave 地址, 温湿度传感器的modbus站地址为0x01
2.建立连接
modbus_connect(ctx);//建立和传感器的连接
3.设置超时时间:
struct timeval t;
t.tv_sec = 0;
t.tv_usec = 1000000;//1000ms
modbus_set_response_timeout(ctx,&t);
5.读写寄存器的值
.同 TCP/IP
示例1. TCP/IP
/*
* The client of modbus tcp.
* test 2 register
*
* 2017-10-26
*/
#include
#include
#include
#include
#include
int main(void)
{
modbus_t *ctx=NULL; // context
int addr=0; // address
int rc=0; // received
int nb = 3; // the number of bit
uint16_t *tab_rq_registers=NULL;
uint16_t *tab_rp_registers=NULL;
/* TCP */
ctx = modbus_new_tcp("192.168.2.29", 1502);
modbus_set_debug(ctx, TRUE);
// connect
if (-1 == modbus_connect(ctx))
{
fprintf(stderr, "Conncetion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
/* Allocate and initialize the memory spaces. */
tab_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
memset(tab_rq_registers, 0, nb * sizeof(uint16_t));
tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
memset(tab_rp_registers, 0, nb * sizeof(uint16_t));
// write
tab_rq_registers[0] = 25;
tab_rq_registers[1] = 2;
tab_rq_registers[2] = 88;
rc = modbus_write_registers(ctx, addr, nb, tab_rq_registers);
if (rc != nb)
{
printf("ERROR modbus_write_bits single (%d)\n", rc);
printf("address = %d\n", addr);
}
// read
rc = modbus_read_registers(ctx, addr, nb, tab_rp_registers);
if (rc != nb)
{
printf("ERROR modbus_read_bits single (%d)\n", rc);
printf("address = %d\n", addr);
}
for (int i = 0; i < nb; ++i)
{
printf("%d%c", tab_rp_registers[i], (i==nb-1)?'\n':' ');
}
free(tab_rq_registers);
free(tab_rp_registers);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
示例2. RTU
#include
#include
#include
#include
#include
int main(void)
{
modbus_t *ctx=NULL; // context
int addr=0; // address
int rc=0; // received
int nb = 3; // the number of bit
uint16_t *tab_rq_registers=NULL;
uint16_t *tab_rp_registers=NULL;
/* RTU */
ctx = modbus_new_rtu("/dev/ttySAC3",9600,'N',8,1);
modbus_set_debug(ctx, TRUE);
modbus_set_slave(ctx, 0x01); // 设置从机地址
// connect
if (-1 == modbus_connect(ctx))
{
fprintf(stderr, "Conncetion failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
// 读取数据
uint16_t tab_reg[2]; // 存放要读的数据
int regs=modbus_read_registers(ctx,0,2,tab_reg);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
[reference]
[1] stuyou 使用libmodbus读传感器流程
[2] CUC_Tony Modbus RTU程序开发解读