上一篇,我们讲述了基于libmodbus库进行主机 modbus通信开发案例,libmodbus协议栈2—— Linux下 modbus RTU master 开发案例,本文介绍一下如何进行从机开发。
我们还是先对开发流程做个梳理:
1. 初始化 modbus 指针
2. 设置从站ID
3. 使用modbus_mapping_new初始化寄存器,返回一个modbus_mapping_t 指针。我们的工程数据只需要存放到
这个指针里,就可以了。
4. 建立连接
5. 调用 modbus_receive 函数,来轮询判断串口的接收数据。该函数不只是负责接收,还有处理,回复。
对于从机开发,modbus_mapping_t数据结构的理解也很重要,具体内容如下:
typedef struct {
int nb_bits;
int start_bits;
int nb_input_bits;
int start_input_bits;
int nb_input_registers;
int start_input_registers;
int nb_registers;
int start_registers;
uint8_t *tab_bits;
uint8_t *tab_input_bits;
uint16_t *tab_input_registers;
uint16_t *tab_registers;
} modbus_mapping_t;
这个 结构体很容易理解,就是包含各种寄存器的个数,以及各种寄存器的数组指针, 很明显,对这个结构体的初始化,必然也是使用malloc 申请一块专用内存。我们将工程数据刷新存放到这块内存中即可。
我们还是举例来分析,代码如下:
/*
*----------------------------------------
*
* modbus-rtu-slave.c
*
*----------------------------------------
*/
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int s = -1;
modbus_t *ctx = NULL;
modbus_mapping_t *mb_mapping = NULL;
int rc;
int use_backend;
//初始化modbus rtu
ctx = modbus_new_rtu("/dev/ttySP0", 9600, 'N', 8, 1);
//设定从设备地址
modbus_set_slave(ctx, 1);
//modbus连接
modbus_connect(ctx);
//寄存器map初始化
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 ){
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
//轮询接收数据,并做相应处理
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);
}
/* For RTU, skipped by TCP (no TCP connect) */
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
进一步总结梳理下:
1. 引用modbus.h 必须的。
2. 使用modbus_new_rtu,功能同上一篇 主机 介绍。
3. 设置设备地址,功能同上一篇 主机介绍。
4. 初始化 寄存器,这个函数 modbus_mapping_new,内部 调用的函数是:
modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
int nb_registers, int nb_input_registers)
{
return modbus_mapping_new_start_address(
0, nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers);
}
从这里可以看出,libmodbus设定的寄存器的起始地址都是从0开始的,这个一般情况下都是可以直接 使用的,如果真要实现从非0开始,那就要应用程序里再调用一次modbus_mapping_new_start_address,设定想要的函数即可。
5. 建立连接。
6. 在主循环中,调用modbus_receive(ctx, query);这个函数不仅仅是负责串口接收,而且还会对数据进行筛选,根据主机的需要打包数据,返回相应 数据给主机。
7. 退出modbus通信后,依然是先关闭 连接,比如关闭串口, 关闭socket。
8. 释放modbus数据指针(内存区域)和modbus寄存器数据指针(内存区域)。