Что такое Floating Action Button? Быстрая и грязная реализация

Протокол ModBus, несмотря на множество специализированных протоколов, появившихся в последние десятилетия, все еще занимает лидирующие позиции в задачах автоматизации и диспетчеризации зданий и технологических процессов. Многие специалисты уже привыкли к его использованию, несмотря на его явную архаичность. Тем не менее, судя по статистике поисковых запросов и популярности статей о ModBus, явно существует пласт специалистов, надеюсь, что это молодое поколение, для которых будет полезно, еще раз на пальцах объяснить, что такое ModBus.

В российской википедии существует довольно обширная , в которой рассказывается история протокола, его основные достоинства и недостатки, терминология, модель данных и функционал. Не претендуя на полноту изложения, но в то же время, не боясь повториться, рассмотрим некоторые базовые вещи для тех, кому надо всего-то «два байта переслать».

Прежде всего, как представлены данные в устройстве поддерживающем ModBus. Это четыре таблицы с данными:

Таблица Тип элемента Тип доступа
Дискретные входы (Discrete Inputs) один бит только чтение
Регистры флагов (Coils) один бит чтение и запись
Регистры ввода (Input Registers) 16-битное слово только чтение
Регистры хранения (Holding Registers) 16-битное слово чтение и запись

В реальной практике чаще всего встречаются устройства, в которых есть только таблица Holding Registers, иногда объединённая с таблицей Input Registers.

Для доступа к этим таблицам существует ряд стандартный функций ModBus:

  • 1 (0x01) - чтение значений из нескольких регистров флагов (Read Coil Status).
  • 2 (0x02) - чтение значений из нескольких дискретных входов (Read Discrete Inputs).
  • 3 (0x03) - чтение значений из нескольких регистров хранения (Read Holding Registers).
  • 4 (0x04) - чтение значений из нескольких регистров ввода (Read Input Registers).

Запись одного значения:

  • 5 (0x05) - запись значения одного флага (Force Single Coil).
  • 6 (0x06) - запись значения в один регистр хранения (Preset Single Register).

Запись нескольких значений:

  • 15 (0x0F) - запись значений в несколько регистров флагов (Force Multiple Coils)
  • 16 (0x10) - запись значений в несколько регистров хранения (Preset Multiple Registers)

Из сказанного выше следует, что самые часто используемые функции ModBus это 3, 6 и 16 («Read Holding Registers», «Preset Single Register» и «Preset Multiple Registers» — соответственно).

Что происходит при чтении или записи регистра в ModBus устройство? Рассмотрим, для начала, протокол ModBus RTU. Он применяется для передачи данных по последовательным интерфейсам, таким как RS-232 или RS-485. Большинство современных устройств используют RS-485, так как он, во первых, как правило, двух проводной и во вторых, позволяет подключить несколько устройств в один шлейф.

Важно то, что при подобной топологии на одном шлейфе может быть только один ModBus Master, то есть устройства не могут свободно «общаться» между собой. На каждом шлейфе организуется четкая иерархия Master – Slave («Ведущий» – «Ведомый»). Ведомых, как уже было сказано, может быть несколько, а ведущий только один!

Адресная модель ModBus позволяет использовать адреса устройств с 1 по 247, что иногда вводит в заблуждение некоторых «проектологов», т.к. RS-485 позволяет подключить к одной шине, без усилителей и репитеров, только 32 устройства. На самом деле я рекомендую для стабильной работы, с приемлемым количеством повторных запросов, не превышать значение 20 устройств на одну шину RS-485.

Итак, для чтения одного Holding Register ведущий посылает запрос на адрес ведомого устройства с кодом функции 3 (Read Holding Registers), указанием адреса интересующего регистра и количеством регистров для чтения, в данном случае = 1. На что ведомый отвечает пакетом, в котором повторяет собственный адрес, номер обрабатываемой функции и, в поле данных размещает значение запрашиваемого регистра. Для чтения нескольких последовательных регистров в запросе ведущий просто указывает адрес первого и их количество.

В общем виде, работу функции 3 (Read Holding Registers) протокола ModBus можно представить так:

Теперь рассмотрим, чем отличается ModBus TCP от ModBus RTU. Во первых, нет ограничения на одного ведущего в сети, все устройства могут практически свободно «общаться» между собой. Во вторых используется другой формат пакета, добавился заголовок, что более типично для данной среды передачи.

Так как транспортом для передачи служит протокол TCP, то для адресации устройств ведущему необходимо знать IP адрес ведомого устройства и порт, на котором ведомый ожидает запросов. Стандартный порт для ModBus TCP протокола 502 , но некоторые среды программирования контроллеров, например CODESYS, позволяют его изменить. Тот же самый CODESYS, а точнее контроллеры, запрограммированные в этой среде или средах производных от CODESYS, при работе по протоколу ModBus TCP игнорируют поле «Unit ID» и отвечают на запросы для любого «Unit ID», а не выдают сообщение об ошибке. Это значит, что иногда, достаточно знать IP адрес и порт контроллера.

Довольно часто сталкиваюсь с непониманием модели OSI среди инженеров и проектировщиков АСУ ТП и АСУЗ. Поэтому вот еще одна картинка, разъясняющая то, как пакет ModBus TCP передается по Ethernet сети:

UPD (26.09.2016): Довольно неплохое русскоязычное видео на тему:

Интерфейс RS-48


Стандарт ANSI TIA/EIA-485, более известный как RS485, определяет сбалансированный способ надёжной передачи данных на длинные расстояния в условиях промышленных помех. Также стандарт определяет топологию сети и описывает способы согласования полного сопротивления линии интерфейса и предоставляет результаты лабораторных тестов.

Физически, интерфейс RS485 является дифференциальным, обеспечивает многоточечные соединения и позволяет передавать и принимать данные в обоих направлениях.

Упрощённо, сеть интерфейса RS485 представляет собой приемопередатчики, соединенные при помощи витой пары - двух скрученных проводов (см. рис. 2.1).


Типовая разница напряжений между линиями A и B передатчика равна 3В, минимальная 1.5В, максимальная 5В.

Разница напряжений между линиями A и B на приёмнике должна быть не менее 0.2В и абсолютная разница потенциалов относительно общего провода должно быть в диапазоне (-7…+12)В.

Таким образом, между двумя проводами витой пары всегда есть разность потенциалов. Именно этой разностью потенциалов и передается сигнал. Такой способ передачи обеспечивает высокую устойчивость к синфазной помехе. Максимальная скорость связи прибора по интерфейсу RS485 может достигать нескольких Мбод. Максимальное расстояние - 1200 метров. Если необходимо организовать связь на расстоянии больше чем 1200 метров или подключить больше устройств, чем допускает нагрузочная способность передатчика - применяют специальные повторители (репитеры). Типовое правило для расчёта максимальной длины линии связи таково: произведение скорости передачи в бодах на длину в метрах должно дать результат не более чем 108.

При значительных расстояниях между устройствами, связанными по витой паре или высоких скоростях передачи начинают проявляться так называемые эффекты длинных линий. Электромагнитный сигнал имеет свойство отражаться от открытых концов линии передачи и ее ответвлений. Фронт сигнала, отразившийся от конца линии, может исказить текущий или следующий сигнал. В таких случаях нужно подавлять эффект отражения.

Существуют стандартные решения этой проблемы (R, RC - терминаторы). У любой линии связи есть такой параметр, как волновое сопротивление Zв. Оно зависит от характеристик используемого кабеля и не зависит от его длины. Для обычно применяемых в линиях связи витых пар волновое сопротивление Zв составляет (90-120) Ом. Рассмотрим варианты:

  1. Если на удаленном конце линии, между проводниками витой пары включить резистор с номинальным омическим сопротивлением равным волновому сопротивлению линии, то электромагнитная волна, дошедшая до ≪тупика≫ поглощается на таком резисторе. Отсюда его названия - согласующий резистор или ≪терминатор≫ . Помимо достоинств этого метода (повышение скорости, увеличение длины и подавление отражений), есть и недостатки (дополнительная нагрузка на драйверы повышает энергопотребление, остальные ответвления линии продолжают вносить искажения, драйвер приёмника находится в неоднозначном состоянии: либо режим ожидания, либо режим приёма).
  2. Если на удалённом конце вместо резистора установить RC цепочку R=(90-120) Ом, С=1000 пФ, то можно устранить проблему повышенного энергопотребления и проблему неопределённости драйвера приёмника (для приёмников с функциями open-line и failsafe). Но из-за постоянной времени RC цепи, максимальная скорость передачи и длинна линии будут меньшими.

