Thread: modbus rtu c programming

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    37

    modbus rtu c programming

    Dear all:

    I am trying to use some function I downloaded from the internet to connect to a modbus meter, the connection is fine, but when I try to read the data off the registers, it kept returning -1, reading unsuccessful

    Code:
    int readState = modbus_read_holding_registers(2, 0, 2, mbusRegisters);

    Meter register map:
    Address word Item(description) Code Unit Sign
    0000H 2 Watt Hour 03H WH Unsigned
    0002H 1 Watt 03H W Unsigned
    0003H 1 Voltage 03H V Unsigned
    0004H 1 Currant 03H A Unsigned




    Below is the source code of the function I used (open source) :
    (from Modbus master C library/code for Linux serial device)


    Code:
    int modbus_read_holding_registers(unsigned char slave_id, unsigned char start_address, unsigned int num_registers, unsigned short * modbus_registers)
    {
        unsigned char transmit[255];
    
            //check return values
            unsigned char *retValue;
            int i;
            retValue = transmit;
    
        transmit[0] = slave_id;
    //      printf("slave_id: %c", transmit[0]);
        transmit[1] = MB_READ_HOLDING_REGISTERS;
        transmit[2] = start_address >> 8;
        transmit[3] = start_address & 0xFF;
        transmit[4] = num_registers >> 8;
        transmit[5] = num_registers & 0xFF;
        short crc = CRC16(transmit, 6);
        transmit[6] = crc;
        transmit[7] = crc >> 8;
    
            for (i=0; i<8; i++) {
                    printf("return value [%d] = %x\n", i, *(retValue+i));
            }
    
        if (write(fd, transmit, 8) == -1) {
            perror("Unable to write to serial device");
            mb_datagram_status = MB_ERROR;
            return -1;
        }
    
    
        mb_waiting_for_reply = 1;
    
        struct timespec time;
        clock_gettime(CLOCK_REALTIME, &time);
        time.tv_sec += 1;
    
    
        /* Time out here if no bytes have been received within the time out period */
        if (pthread_cond_timedwait(&datagram_start_receiving, &waiting_for_reply, &time) == ETIMEDOUT) {
     mb_datagram_status = MB_TIMEOUT;
            timeout_error_count++;
            return -1;
        }
    
            printf("after pthread_cond_timedwait()\n");
    
        pthread_cond_wait(&datagram_finished_receiving, &waiting_for_reply);
    
        mb_waiting_for_reply = 0;
    
        if (mb_datagram_status == MB_OK) {
    
            unsigned char byte_count = modbus_read_num_bytes(datagram);
            mb_datagram_status = MB_OK;
    
            unsigned char * datagram_data = datagram + 3;
    
            int i;
            for(i = 0; i < byte_count / 2; i++) {
                modbus_registers[i] = datagram_data[i * 2] << 8 | datagram_data[i * 2 + 1];
            }
            return byte_count / 2;
    
        } else {
            return mb_datagram_status;
        }
    
    }
    Am I using the function wrong, or it's a modbus thing?

    Any help is appreciated, thanks.

    barramundi9

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Is this you as well?
    modbus starting address question

    Did you try the response you got, namely swapping over the crc bytes?

    Have you called modbus_init() at the start?
    Have you tried putting some prints in receive_thread() to see if it actually does anything.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2011
    Posts
    37
    Hi, Salem, thanks for the reply, I know it's been a month ...

    It was me and I did try swapping the crc bytes but it still returns -1

    And I did called modbus_init() first and it was connected, it dies at

    Code:
     if (pthread_cond_timedwait(&datagram_start_receiving, &waiting_for_reply, &time) == ETIMEDOUT) {
                 mb_datagram_status = MB_TIMEOUT;
                 timeout_error_count++;
                 return -1;
      }
    Any ideas?

    Thanks


    Quote Originally Posted by Salem View Post
    Is this you as well?
    modbus starting address question

    Did you try the response you got, namely swapping over the crc bytes?

    Have you called modbus_init() at the start?
    Have you tried putting some prints in receive_thread() to see if it actually does anything.

  4. #4
    Registered User
    Join Date
    May 2011
    Posts
    37
    I decide to rewrite the code and the following is what I have done:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #include <fcntl.h>
    #include <unistd.h>
    
    #include <termios.h> //set baud rate
    
    #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
    
    #define device "/dev/ttyUSB0"
    #define MyBaudRate 9600
    #define rec_buf_wait_2s 2
    
    int read_data_tty (int fd, char *rec_buf, int rec_wait) {
            int retval;
            fd_set rfds;
            struct timeval tv;
    
            int ret, pos;
            tv.tv_sec = rec_wait;
            tv.tv_usec = 0;
            pos = 0;
    
            while (1) {
                    FD_ZERO (&rfds);
                    FD_SET (fd, &rfds);
    
                    retval = select (fd+1, &rfds, NULL, NULL, &tv);
    
                    if (retval == -1) {
                            perror("select()");
                            break;
                    } else if (retval) {
                            ret = read(fd, rec_buf+pos, 2048);
                            pos += ret;
                            if (rec_buf[pos-2] == '\r' && rec_buf[pos-1] == '\n') {
                                    FD_ZERO (&rfds);
                                    FD_SET (fd, &rfds);
                                    retval = select (fd+1, &rfds, NULL, NULL, &tv);
    
                                    if (!retval) {
                                            break;
                                    }
                            }
                    } else {
                            break;
                    }
            }
    
            return 1;
    }
    
    int device_485_receive (int fd) {
            ssize_t ret;
            char rec_buf[1024];
            int i;
            char *send_buf = "02030202f925";
    
            for (i=0; i<10; i++) {
                    ret = write (fd, send_buf, strlen(send_buf));
                    if (ret == -1) {
                            printf("write device %s error\n", device);
                            return -1;
                    }
    
                    if (read_data_tty(fd, rec_buf, rec_buf_wait_2s)) {
                            printf("%s\n", rec_buf);
                    } else {
                            printf("read_error\n");
                    }
    
                    //if ((read(fd, rec_buf, strlen(rec_buf))) == -1) {
                    //      printf("error reading string\n");
                    //      return -1;
                    //} else {
                    //      printf("%s\n", rec_buf);
            }
            return 0;
    }
    
    
    int main () {
    
            int fd;
            //open serial port
            fd = open (device, O_RDWR);
            //check if device opened properly
            if (fd == -1) {
                    printf("open device %s error\n", device);
            } else {
                    //set baudrate
                    struct termios options;
                    cfsetispeed (&options, MyBaudRate);
                    cfsetospeed (&options, MyBaudRate);
                    device_485_receive(fd);
            }
    
            if (close(fd) != 0) {
                    printf("close device error\n");
            }
    
    
            return 0;
    }
    the send_buf string "02 03 02 02 f9 25" (space included here for clarity)is the modbus command, 02 is the slave id, 03 is function code, the following 02 is the starting address and 02 means 2 registers are to be read and f9 25 are the crc values.

    When I execute the program, it keeps returning the value 4, any ideas???

    Thanks.

    barramundi9


    Quote Originally Posted by barramundi9 View Post
    Hi, Salem, thanks for the reply, I know it's been a month ...

    It was me and I did try swapping the crc bytes but it still returns -1

    And I did called modbus_init() first and it was connected, it dies at

    Code:
     if (pthread_cond_timedwait(&datagram_start_receiving, &waiting_for_reply, &time) == ETIMEDOUT) {
                 mb_datagram_status = MB_TIMEOUT;
                 timeout_error_count++;
                 return -1;
      }
    Any ideas?

    Thanks

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    When you say that it "keeps returning the value 4", do you mean
    that this statement in device_485_receive prints 4:
    Code:
    printf("%s\n", rec_buf);
    What do you expect it to print?


    And are you supposed to be sending characters like you have here:
    Code:
            char *    send_buf = "02030202f925";
    or should it be (as your first post suggests) binary data, more like this:
    Code:
            unsigned char *  send_buf = "\x02\x03\x00\x02\x00\x02\xf9\x25";
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    Registered User
    Join Date
    May 2011
    Posts
    37
    Hello, oogabooga

    I actually tried send both and it still returns 4.

    I have given up on that and use libmodbus instead.

    libmodbus.org - News
    Libmodbus works like a charm.

    Thanks for the replies.


    barramundi9


    Quote Originally Posted by oogabooga View Post
    When you say that it "keeps returning the value 4", do you mean
    that this statement in device_485_receive prints 4:
    Code:
    printf("%s\n", rec_buf);
    What do you expect it to print?


    And are you supposed to be sending characters like you have here:
    Code:
            char *    send_buf = "02030202f925";
    or should it be (as your first post suggests) binary data, more like this:
    Code:
            unsigned char *  send_buf = "\x02\x03\x00\x02\x00\x02\xf9\x25";

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 04-10-2012, 10:51 AM
  2. Replies: 4
    Last Post: 12-11-2011, 04:25 PM
  3. open source code compile problems - modbus stack
    By noob in forum C Programming
    Replies: 2
    Last Post: 10-16-2009, 08:04 PM
  4. TCP IP Modbus
    By boschow in forum Networking/Device Communication
    Replies: 0
    Last Post: 03-27-2008, 12:20 PM
  5. Termios Flags Rs232 Serial Ttys0 Modbus Rtu
    By Mighty-D in forum Linux Programming
    Replies: 2
    Last Post: 10-31-2006, 11:53 AM