2015-08-28 2 views
0

Мы используем библиотеку libmodbus для считывания значений регистра с измерителя энергии EM6400, который поддерживает Modbus через RTU. Мы сталкиваемся с двумя следующими проблемами.modbus_read_register - время установления ошибки

1) Мы сталкиваемся проблема с modbus_read_registers API, это API возвращает -1 и сообщения об ошибке:

Ошибка соединения истекло: выберите.

После отладки библиотеки мы обнаружили, что эта проблема вызвана эхом байтов запроса в ответном сообщении. read() API-вызов в _modbus_rtu_recv сначала возвращает байты запросов, за которыми следуют байты ответа. В результате length_to_read вычисляется в compute_data_length_after_meta() на основе байтов запроса вместо байтов ответа (который содержит количество прочитанных байтов) и возникает проблема с тайм-аутом соединения. Мы попытались использовать версии libmodbus 3.0.6 и 3.1.2, но такая же проблема возникает и в обеих версиях.

2) modbus_rtu_set_serial_mode (ctx, MODBUS_RTU_RS485) возвращает "BAD дескриптор файла".

Проверьте, отсутствует ли какой-либо API-запрос, или какой-либо параметр установлен неправильно.

Наш пример кода для считывания значения регистра выглядит следующим образом.

int main() 
{ 

    modbus_t *ctx; 
    uint16_t tab_reg[2] = {0,0}; 
    float avgVLL = -1;; 
    int res = 0; 
    int rc; 
    int i; 
    struct timeval response_timeout; 
    uint32_t tv_sec = 0; 
    uint32_t tv_usec = 0; 
    response_timeout.tv_sec = 5; 
    response_timeout.tv_usec = 0; 

    ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'E', 8, 1); 
    if (NULL == ctx) 
    { 
        printf("Unable to create libmodbus context\n"); 
        res = 1; 
    } 
    else 
    { 
     printf("created libmodbus context\n"); 
     modbus_set_debug(ctx, TRUE); 
     //modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK |MODBUS_ERROR_RECOVERY_PROTOCOL); 
     rc = modbus_set_slave(ctx, 1); 
     printf("modbus_set_slave return: %d\n",rc); 
     if (rc != 0) 
     { 
         printf("modbus_set_slave: %s \n",modbus_strerror(errno)); 
     } 

     /* Commented - Giving 'Bad File Descriptor' issue 
     rc = modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485); 
     printf("modbus_rtu_set_serial_mode: %d \n",rc); 

     if (rc != 0) 
     { 
         printf("modbus_rtu_set_serial_mode: %s \n",modbus_strerror(errno)); 
     } 
     */ 

     // This code is for version 3.0.6 
     modbus_get_response_timeout(ctx, &response_timeout); 
     printf("Default response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec); 

     response_timeout.tv_sec = 60; 
     response_timeout.tv_usec = 0; 

     modbus_set_response_timeout(ctx, &response_timeout); 
     modbus_get_response_timeout(ctx, &response_timeout); 
     printf("Set response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec); 


     /* This code is for version 3.1.2 
     modbus_get_response_timeout(ctx, &tv_sec, &tv_usec); 
     printf("Default response timeout:%d sec %d usec \n",tv_sec,tv_usec); 

     tv_sec = 60; 
     tv_usec = 0; 

     modbus_set_response_timeout(ctx, tv_sec,tv_usec); 
     modbus_get_response_timeout(ctx, &tv_sec, &tv_usec); 
     printf("Set response timeout:%d sec %d usec \n",tv_sec,tv_usec); 
     */ 

     rc = modbus_connect(ctx); 
     printf("modbus_connect: %d \n",rc); 

     if (rc == -1) { 
         printf("Connection failed: %s\n", modbus_strerror(errno)); 
      res = 1; 
     } 

     rc = modbus_read_registers(ctx, 3908, 2, tab_reg); 
     printf("modbus_read_registers: %d \n",rc); 

     if (rc == -1) { 
         printf("Read registers failed: %s\n", modbus_strerror(errno)); 
      res = 1; 
     } 

     for (i=0; i < 2; i++) { 
      printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]); 
     } 

     avgVLL = modbus_get_float(tab_reg); 

     printf("Average Line to Line Voltage = %f\n", avgVLL); 

     modbus_close(ctx); 
     modbus_free(ctx); 
    } 
} 

Выхода этого образца следующим образом:

created libmodbus context 
modbus_set_slave return: 0 
modbus_rtu_set_serial_mode: -1 
modbus_rtu_set_serial_mode: Bad file descriptor 
Default response timeout:0 sec 500000 usec 
Set response timeout:60 sec 0 usec 
Opening /dev/ttyUSB0 at 19200 bauds (E, 8, 1) 
modbus_connect: 0 
[01][03][0F][44][00][02][87][0A] 
Waiting for a confirmation... 
ERROR Connection timed out: select 
<01><03><0F><44><00><02><87><0A><01><03><04><C4><5F><43><D4><C6><7E>modbus_read_registers: -1 
Read registers failed: Connection timed out 
reg[0]=0 (0x0) 
reg[1]=0 (0x0) 
Average Line to Line Voltage = 0.000000 

ответ

0

Выпуск 1), вероятно, является аппаратной проблемой, с "локальным эхом" включен в адаптере RS-485. Локальное эхо иногда используется для подтверждения отправки байтов данных на шине. Вам необходимо отключить его или найти другой адаптер RS-485.

Я написал об этом в документации моей библиотеки MinimalModbus Python: Local Echo

Он перечисляет несколько распространенных способов, чтобы отключить локальное эхо адаптеров RS-485.

+0

Я просмотрел документацию по libmodbus и нет флага для чтения/игнорирования ответа эха. SO, если OP имеет адаптер RS-485, который заставляет локальное эхо, может быть не так много, что можно сделать ... –

Смежные вопросы