Эффект отражения и необходимость правильного согласования накладывают ограничения на конфигурацию линии связи (топология сети). Линия связи должна представлять собой один кабель витой пары. К этому кабелю присоединяются все приемники и передатчики (гирлянда). Расстояние от линии до микросхем интерфейса RS485 должно быть как можно короче, так как длинные ответвления вносят рассогласование и вызывают отражения. В оба наиболее удаленных конца кабеля включают терминаторы. Калибр витой пары достаточно не более AWG24.


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


Протокол MODBUS


MODBUS - это протокол уровня приложений (уровень 7 модели OSI), что обеспечивает связь между устройствами, соединёнными различными каналами связи и сетями.

Де-факто, MODBUS является стандартом в сетях промышленного назначения с 1979 года. Он обеспечивает связь миллионам устройств во всём мире, в том числе и через Интернет. Есть различные реализации протокола:

  • Для асинхронных беспроводных, оптических и проводных каналов связи (RS-232, RS-485, RS-422)
  • Для TCP/IP (порт 502) через интернет
  • MODBUS-PLUS - для высокоскоростных сетей с передачей меток (high speed token passing network)

Кроме того, разнородные участки сетей могут объединяться шлюзами (специальными конверторами).

Для асинхронных последовательных каналов связи существует две реализации MODBUS-SERIAL-LINE протокола МODBUS-RTU и MODBUS-ASCII (уровень 1 и 2 модели OSI). Разница между ними заключается в способе кодировки данных, способе синхронизации фреймов, и алгоритме обеспечения целостности данных. В нашем случае, в сети RS485 обмен данными реализован посредством протокола MODBUS-RTU. Далее по тексту будем рассматривать ситуацию только в этом аспекте.

MODBUS-SERIAL-LINE протокол - это протокол типа MASTER-SLAVE (протокол запросов-ответов). Ведущий в сети (MASTER) всегда один. Каждый подчинённый (SLAVE) должен иметь уникальный номер 1-247. Адрес 0 - это широковещательный запрос, адресованный сразу всем подчинённым. Таким образом, логически в одном участке сети может быть до 248 устройств (включая MASTER). Каждый запрос содержит код функции. Под MODBUS функциями понимают определённые сервисы предоставляемые подчинёнными ведущему. Таким образом, роль клиента играет MASTER, а роль сервера, с определённым набором функций-сервисов, SLAVE.


Функции протокола MODBUS


Каждый SLAVE может содержать уникальный набор функций-сервисов, но есть и ряд стандартных функций, которые подробно описаны в документе (www.modbus.org ). Также полезная информация может быть найдена в документе “MODBUS over serial line specification and implementation guide” (www.modbus.org ).

Поддерживаемые нами функции (см. табл. 4.1 - 4.2).



В более ранних версиях приборов (до 2010г) были реализованы лишь пользовательские функции, но со временем стало понятно, что для обеспечения совместного использования приборов с ПЛК (минуя ПК) необходимы и стандартные функции.

Будьте внимательны и обратите внимание на то, что стандартные функции оперируют только со словами (16-бит) и в формате big-endian, но при этом формат контрольной суммы CRC16 little-endian! Поэтому, для исключения разночтений в описании протокола MODBUS, в части порядка следования байт контрольной суммы CRC16, стоит пользоваться нехитрым правилом: правильно посчитанная контрольная сумма неповреждённого пакета (с участием 2-ух последних байт CRC16) всегда равна нулю.

Правильный запрос: CRC16 (1 104 0 0 8 0 103 195) = 0

Неверный запрос: CRC16 (1 104 0 0 8 0 195 103) <> 0

Стандартные функции (см. таб. 4.1) подробно описаны в документе “MODBUS Application Protocol Specification” (www.modbus.org ).






Функция 108 «Служебные команды» имеет следующие коды подфункций (см. таб. 4.8).
Подфункции, возвращающие какие-либо данные, имеют префикс GET. Подфункции, не возвращающие данных, не содержат поля данных и, при удачном выполнении, возвращаются эхом.


Подфункции 1 и 2, возвращающие номер тома всегда возвращают 4-х байтное значение типа DWORD.

Подфункции 3 и 4, возвращающие номера страниц могут возвращать как 2-х байтные (WORD), так и 4-х байтные (DWORD) значения, в зависимости от модели прибора.


Карты распределения памяти приборов


В следующих таблицах представлены карты распределения памяти приборов. Следует отметить тот факт, что в стандартных MODBUS функциях размеры типов данных могут отличаться от типов данных пользовательских функций (в большую сторону) в случае, если размер типа данных не кратен типу WORD (2 байта).

Порядок следования байт указан в столбце Order. Обозначение BE соответствует порядку big endian, а LE - little endian.

Операции, доступные для данной переменной, указываются в последнем столбце rw (read-write). R - разрешается только чтение, W - разрешается только запись, RW - разрешается, как чтение, так и запись.

Массивы обозначены словом array, а количество элементов массив указано в квадратных скобках [n].






Однофазный прибор OMIX измеряет 7 параметров качества электроэнергии, в массивах памяти (array) они расположены в следующем порядке -напряжение, -ток, - частота, - полная мощность, - активная мощность, - реактивная мощность, - cos(Φ).







Использованные источники информации
  • Electrical Characteristics of Balanced Voltage Digital Interface Circuits, ANSI/TIA/EIA-422-B-1994, Telecommunications Industry Association, 1994
  • Electrical Characteristics of Generators and Receivers for Use in Balanced Digital Multipoint Systems, ANSI/TIA/EIA-485-A-1998, Telecommunications Industry Association, 1998
  • Application Guidelines for TIA/EIA-485-A, TIA/EIA Telecommunications Systems Bulletin, Telecommunications Industry Association, 1998
  • A Comparison of Differential Termination Techniques, Joe Vo, National Semiconductor, Application Note AN-903
  • Data Transmission Design Seminar Reference Manual, 1998, Texas Instruments, literature number SLLE01
  • Data Transmission Line Circuits Data Book, 1998, Texas Instruments, literature number SLLD001
  • MODBUS Application Protocol Specification
  • MODBUS over serial line specification and implementation guide

ООО «Автоматика» 2012

В этой статье вы узнаете о протоколе Modbus TCP, который является развитием протокола Modbus RTU. Англоязычная версия статьи доступна на ipc2u.com .

Куда посылать команду Modbus TCP?

В сети Ethernet адресом устройства является его IP-адрес. Обычно устройства находятся в одной подсети, где IP адреса отличаются последними цифрами 192.168.1.20 при использовании самой распространённой маски подсети 255.255.255.0.

Интерфейсом является сеть Ethernet , протоколом передачи данных – TCP/IP .

Используемый TCP-порт: 502 .

Описание протокола Modbus TCP

Команда Modbus TCP состоит из части сообщения Modbus RTU и специального заголовка.

Из сообщения Modbus RTU удаляется SlaveID адрес в начале и CRC контрольная сумма в конце, что образует PDU, Protocol Data Unit.

Ниже приведен пример запроса Modbus RTU для получения значения AO аналогового выхода (holding registers) из регистров от #40108 до 40110 с адресом устройства 17.

11 03 006B 0003 7687

Отбрасываем адрес устройства SlaveID и контрольную сумму CRC и получаем PDU:

03 006B 0003

К началу получившегося сообщения PDU добавляется новый 7-байтовый заголовок, который называется MBAP Header (Modbus Application Header). Этот заголовок имеет следующие данные:

Transaction Identifier (Идентификатор транзакции) : 2 байта устанавливаются Master, чтобы однозначно идентифицировать каждый запрос. Может быть любыми. Эти байты повторятся устройством Slave в ответе, поскольку ответы устройства Slave не всегда могут быть получены в том же порядке, что и запросы.

Protocol Identifier (Идентификатор протокола) : 2 байта устанавливаются Master, всегда будут = 00 00, что соответствует протоколу Modbus.

Length (Длина) : 2 байта устанавливаются Master, идентифицирующие число байтов в сообщении, которые следуют далее. Считается от Unit Identifier до конца сообщения.

Unit Identifier (Идентификатор блока или адрес устройства) : 1 байт устанавливается Master. Повторяется устройством Slave для однозначной идентификации устройства Slave.

Итого получаем:

Modbus RTU Slave ID Запрос CRC
Modbus RTU 11 03 006B 0003 7687
0001 0000 0006 11 03 006B 0003
PDU
ADU, Application Data Unit

В ответе от Modbus TCP Slave устройства мы получим:

0001 0000 0009 11 03 06 022B 0064 007F

0001 Идентификатор транзакции Transaction Identifier
0000 Идентификатор протокола Protocol Identifier
0009 Длина (9 байтов идут следом) Message Length
11 Адрес устройства (17 = 11 hex) Unit Identifier
03 Функциональный код (читаем Analog Output Holding Registers) Function Code
06 Количество байт далее (6 байтов идут следом) Byte Count
02 (02 hex) Register value Hi (AO0)
2B (2B hex) Register value Lo (AO0)
00 Значение старшего разряда регистра (00 hex) Register value Hi (AO1)
64 Значение младшего разряда регистра (64 hex) Register value Lo (AO1)
00 Значение старшего разряда регистра (00 hex) Register value Hi (AO2)
7F Значение младшего разряда регистра (7F hex) Register value Lo (AO2)

Регистр аналогового выхода AO0 имеет значение 02 2B HEX или 555 в десятичной системе.

Регистр аналогового выхода АО1 имеет значение 00 64 HEX или 100 в десятичной системе.

Регистр аналогового выхода АО2 имеет значение 00 7F HEX или 127 в десятичной системе.

Типы команд Modbus TCP

Приведем таблицу с кодами функций чтения и записи регистров Modbus TCP.

Код функции Что делает функция Тип значения Тип доступа
01 (0x01) Чтение DO Read Coil Status Дискретное Чтение
02 (0x02) Чтение DI Read Input Status Дискретное Чтение
03 (0x03) Чтение AO Read Holding Registers 16 битное Чтение
04 (0x04) Чтение AI Read Input Registers 16 битное Чтение
05 (0x05) Запись одного DO Force Single Coil Дискретное Запись
06 (0x06) Запись одного AO Preset Single Register 16 битное Запись
15 (0x0F) Запись нескольких DO Force Multiple Coils Дискретное Запись
16 (0x10) Запись нескольких AO Preset Multiple Registers 16 битное Запись

Как послать команду Modbus TCP на чтение дискретного вывода? Команда 0x01

Эта команда используется для чтения значений дискретных выходов DO.

В запросе PDU задается начальный адрес первого регистра DO и последующее количество необходимых значений DO. В PDU значения DO адресуются, начиная с нуля.

Значения DO в ответе находятся в одном байте и соответствуют значению битов.

Значения битов определяются как 1 = ON и 0 = OFF.

Младший бит первого байта данных содержит значение DO адрес которого указывался в запросе. Остальные значения DO следуют по нарастающей к старшему значению байта. Т.е. справа налево.

Если запрашивалось меньше восьми значений DO, то оставшиеся биты в ответе будут заполнены нулями (в направлении от младшего к старшему байту). Поле Byte Count Количество байт далее указывает количество полных байтов данных в ответе.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
06 04
01 Адрес устройства 01 Адрес устройства
01 Функциональный код 01 Функциональный код
00 01 Количество байт далее
00 02 Значение регистра DO 0-1
00 Количество регистров Hi байт
02 Количество регистров Lo байт

Состояния выходов DO0-1 показаны как значения байта 02 hex, или в двоичной системе 0000 0010.

Значение DO1 будет вторым справа, а значение DO0 будет первым справа (младший бит).

Шесть остальных битов заполнены нулями до полного байта, т.к. их не запрашивали.

Модули с дискретным выводом: ioLogik E1211 , ET-7060 , ADAM-6060

Как послать команду Modbus TCP на чтение дискретного ввода? Команда 0x02

Эта команда используется для чтения значений дискретных входов DI.

