libmodbus协议栈3—— Linux下 modbus RTU 从机 开发案例

    上一篇,我们讲述了基于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寄存器数据指针(内存区域)。

你可能感兴趣的:(Linux)