Вы сможете однозначно сказать, что такое “пауза в 1.5 символа” в Modbus RTU?
Берем символ 0xff и при 2 стоп битах без четности. На линии rs-485 это выглядит как стартовый бит и далее “тишина” (она-же пауза) в 10 бит. Пауза в 1.5 символа – это 1.5*11 = 16.5 бит тишины.
Значит, если фрейм заканчивается значением 0xFF, то “истечением паузы 1.5 символа” будет считаться место 17-того бита после вывода сигнала старта последнего символа при случае его значения 0xFF?
Но это для принимающего устройства анализирующего шину означает, что после вывода последнего символа (или помехи) прошло всего 6 бит тишины, т.е. всего 0.5 символа, а не 1.5 ? Ну и куда эти 10/11-ых символа девать к 1.5 и 3.5 ?
Зашел случайно, тема интересная, т.к. сам не так давно вылизал высокоскоростной Modbus RTU на PIC и в принципе все получилось. Выражу свои мысли по поводу, может кому пригодится, может чего нового узнаю.
Итак. По поводу ляпов Modbus RTU, на самом деле в самом протоколе ляпов то и нет, есть неправильное понимание документа и как следствие практическая реализация. Единственный минус самого протокола - отсутствие регламентации на максимальные задержки между пакетами, или хотя бы на строгую необходимость их указании в документации на устройство с заявленным Modbus.
Нюанс №1:
Протокол Modbus RTU очень четко оговаривает: между символами (концом предыдущего и началом нового) не более 1.5 символа, между пакетами не менее 3.5 символа (но по хорошему с 3.5 символами в сети каждое устройство работать обязано, даже если оно само не может отвечать так быстро). И в этом главный подвох: в алгоритме нельзя ждать 3.5 символа и начинать обрабатывать пакет, т.к. через 3.5 символа по протоколу уже допускается новый пакет и нужно быть к нему готовым. Т.е обрабатывать пакет нужно уже через 1.5 символа и это четко указано на Figure 14 Modbus_over_serial_line_V1_02. Там видно, что обработка пакета идет через 1.5 символа, а через 3.5 символа уже нужно быть готовым ждать новый пакет.
Нюанс №2:
На практике возникает проблема высчитать 1.5 символа. Например в PIC в UART есть только прерывание по окончанию приема символа. И он срабатывает в любом случае ровно через 11 бит после получения стартового (неважно был стоповый бит или нет). После успешного приема символа запускаем таймер, но не 1.5 символа, а 2.5 символа, т.к. UART не информирует о приеме стартового бита, только об окончании. Таким образом если через паузу 2.5 символа с момента предыдущего символа UART так и не получил новый символ , то 1.5 символа гарантированно прошло, хоть мы и простояли зря символ, но таков уж UART.
Нюанс №3
После паузы 1.5 символа (а по факту 2.5 символа) нужно переходить к обработке всего пакета. Т.к. через 3.5 символа нужно уже быть готовым к новому пакету, то на обработку пакета и CRC времени остается лишь 1 символ. При 19200 - это 0.573 мс, ну а для скоростей выше 19200 это даже по более 0.714 мс (1.75 мс - (0.75 мс+1 символ)).
За это время вычислить CRC довольно сложно, особенно если пакет большой. Однако стандарт дает простую рекомендацию: сначала проверить адрес устройства в начале пакета, если адрес не наш, обнуляем пакет без проверки CRC и тогда должны успеть до окончания таймера 3.5 символа. А если адрес наш, то можем вычислять CRC хоть 50-100 мс ведь Modbus этого и не запрещает, сеть ведь ждет нашего ответа.
Об этом комментарий №5 под Figure 14: After detection of the end of frame, the CRC calculation and checking is completed. Afterwards the address field is analysed to determine if the frame is for the device. If not the frame is discarded. In order to reduce the reception processing time the address field can be analysed as soon as it is received without waiting the end of frame. In this case the CRC will be calculated and checked only if the frame is addressed to the slave (broadcast frame included).
Итого, правильный Slave Modbus RTU не обязан отвечать быстро, но обязан не пропустить от мастера свой запрос, если параллельно с ним есть быстрые слейвы, которые могут отвечать с задержкой 3.5 символа. По факту, многие слейвы принимают пакет другого слейва и уходят на расчет CRC, а в это время мастер уже шлет следующий запрос именно ему, который тот естественно не принимает или начинает принимать где нибудь в середине.
И проявляется это очень просто - если подключение точка-точка - проблем нет, то как добавляется несколько слейвов - начинаются падения в сети и лечится увеличением задержки мастера на новый запрос.
По поводу помех:
Если была помеха хоть на одном символе, которая, например, исказила стартовый или стоповый бит, то проблем нет - обнуляем весь пакет и снова мгновенно запускаем прием UART с нуля, куски оставшегося сообщения будут неизбежно обнуляться на ошибочных символах, либо в конце пакета по паузе 1.5 символа (это уже маловероятно).
Если помеха (стартовый бит) проникла в паузу 1.5 символа в конце пакета, то если сообщение было нам, то за помехой новых пакетов не будет и будет опять задержка 1.5 символа (и можно даже эту помеху исключить, посчитав CRC без последнего байта). А если после помехи пошел новый пакет, который склеится с предыдущим, то значит это однозначно не нам и мы обнулим склеенный пакет (2-й пакет мог быть конечно адресован нам, но выцеплять его в сообщении долго, проще не ответить).
Таким образом Modbus RTU очень даже и неплохой протокол при грамотной реализации. В наших изделиях мы имеем возможность работать на частотах 230.4 кбод с задержками между пакетами от 0.3 мс (не используя ограничения t3.5=1.75 мс и t1.5=0.75 мс) стабильно обеспечивая до 500 транзакций в секунду без ошибок. Одна проблема - таких быстрых контроллеров на пальцах посчитать.
На практике есть контроллеры которые работают c Modbus RTU на скоростях до 4.5 Mbit т.е. это тот же Modbus RTU но с паузами 3.5 символа на всех скоростях (а не 1.75 мс) . По физике и скоростям такой Modbus RTU ничем не уступает Profibus DP, который работает до 12 Мбит,т.к. тот же RS-485.