Чтение аналоговых входов (4-20мА / 0-10В)
Введение в аналоговые сигналы: 0-10В и 4-20мА
В предыдущих уроках, например, при рассмотрении чтения дискретных входов, мы работали с сигналами, которые имеют всего два состояния: "включено" или "выключено", "есть контакт" или "нет контакта", логическая "1" или "0". Однако для измерения плавно меняющихся физических величин — таких как температура, давление, влажность или уровень освещенности — дискретных сигналов недостаточно. Здесь на сцену выходят аналоговые сигналы.
Аналоговый сигнал — это сигнал, который может принимать любое значение в заданном непрерывном диапазоне. В отличие от дискретного "да/нет", аналоговый сигнал говорит "насколько": не просто "жарко", а "+25.3 °C"; не просто "светло", а "освещенность 500 люкс".В современной автоматизации зданий и промышленности доминируют два основных стандарта аналоговых сигналов: 0-10В (по напряжению) и 4-20мА (по току).
Области применения и ключевые отличия
Выбор между этими стандартами диктуется задачей, условиями эксплуатации и требуемой надежностью.
| Характеристика | Стандарт 0-10В | Стандарт 4-20мА (Токовая петля) |
| ----------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| Принцип работы | Измеряемая величина кодируется уровнем напряжения от 0 до 10 Вольт. | Измеряемая величина кодируется силой тока от 4 до 20 миллиампер. |
| Типовые применения | Управление диммируемыми светильниками, управление клапанами и заслонками в системах вентиляции (HVAC), управление скоростью вентиляторов. | Промышленные датчики давления, расхода, уровня, температуры, влажности. Датчики для ответственных систем и длинных линий. |
| Помехоустойчивость | Средняя. Напряжение чувствительно к электромагнитным наводкам от силовых кабелей, что может приводить к искажению показаний. | Высокая. Токовый сигнал значительно менее подвержен влиянию внешних помех, что делает его идеальным для промышленных сред. |
| Длина линии | Ограничена. На длинных линиях (>15-20 м) падение напряжения на сопротивлении кабеля может вносить существенную погрешность. | Может достигать сотен метров без значительной потери точности, так как ток в последовательной цепи одинаков в любой точке. |
| Диагностика обрыва | Сложная. Уровень сигнала 0В может означать как 0% измеряемой величины, так и обрыв провода. Невозможно различить эти состояния. | Простая и надежная. Уровень сигнала 4мА соответствует 0% измеряемой величины. Если же контроллер измеряет ток близкий к 0мА, это однозначно указывает на обрыв линии или неисправность датчика. |
| Питание датчика | Обычно требует отдельной линии питания (3 или 4 провода). | Часто датчик может питаться непосредственно от самой токовой петли (2-проводная схема), что упрощает монтаж. |
> ℹ️ Информация: Сигнал 4-20мА часто называют "живым нулем" (live zero). Это свойство — когда минимальное значение измеряемой величины (например, 0 бар давления) соответствует ненулевому сигналу (4мА) — является его ключевым преимуществом. Оно позволяет системе мониторинга мгновенно отличить штатную работу на нулевой отметке от аварийной ситуации, такой как обрыв кабеля или выход датчика из строя.
Физическое подключение к контроллеру HI
Контроллер HI оснащен универсальными входами (UI), которые могут быть сконфигурированы для работы с различными типами сигналов, включая 0-10В и 4-20мА.
* Режим 0-10В: Джампер устанавливается в положение "V" (Voltage).
* Режим 4-20мА: Джампер устанавливается в положение "I" (Current). Это физически подключает к входу прецизионный шунтирующий резистор, который преобразует ток в напряжение для дальнейшего измерения аналого-цифровым преобразователем.
* Для сигнала 0-10В используется два провода: сигнальный провод от датчика подключается к клемме UI, а общий провод (GND) датчика — к клемме GND контроллера.
* Для сигнала 4-20мА также используются два провода, образующие "петлю". Схема подключения зависит от типа датчика (с внешним питанием или с питанием от петли). В простейшем случае выход датчика `Iout` подключается к клемме UI, а второй провод петли замыкается на GND источника питания датчика, который должен быть также соединен с GND контроллера.
> ⚠️ Внимание: Всегда сверяйтесь со схемой подключения конкретного датчика и инструкцией к контроллеру HI. Неправильное подключение или неверно установленный джампер может привести к выходу из строя как входа контроллера, так и самого датчика.
---
Конфигурация универсальных входов контроллера HI
После того как физическое подключение выполнено и джамперы установлены правильно, необходимо программно указать контроллеру, какой тип сигнала он должен ожидать на данном входе. Эта конфигурация выполняется путем записи определенных значений в служебные Modbus-регистры самого контроллера.
> ⚠️ Внимание: Перед программной сменой режима входа на '4-20мА' или '0-10В' ОБЯЗАТЕЛЬНО убедитесь, что соответствующие джамперы на плате контроллера установлены в правильное положение. Несоответствие аппаратной и программной конфигурации может привести к некорректным измерениям, а в худшем случае — к выходу из строя порта или подключенного датчика.
Работа с картой регистров контроллера
Контроллер HI, помимо управления внешними устройствами, предоставляет доступ к своим собственным настройкам и данным через протокол Modbus TCP. Вся информация о доступных параметрах содержится в документе "Карта регистров" (Register Map), который является главным справочником для интегратора.
В этой карте для каждого универсального входа (UI) обычно есть как минимум два важных адреса:
'Сырое' значение АЦП
Важно понимать, что контроллер не отдает нам сразу готовые градусы Цельсия или бары. Он отдает 'сырое' значение (raw value) — это целочисленный результат работы внутреннего Аналого-Цифрового Преобразователя (АЦП). АЦП измеряет напряжение на входе и представляет его в виде числа.
Разрядность АЦП определяет диапазон 'сырых' значений. Например, для 12-битного АЦП диапазон составляет от 0 до 4095 (2^12 - 1).
- 0В на входе будет соответствовать 'сырому' значению `0`.
- Максимальное измеряемое напряжение (например, 10В) будет соответствовать 'сырому' значению `4095`.
- Соответственно, 5В на входе дадут 'сырое' значение около `2047`.
Наша задача как инженеров — сначала прочитать это 'сырое' число, а затем, зная характеристики датчика, преобразовать его в понятную физическую величину.
Пример конфигурации входа
Предположим, согласно карте регистров контроллера HI (Unit-ID 1), универсальный вход №3 (UI-03) настраивается через Holding Register с адресом `102`. Значения для режимов следующие:
- `1`: Режим 0-10В
- `2`: Режим 4-20мА
Чтобы перевести UI-03 в режим измерения напряжения 0-10В, нам нужно в Node-RED отправить Modbus-команду на наш же контроллер.
* Server: Создаем новый Modbus TCP клиент с IP-адресом `127.0.0.1` (или `localhost`) и портом `502`. Это указывает, что мы обращаемся к самому контроллеру.
* Unit-ID: `1` (адрес нашего контроллера на шине Modbus).
* FC: `FC 6: Write Single Register`.
* Address: `102` (адрес регистра конфигурации для UI-03).
* Value: `1` (код режима 0-10В).
После нажатия на узел `Inject` контроллер получит команду и переконфигурирует свой универсальный вход UI-03 для измерения напряжения. Теперь он готов к приему данных от датчика.
---
Чтение 'сырых' значений в Node-RED
После того как вход сконфигурирован, следующим шагом является организация периодического чтения 'сырых' значений с этого входа. Для этого мы снова будем использовать протокол Modbus и палитру `node-red-contrib-modbus`.
> 💡 Подсказка: Для большинства задач периодического опроса датчиков (раз в 1-10 секунд) удобнее использовать встроенную в узел `Modbus-Read` функцию 'Poll', а не создавать отдельный поток с `Inject`. Это делает поток более читаемым, компактным и избавляет от лишних узлов.
Настройка узла Modbus-Read
Предположим, мы хотим каждые 5 секунд читать 'сырое' значение с нашего входа UI-03, который мы ранее настроили. Согласно карте регистров, измеренное значение АЦП для UI-03 находится в Input Register с адресом `202`.
Построим поток:// Простой поток для чтения аналогового входа
[Modbus-Read: Читать UI-03] ----> [Debug: Сырое значение]
Конфигурация узла `Modbus-Read`:
После развертывания этого потока узел `Modbus-Read` будет автоматически каждые 5 секунд отправлять запрос контроллеру, получать ответ и передавать его дальше.
Анализ выходного сообщения
Давайте посмотрим, что именно узел `Modbus-Read` отправляет на выход. Если мы подключим к нему узел `Debug`, настроенный на отображение всего объекта `msg`, мы увидим примерно следующее:
{
"topic": "raw/ui-03",
"payload": [ 2048 ],
"responseBuffer": {
"type": "Buffer",
"data": [ 8, 0 ]
},
"_msgid": "a1b2c3d4.e5f6g7"
}
Ключевой для нас является часть `msg.payload`. По умолчанию узел `Modbus-Read` возвращает 'сырые' значения в виде массива чисел. В данном случае `[2048]` означает, что АЦП измерил значение, соответствующее середине своего диапазона (так как 2048 ≈ 4095 / 2).
> 🔗 Связанный материал: Как мы уже обсуждали в рамках паттерна "Контракт сообщения", работа с такими "сырыми" форматами напрямую в логике является плохой практикой. Следующим шагом всегда должно быть преобразование этого значения в стандартизированный JSON-объект.
На этом этапе мы добились главного: система автоматически и периодически получает 'сырые' данные с аналогового входа. Теперь нам предстоит превратить эти абстрактные цифры в реальные физические величины.
---
Масштабирование 'сырых' значений в физические величины
Мы получили 'сырое' значение `2048`, но что оно означает? Это 5В? +50°C? Давление в 4 бара? Без масштабирования это просто число. Масштабирование (или калибровка) — это процесс преобразования значения из одного диапазона (диапазон АЦП) в другой (диапазон физической величины датчика) с помощью математической функции.
Для большинства аналоговых датчиков эта зависимость является линейной, поэтому мы можем использовать простую формулу линейной интерполяции:
`Output = Output_start + (Input - Input_start) * (Output_end - Output_start) / (Input_end - Input_start)`
Где:
- `Input` — текущее 'сырое' значение от АЦП (например, `2048`).
- `Input_start` — 'сырое' значение, соответствующее началу шкалы датчика (например, `819` для 4мА).
- `Input_end` — 'сырое' значение, соответствующее концу шкалы датчика (например, `4095` для 20мА).
- `Output_start` — физическое значение в начале шкалы (например, `0` бар).
- `Output_end` — физическое значение в конце шкалы (например, `10` бар).
- `Output` — искомое физическое значение.
Определение диапазонов
Чтобы применить эту формулу, нам нужно знать четыре ключевых параметра, которые мы берем из документации на датчик и контроллер:
* Для 0-10В: Если АЦП 12-битный, то `Input_start = 0` (для 0В) и `Input_end = 4095` (для 10В).
* Для 4-20мА: Здесь сложнее. Мы должны знать, какому 'сырому' значению соответствуют 4мА и 20мА. Эти значения зависят от номинала шунтирующего резистора и настроек АЦП контроллера. Предположим, в документации на контроллер HI указано, что для 12-битного АЦП в режиме 4-20мА диапазон 'сырых' значений составляет 819...4095. Тогда `Input_start = 819`, `Input_end = 4095`.
Пример расчета
Давайте рассчитаем показания для датчика давления 0-10 бар, подключенного по стандарту 4-20мА.
- `Output_start` = 0 бар
- `Output_end` = 10 бар
- `Input_start` = 819 (соответствует 4мА)
- `Input_end` = 4095 (соответствует 20мА)
Предположим, мы прочитали 'сырое' значение (`Input`) равное `3000`.
Подставляем в формулу:
Таким образом, 'сырое' значение `3000` соответствует давлению примерно 6.66 бар. Эту логику мы и будем реализовывать в Node-RED.
---
Практика: Flow для датчика температуры 4-20мА
Теперь соберем все воедино и создадим полноценный поток для чтения данных с канального датчика температуры в системе вентиляции.
Задача:- Датчик температуры имеет диапазон измерения -20 ... +80 °C.
- Выходной сигнал датчика — 4-20мА.
- Контроллер HI имеет 12-битный АЦП, 'сырой' диапазон для 4-20мА — 819 ... 4095.
- Данные нужно читать каждые 10 секунд и выводить в отладку в виде стандартизированного объекта.
> 💡 Подсказка: Для простого линейного масштабирования можно использовать узел `node-red-contrib-range`. Он работает как функция `map()` в Arduino и позволяет настроить входной и выходной диапазоны в графическом интерфейсе, что избавляет от написания кода в узле `Function`. Однако для полного контроля над логикой (обработка ошибок, валидация) узел `Function` является более мощным инструментом.
Построение потока:// Поток считывания и масштабирования данных с датчика температуры
[Modbus-Read: Читать T-датчик] --> [Function: Масштабировать] --> [Debug: Температура °C]
1. Узел `Modbus-Read`
Настраиваем его так, как было описано ранее, для чтения одного Input Register (например, с адресом `202`) с интервалом `10 seconds`.
2. Узел `Function`
Это сердце нашего преобразования. В нем мы напишем JavaScript-код, реализующий формулу масштабирования.
- Name: "Масштабировать температуру"
- Code:
// 1. Получаем 'сырое' значение из входящего сообщения
// msg.payload от Modbus-Read узла приходит как массив, например [2500]
const rawValue = msg.payload[0];
// 2. Определяем константы для масштабирования
// Входной диапазон (сырые значения АЦП)
const INPUT_MIN = 819; // для 4мА
const INPUT_MAX = 4095; // для 20мА
// Выходной диапазон (физические значения датчика)
const OUTPUT_MIN = -20.0; // для 4мА
const OUTPUT_MAX = 80.0; // для 20мА
// 3. Валидация 'сырого' значения
// Проверяем на обрыв линии (значение сильно ниже минимального)
if (rawValue < 200) { // Порог для детекции обрыва
node.status({ fill: "red", shape: "dot", text: "Обрыв линии. Raw: " + rawValue });
node.error("Обрыв линии датчика. Получено значение: " + rawValue, msg);
return null; // Прерываем поток
}
// Проверяем, что значение в рабочем диапазоне. Если нет, возможно, короткое замыкание или неисправность.
if (rawValue < INPUT_MIN || rawValue > INPUT_MAX) {
node.status({ fill: "yellow", shape: "ring", text: "Вне диапазона. Raw: " + rawValue });
node.warn("Значение вне рабочего диапазона: " + rawValue, msg);
// Можно прервать поток или продолжить обработку, ограничив значение.
// В данном случае, мы ограничим его для стабильности.
if (rawValue < INPUT_MIN) rawValue = INPUT_MIN;
if (rawValue > INPUT_MAX) rawValue = INPUT_MAX;
}
// 4. Выполняем масштабирование по линейной формуле
const inputRange = INPUT_MAX - INPUT_MIN;
const outputRange = OUTPUT_MAX - OUTPUT_MIN;
let temperature = OUTPUT_MIN + (rawValue - INPUT_MIN) * outputRange / inputRange;
// Округляем до одного знака после запятой для аккуратности
temperature = Math.round(temperature * 10) / 10;
// 5. Формируем исходящее сообщение в соответствии с 'Контрактом сообщения'
msg.payload = {
value: temperature,
unit: "°C",
source: "temp-sensor-duct-01", // Уникальный ID источника
ts: Date.now()
};
// 6. Обновляем статус узла для визуальной диагностики
node.status({ fill: "green", shape: "dot", text: temperature + " °C" });
return msg;
3. Узел `Debug`
Подключаем его к выходу узла `Function`. После развертывания потока мы увидим в панели отладки сообщения следующего вида:
{
"value": 25.4,
"unit": "°C",
"source": "temp-sensor-duct-01",
"ts": 1678886400000
}
Это и есть конечный результат нашей работы: понятное, готовое к использованию значение температуры, которое теперь можно отправлять в базы данных (MySQL), системы визуализации (Grafana), использовать в логике управления климатом и так далее. Мы успешно прошли весь путь от аналогового сигнала на клемме контроллера до цифровых данных в нашей системе автоматизации.
---
Итоги и дальнейшие шаги
В этом уроке мы сделали важный шаг от мира простых дискретных сигналов к более сложному, но и более информативному миру аналоговых измерений. Мы разобрали полный цикл работы с аналоговыми датчиками на платформе HI.
Ключевые этапы, которые мы прошли:Теперь вы умеете подключать и обрабатывать данные с подавляющего большинства промышленных и бытовых датчиков, что открывает широкие возможности для построения сложных систем автоматизации.
Продвинутые сценарии
На базе полученных знаний можно реализовывать более сложные сценарии:
- Сглаживание шумов: Если показания датчика "скачут", можно добавить в поток узел `smooth` для получения усредненного значения за несколько измерений.
- Создание алертов: С помощью узла `Switch` можно проверять, не вышло ли значение температуры или давления за допустимые пределы, и в случае превышения отправлять уведомление или активировать аварийный сценарий.
- Гистерезис: При управлении нагревателем или охладителем на основе показаний датчика, используется логика гистерезиса (включение при T < 20°C, выключение при T > 22°C) для предотвращения частых переключений.
Что дальше?
Мы научились получать аналоговые данные. Логичным продолжением является научиться отдавать аналоговые команды. В следующем уроке мы рассмотрим работу с аналоговыми выходами контроллера. Вы научитесь, используя тот же стандарт 0-10В, управлять яркостью светильников (диммирование) и плавно регулировать положение приводов клапанов в системах отопления и вентиляции.