Modbus master example1

This is a message copy from the iprog [1 ] forum:

Автор: Alexey Rakov Дата: 16.04.10 18:29

Накатал такой тест на tcl (считается относительно медленным скриптовым языком).

Погонял с тестовым modbus-tcp slave'ом. Довольно резво все выходит - больше 500 запросов в секунду, период получается меньше 2 мс. Мастер: Pentium 4 1800МГц, подчиненный вообще нетбук с атомом, сеть: какой-то нонейм хаб.

Leks, обратите внимание, после посылки запроса, сразу же, без всяких пауз, идет чтение данных. Сокет сконфигурирован для работы в асинхронном режиме, если этого не сделать, чтение будет блокировать работу программы, и если данных не будет, прога зависнет. По любой ошибке сразу выход (это всего лишь тест :).

Ну и конечно, полученные результаты мало о чем говорят, реальный контроллер может гораздо медленнее отвечать.

На WinSockAPI в С или Делфи для ожидания данных с таймаутом лучше использовать select() с выставленным таймаутом, либо устанавливать обработчики сетевых событий и таймеров.


# простой модбас запрос, чтение адресов 400001-400010
set query [binary format H* 0000000601030000000A]

# устанавливаем соеденение с подчиненным устройством
set connection [socket 192.168.3.241 502]
fconfigure $connection -blocking 0 -buffering none -translation binary

set perftime [clock milliseconds]
set perfcnt 0
set transact_id 0

# цикл опроса
while {on} {
    # формируем первые два байта заголовка и посылаем запрос
    puts -nonewline $connection "[binary format S $transact_id]$query"

    set response {}
    set resplen 29      ;# длина ответа должна быть 29 байт !
    set begtime [clock milliseconds]

    # ждем ответа
    while {$resplen} {
        if { [eof $connection] } {
            # соеденение закрыли на той стороне
            puts "connection closed"
            exit
        }
        # читаем прешедшие данные
        if { [catch {read $connection $resplen} data] } {
            # другая ошибка сокетов
            puts $errorInfo
            exit
        } elseif { [string length $data] } {
            # какие-то данные пришли

            # добавляем, то что пришло к ответу
            append response $data
            # вычисляем, сколько еще осталось прочитать
            incr resplen -[string length $response]
        } else {
            # ничего не пришло, проверка на таймаут
            if { [clock milliseconds] - $begtime >= 300 } {
                puts "connection timeout"
                exit
            }
        }
    }

    # вычисляем идентификатор транзакции
    binary scan $response S resp_id
    set resp_id [expr {$resp_id & 0xFFFF}]

    # проверям соответствие идентификаторов запроса и ответа
    if {$transact_id != $resp_id} {
        puts "modbus error"
        exit
    }

    # раз в 10 секунд смотрим, сколько транзакций прошло
    # вычисляем производительность и выводим на печать
    incr perfcnt
    if { [clock milliseconds] - $perftime >= 10000 } {
        set queryinsec [format %.2f [expr {$perfcnt / 10.0}]]
        set period [format %.4f [expr {10.0 / $perfcnt}]]
        puts "perfomance: $queryinsec queries in sec, period: $period"
        set perfcnt 0
        set perftime [clock milliseconds]
    }
}