Запрос и ответ для DI похож на запрос для DO.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
06 04
01 Адрес устройства 01 Адрес устройства
02 Функциональный код 02 Функциональный код
00 Адрес первого регистра Hi байт 01 Количество байт далее
00 Адрес первого регистра Lo байт 03 Значение регистра DI 0-1
00 Количество регистров Hi байт
02 Количество регистров Lo байт

Состояния выходов DI 0-1 показаны как значения байта 03 hex, или в двоичной системе 0000 0011.

Значение DI1 будет вторым справа, а значение DI0 будет первым справа (младший бит).

Шесть остальных битов заполнены нулями.

Модули с дискретным вводом: ioLogik E1210 , ET-7053 , ADAM-6050

Как послать команду Modbus TCP на чтение аналогового вывода? Команда 0x03

Эта команда используется для чтения значений аналоговых выходов AO.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
06 07
01 Адрес устройства 01 Адрес устройства
03 Функциональный код 03 Функциональный код
00 Адрес первого регистра Hi байт 04 Количество байт далее
00 Адрес первого регистра Lo байт 02 Значение регистра Hi (AO0)
00 Количество регистров Hi байт 2B Значение регистра Lo (AO0)
02 Количество регистров Lo байт 00 Значение регистра Hi (AO1)
64 Значение регистра Lo (AO1)

Состояния выхода AO0 показаны как значения байта 02 2B hex, или в десятичной системе 555.

Состояния выхода AO1 показаны как значения байта 00 64 hex, или в десятичной системе 100.

Модули с дискретным вводом: ioLogik E1210 , ET-7053 , ADAM-6050

Как послать команду Modbus TCP на чтение аналогового ввода? Команда 0x04

Эта команда используется для чтения значений аналоговых входов AI.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
06 07
01 Адрес устройства 01 Адрес устройства
04 Функциональный код 04 Функциональный код
00 Адрес первого регистра Hi байт 04 Количество байт далее
00 Адрес первого регистра Lo байт 00 Значение регистра Hi (AI0)
00 Количество регистров Hi байт 0A Значение регистра Lo (AI0)
02 Количество регистров Lo байт 00 Значение регистра Hi (AI1)
64 Значение регистра Lo (AI1)

Состояния выхода AI0 показаны как значения байта 00 0A hex, или в десятичной системе 10.

Состояния выхода AI1 показаны как значения байта 00 64 hex, или в десятичной системе 100.

Модули с аналоговым вводом: ioLogik E1240 , ET-7017-10 , ADAM-6217

Как послать команду Modbus TCP на запись дискретного вывода? Команда 0x05

Эта команда используется для записи одного значения дискретного выхода DO.

Значение FF 00 hex устанавливает выход в состояние включен ON.

Значение 00 00 hex устанавливает выход в состояние выключен OFF.

Все остальные значения недопустимы и не будут влиять на состояние выхода.

Нормальный ответ на такой запрос - это эхо (повтор запроса в ответе), возвращается после того, как состояние DO было изменено.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
06 06
01 Адрес устройства 01 Адрес устройства
05 Функциональный код 05 Функциональный код
00 Адрес регистра Hi байт 00 Адрес регистра Hi байт
01 Адрес регистра Lo байт 01 Адрес регистра Lo байт
FF Значение Hi байт FF Значение Hi байт
00 Значение Lo байт 00 Значение Lo байт

Модули с дискретным выводом: ioLogik E1211 , ET-7060 , ADAM-6060

Как послать команду Modbus TCP на запись аналогового вывода? Команда 0x06

Эта команда используется для записи одного значения аналогового выхода AO.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
06 06
01 Адрес устройства 01 Адрес устройства
06 Функциональный код 06 Функциональный код
00 Адрес регистра Hi байт 00 Адрес регистра Hi байт
01 Адрес регистра Lo байт 01 Адрес регистра Lo байт
55 Значение Hi байт 55 Значение Hi байт
FF Значение Lo байт FF Значение Lo байт

Состояние выхода AO0 поменялось на 55 FF hex, или в десятичной системе 22015.

Модули с аналоговым выводом: ioLogik E1241 , ET-7028 , ADAM-6224

Как послать команду Modbus TCP на запись нескольких дискретных выводов? Команда 0x0F

Эта команда используется для записи нескольких значений дискретного выхода DO.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
08 06
01 Адрес устройства 01 Адрес устройства
0F Функциональный код 0F Функциональный код
00 Адрес первого регистра Hi байт 00 Адрес первого регистра Hi байт
00 Адрес первого регистра Lo байт 00 Адрес первого регистра Lo байт
00 Количество регистров Hi байт 00
02 Количество регистров Lo байт 02
01 Количество байт далее
02 Значение байт

Состояние выхода DO1 поменялось с выключен OFF на включен ON.

Состояние выхода DO0 осталось выключен OFF.

Модули с дискретным выводом: ioLogik E1211 , ET-7060 , ADAM-6060

Как послать команду Modbus TCP на запись нескольких аналоговых выводов? Команда 0x10

Эта команда используется для записи нескольких значений аналогового выхода AO.

Байт Запрос Байт Ответ
(Hex) Название поля (Hex) Название поля
01 Идентификатор транзакции 01 Идентификатор транзакции
02 02
00 Идентификатор протокола 00 Идентификатор протокола
00 00
00 Длина сообщения 00 Длина сообщения
0B 06
01 Адрес устройства 01 Адрес устройства
10 Функциональный код 10 Функциональный код
00 Адрес первого регистра Hi байт 00 Адрес первого регистра Hi байт
00 Адрес первого регистра Lo байт 00 Адрес первого регистра Lo байт
00 Количество регистров Hi байт 00 Кол-во записанных рег. Hi байт
02 Количество регистров Lo байт 02 Кол-во записанных рег. Lo байт
04 Количество байт далее
00 Значение Hi AO0 байт
0A Значение Lo AO0 байт
01 Значение Hi AO1 байт
02 Значение Lo AO1 байт

Состояние выхода AO0 поменялось на 00 0A hex, или в десятичной системе 10.

В этом году на презентации Google I/O был представлен новая версия Android - L . Вместе с этим было представлено много новых плюшек для пользователей и разработчиков. Но одним из главных новшеств, несомненно, было новое решение Google для унификации дизайна - Material Design.

Одним из паттернов Material Design является Floating Action Button .

Что такое Floating Action Button ?

Google говорит, что это «специальный метод для способствования действию». Сама же кнопка имеет форму круга, плавающего над интерфейсом.


Стоит отметить , что Floating Action Button должна отражать только главное действие в приложении.

Быстрая и грязная реализация

Я хотел создать быстрый способ добавления простейшей FAB для своих Android приложений с minSdkVersion = 14 (Ice Cream Sandwich). Я также реализовал анимацию появления/исчезновения и небольшие возможности для кастомизации кнопки.

Весь код доступен в Github Gist (добавьте этот класс в свой проект).

Для надежности продублирую код здесь

package your_package; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.OvershootInterpolator; import android.widget.FrameLayout; public class FloatingActionButton extends View { Context context; Paint mButtonPaint; Paint mDrawablePaint; Bitmap mBitmap; boolean mHidden = false; public FloatingActionButton(Context context) { super(context); this.context = context; init(Color.WHITE); } public void setFloatingActionButtonColor(int FloatingActionButtonColor) { init(FloatingActionButtonColor); } public void setFloatingActionButtonDrawable(Drawable FloatingActionButtonDrawable) { mBitmap = ((BitmapDrawable) FloatingActionButtonDrawable).getBitmap(); invalidate(); } public void init(int FloatingActionButtonColor) { setWillNotDraw(false); setLayerType(View.LAYER_TYPE_SOFTWARE, null); mButtonPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mButtonPaint.setColor(FloatingActionButtonColor); mButtonPaint.setStyle(Paint.Style.FILL); mButtonPaint.setShadowLayer(10.0f, 0.0f, 3.5f, Color.argb(100, 0, 0, 0)); mDrawablePaint = new Paint(Paint.ANTI_ALIAS_FLAG); invalidate(); } @Override protected void onDraw(Canvas canvas) { setClickable(true); canvas.drawCircle(getWidth() / 2, getHeight() / 2, (float) (getWidth() / 2.6), mButtonPaint); canvas.drawBitmap(mBitmap, (getWidth() - mBitmap.getWidth()) / 2, (getHeight() - mBitmap.getHeight()) / 2, mDrawablePaint); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { setAlpha(1.0f); } else if (event.getAction() == MotionEvent.ACTION_DOWN) { setAlpha(0.6f); } return super.onTouchEvent(event); } public void hideFloatingActionButton() { if (!mHidden) { ObjectAnimator scaleX = ObjectAnimator.ofFloat(this, "scaleX", 1, 0); ObjectAnimator scaleY = ObjectAnimator.ofFloat(this, "scaleY", 1, 0); AnimatorSet animSetXY = new AnimatorSet(); animSetXY.playTogether(scaleX, scaleY); animSetXY.setInterpolator(new AccelerateInterpolator()); animSetXY.setDuration(100); animSetXY.start(); mHidden = true; } } public void showFloatingActionButton() { if (mHidden) { ObjectAnimator scaleX = ObjectAnimator.ofFloat(this, "scaleX", 0, 1); ObjectAnimator scaleY = ObjectAnimator.ofFloat(this, "scaleY", 0, 1); AnimatorSet animSetXY = new AnimatorSet(); animSetXY.playTogether(scaleX, scaleY); animSetXY.setInterpolator(new OvershootInterpolator()); animSetXY.setDuration(200); animSetXY.start(); mHidden = false; } } public boolean isHidden() { return mHidden; } static public class Builder { private FrameLayout.LayoutParams params; private final Activity activity; int gravity = Gravity.BOTTOM | Gravity.RIGHT; // default bottom right Drawable drawable; int color = Color.WHITE; int size = 0; float scale = 0; public Builder(Activity context) { scale = context.getResources().getDisplayMetrics().density; // The calculation (value * scale + 0.5f) is a widely used to convert to dps to pixel units // based on density scale // see developer.android.com (Supporting Multiple Screen Sizes) size = (int) (72 * scale + 0.5f); // default size is 72dp by 72dp params = new FrameLayout.LayoutParams(size, size); params.gravity = gravity; this.activity = context; } /** * Sets the gravity for the FAB */ public Builder withGravity(int gravity) { this.gravity = gravity; return this; } /** * Sets the margins for the FAB in dp */ public Builder withMargins(int left, int top, int right, int bottom) { params.setMargins((int) (left * scale + 0.5f), (int) (top * scale + 0.5f), (int) (right * scale + 0.5f), (int) (bottom * scale + 0.5f)); return this; } /** * Sets the FAB drawable */ public Builder withDrawable(final Drawable drawable) { this.drawable = drawable; return this; } /** * Sets the FAB color */ public Builder withButtonColor(final int color) { this.color = color; return this; } /** * Sets the FAB size in dp */ public Builder withButtonSize(int size) { size = (int) (size * scale + 0.5f); params = new FrameLayout.LayoutParams(size, size); return this; } public FloatingActionButton create() { final FloatingActionButton button = new FloatingActionButton(activity); button.setFloatingActionButtonColor(this.color); button.setFloatingActionButtonDrawable(this.drawable); params.gravity = this.gravity; ViewGroup root = (ViewGroup) activity.findViewById(android.R.id.content); root.addView(button, params); return button; } } }


При создании кнопки в XML, я обнаружил некоторые трудности позиционирования View у нашей кнопки над остальными View (в частности, над Navigation Drawer). Я решил реализовать кнопку программно и работать посредством Builder-паттерна, что позволит размещать FAB выше других View в Activity при вызове .create() .

Отлично! Но как мне добавить это в свое приложение?

Добавить Floating Action Button очень даже просто:

FloatingActionButton fabButton = new FloatingActionButton.Builder(this) .withDrawable(yourDrawable) .withButtonColor(Color.WHITE) .withGravity(Gravity.BOTTOM | Gravity.RIGHT) .withMargins(0, 0, 16, 16) .create();
Размер кнопки легко изменить посредством вызова .withButtonSize(int size) . По умолчанию стоит 72dp.

Заключение

Похоже, что Google будет использовать этот паттерн во многих своих приложениях. И еще до сих пор нет никаких новостей о том, будет ли Google добавлять floating action button в support library, поэтому пока что не стесняйтесь использовать это решение.

Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: