简体   繁体   中英

Multiple RS485 slaves with libmodbus

I have multiple slaves on a RS485 bus. I have been using pymodbus so far but I'm not quite happy with it's performance and other issues. So I wanted to to test libmodus and use that instead.

I wrote a minimal program that reads the model number of my slaves

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <modbus.h>
#include <errno.h>


char *bigendian_vec_to_str(uint16_t *vec, size_t vec_size, char *buff, size_t buff_len)
{
    memset(buff, 0, sizeof *buff * buff_len);
    int i;

    for(i = 0; i < vec_size; ++i)
    {
        uint16_t fl = vec[i] >> 8;
        uint16_t sl = vec[i] & 0xff;

        if(2*i >= buff_len - 1)
            return buff;

        if(fl == 0)
            return buff;

        buff[2 * i] = fl;

        if(2*i + 1 >= buff_len - 1)
            return buff;

        if(sl == 0)
            return buff;

        buff[2 * i + 1] = sl;
    }

    return buff;
}

char *get_model_name_of(modbus_t *modbus, int slave, char *buff, size_t buff_len)
{
    modbus_flush(modbus);
    modbus_set_slave(modbus, slave);

    int rc; 
    uint16_t reg[9];

    memset(reg, 0, sizeof reg);

    rc = modbus_read_registers(modbus, 0xe, 8, reg);
    if (rc == -1) {
        fprintf(stderr, "Error %d while reading: %s\n", errno, modbus_strerror(errno));
        return NULL;
    }   
    return bigendian_vec_to_str(reg, 8, buff, buff_len);
}


int main(void)
{
    modbus_t *modbus = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);

    modbus_rtu_set_serial_mode(modbus, MODBUS_RTU_RS485);

    if (modbus_connect(modbus) == -1) {
        fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
        modbus_free(modbus);
        return -1;
    }

    char buff[1024];
    int i;

    for(i = 2; i < 5; ++i)
    {
        printf("Model of slave %d: %s\n", i, get_model_name_of(modbus, i, buff, sizeof buff));
    }

    modbus_free(modbus);
    return 0;
}

When I ran this code I got

Model of slave 2: LEFS25B-600
Error 110 while reading: Connection timed out
Model of slave 3: (null)
Model of slave 4: LEHF10K2-16

and it seemed strange that the 2nd module was not responding. So I looped get_model_name_of through 2,3,4,2,3,4,2,3,4.... and every second read attempt ended with Error 110 while reading: Connection timed out . After the iine modbus_set_slave(modbus, slave); I added

usleep(0.005 * 1000000);

and then I didn't get timeouts anymore. I read the man pages twice and I didn't find anything warning me about this. I also searched google but none of the "similar" threads I found were of any help.

What is the best way to deal with multiple slaves? Why does adding a sleep of half of milisecond help here? I mean the code on libmodus does

static int _modbus_set_slave(modbus_t *ctx, int slave)
{
    /* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
    if (slave >= 0 && slave <= 247) {
        ctx->slave = slave;
    } else {
        errno = EINVAL;
        return -1;
    }

    return 0;
}

is setting an internal value in the context. Are there any time constraints between the change of an internal value in the context and reading/writing to the bus? If so, how long should I wait after a set_slave ? Why does libmodbus set the slave id globally instead of having it as a parameter in the read / write method as other libraries (like pymodbus ) do?

Or am I using this API just incorrectly?

Thanks

I may be wrong.. but.. as I understand it. The modbus master sends out a request, targeted at a specfic slave number. The intention is to recieve a reply from the targeted slave and then send a request to the next slave and await a reply from second slave. If the requests are sent out without waiting for reply from the first slave.. then there is a possibility to miss the reply from the second slave(or third or whatever number slave) , while the first slave reply is being sent and recieved by the master.

I am not good in C programming.. but I recommend you check this..as I think that may be why you adding a delay seems to help... ( Also.. part of Modbus protocol does require a pause in signal transmission to define start and end of transmission.) If I am correct , then the use of a delay will only work well if you know the size of data being sent and the time to calculate a response..For other situations a handshake of some kind would be safe.. Such as read a coil.. that indicates whether data is refreshed and ready to be read from the slave as a possible traffic light . to control timing of requests going to other slave and to avoid collision of responses. Again.. I am not good in C and if I have misinterpreted the program.. please ignore what I have said.. If it helps.. I would be happy hear.

Peter

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM