Ряд наших устройств имеет встроенный порт RS-485 для прямого подключения электросчётчиков, имеющих данный интерфейс. Для облегчения тестирования устройств мы разработали небольшую программу-эмулятор. Именно о ней дальше и пойдёт речь. Данная статья появилась после написания предыдущей про эмулятор ИБП. Идея эмулятора оказалась очень полезной. С его помощью были отловлены некоторые баги в «прошивках» микроконтроллеров. В итоге возникла идея реализовать то же самое и с электросчётчиками. Ранее отладку мы вели очень просто, вот на таком вот стенде: Подключая по очереди каждый из электросчётчиков, разработчик «прошивки» убеждался в корректности считывания данных. Надо сказать, что современные электросчётчики достаточно навороченные, но мы снимаем с них не всю информацию, а только следующие параметры: Серийный номер Напряжение сети (В) Частота сети (Гц) Ток нагрузки (А) Мощность нагрузки (Вт) Текущее значение тарифов (кВт x ч) Начинали мы с модели «Меркурий 206», но постепенно список стал расширяться. На текущий момент у нас поддерживаются четыре модели: Инкотекс-СК «Меркурий 206» Энергомера «СЕ102» Энергомера «СЕ102М» IEK «STAR 104/1» В будущем наверняка добавим поддержку и других приборов учёта. Каждый электросчётчик имеет свой протокол работы и свою скорость обмена данными по RS‑485 интерфейсу. Ниже я хочу кратко рассказать об особенностях каждого из них. Данный счётчик весьма популярен, по нему несложно найти примеры подключения и примеры кода для считывания информации. Счётчик подключается к считывающему устройству четырьмя проводами: линии A, B интерфейса RS-485, питание и «земля». Скорость обмена данными 9600 бит/сек без контроля чётности. Напряжение питания может быть в диапазоне от 6 до 12В. Имеются модификации со встроенным источником питания: Меркурий 206 PRSN и Меркурий 206 PRSNO. С этим счётчиком была связана одна проблема. Изначально мы питали его от напряжения 12В, от которого запитывался и наш контроллер. Но в процессе эксплуатации несколько счётчиков вышло из строя. Точнее они работали, но обмен данными по RS-485 пропал. Мы вскрыли несколько из них и обнаружили что там вышел из строя сам драйвер. Он питался через стабилизатор, выполненный на резисторе и стабилитроне. Так вот стабилитрон просто вышел из строя и всё напряжение шло непосредственно на драйвер. Для исключения подобных случаев мы сделали у себя в контроллере отдельный выход на напряжение 10В для запитывания электросчётчиков. После этого было выпущено более 10 тыс. таких изделий и проблем с ними в этой части больше не было. Теперь надо немного остановиться на протоколе обмена данного электросчётчика.Он довольно простой и в чём-то похож на Modbus RTU.Описание протокола можно найти здесь. Форматы запросов и ответов совпадают.  Название поля  Условное обозначение  Длина поля (байт)  Примечание Сетевой адрес ADDR 4 Серийный номер счётчика (передаётся старшим байтом вперёд) Команды CMD 1 Двоичный код команды Данные ­- 0…17 Может отсутствовать (в зависимости от типа и назначения пакета) Контрольная сумма CRC16 2 2-х байтовый̆ циклический̆ избыточный̆ код, вычисляемый̆ по всем предшествующим байтам данного пакета (передаётся младшим байтом вперёд) CRC16 рассчитывается при помощи полинома 0xA001 и стартового значения 0xFFFF, точно так же, как в протоколе Modbus RTU. Приведу пример функций расчёта контрольной суммы, которые используются у нас в проектах: К сожалению, в данном протоколе обмена отсутствует какой-либо префикс начала пакета данных, поэтому определить его можно только по времени отсутствия обмена данными на линии, необходимого для передачи 5-6 байт. Мы используем следующие команды для этого счётчика: 0x27 (чтение тарифов) – в ответ получаем пакет из 16 байт данных по 4 байта на каждый тариф. При этом данные передаются в двоично-десятичном формате с точностью до 10 Вт. Запрос:00 00 04 D2 27 79 7B
00 00 04 D2 – адрес счётчика
27 – команда
79 7B – CRC16 Ответ:00 00 04 D2 27 00 02 27 50 00 02 27 50 00 02 27 50 00 02 27 50 A5 FB00 00 04 D2 – адрес счётчика27 – команда00 02 27 50 – тариф №1 (227,5 кВт × ч)00 02 27 50 – тариф №2 (227,5 кВт × ч)00 02 27 50 – тариф №3 (227,5 кВт × ч)00 02 27 50 – тариф №4 (227,5 кВт × ч)A5 FB – CRC16 0x63 (чтение U, I, P) – получаем значения сетевого напряжения, тока и мощности потребления. Данные также передаются в двоично-десятичном формате. Величина напряжения передаётся с коэффициентом 10, тока – 100, мощности – без коэффициента. Запрос:00 00 04 D2 63 79 4800 00 04 D2 – адрес счётчика63 – команда79 48 – CRC16 Ответ:00 00 04 D2 63 23 00 01 50 00 01 00 A5 FB00 00 04 D2 – адрес счётчика63 – команда23 00 – напряжение (230,0 В)01 50 – ток нагрузки (1,5 А)00 01 00 – потребляемая мощность (100 Вт)A5 FB – CRC16 0x81 (F, текущего тарифа и битовых флагов) – из ответа данной команды нас интересуют только первые два байта, представляющие частоту в двоично-десятичном формате. Частота передаётся с коэффициентом 100. Запрос:00 00 04 D2 81 F9 0100 00 04 D2 – адрес счётчика81 – команда09 01 – CRC16 Ответ:00 00 04 D2 81 50 50 3A 00 00 00 00 00 00 CC A400 00 04 D2 – адрес счётчика81 – команда50 50 – частота (50,5 Гц)3A – битовые флаги (0 бит – неравенство токов, 1 бит – обратная энергия, остальные биты не используются).00 00 00 00 00 00 – резервCC A4 – CRC16 Этот электросчётчик недорогой, но имеет меньше возможностей. В частности, он не позволяет выдавать значения напряжения сети, частоты, тока и мощности потребления нагрузкой. Поэтому с данного счётчика мы считываем только значения тарифов и полное значение серийного номера. Полное потому, что адресация счётчика осуществляется по пяти последним цифрам серийника, а сам он имеет длину до 16 десятичных цифр. Счётчик подключается к считывающему устройству также четырьмя проводами: линии A, B интерфейса RS-485, питание и «земля». Скорость обмена данными 9600 бит/сек без контроля чётности. Напряжение питания, указанное в документации: 12В. Внутри для питания драйвера RS-485 используется классический линейный стабилизатор 78L05, проблем с выходом из строя модуля связи на данных счётчиках зафиксировано не было. Реально питать его можно напряжением от 7 до 18В. Теперь рассмотрим протокол обмена. Тут он более навороченный. Описание его находится здесь. Формат запроса и ответа следующий: Условное обозначение Длина поля (байт) Примечание END 1 Байт начала пакета OPT 1 Тип адресации и контрольной суммы AddrD 2 Адрес электросчётчика (последние 5 цифр серийного номера) AddrS 2 Адрес устройства, отправившего запрос. В нашем случае адрес контроллера. PAL N Структура данных CRC8 1 Контрольная сумма END 1 Байт окончания пакета END (0xС0) – флаг, обозначающий начало и конец пакета. Если в пакете встречается байт с кодом, идентичным END, то такой байт замещается на последовательность из 2 байтов: 0xDB и 0xDC. Специальный символ 0xDB называется ESC-символом. Если в пакете встречается байт с кодом ESC-символа, то он замещается двухбайтовой последовательностью 0xDB, 0xDD. OPT (0x48): включена 16-битная адресация и 8-битный циклический код. AddrD – адрес назначения (счётчика), передаётся младшим байтом вперёд. AddrS (253) – адрес источника, передаётся младшим байтом вперёд. CRC8 – контрольная сумма пакета, рассчитывается до применения ESC-символов для всех байтов, исключая первый и последний END. Вычисление производится с использованием полинома 0xB5 и стартового значения 0x00. Внутренняя структура сообщения PAL при запросе следующая: Условное обозначение Длина поля (байт) Примечание Passw 4 Пароль доступа Serv 1 Сервисное поле CmdH 1 Старший байт кода команды CmdL 1 Младший байт кода команды Data N Данные Passw (777777) – пароль доступа к информации. Формат поля Serv: Условное обозначение Бит Примечание Direct 7 Тип обмена (1 – запрос, 0 – ответ) ClassAccess 6…4 Класс доступа к счётчику (0x05) MessageLen 3…0 Количество байт, которые помещены в данные CmdH, CmdL – старший и младший байты кода команды счётчику. Data – данные. Внутренняя структура сообщения PAL при ответе повторяет структуру запроса, но только адреса AddrD и AddrS меняются местами, а поле пароля отсутствует: Условное обозначение Длина поля (байт) Примечание Serv 1 Сервисное поле CmdH 1 Старший байт кода команды CmdL 1 Младший байт кода команды Data N Данные Расчёт контрольной суммы осуществляется следующими функциями: Мы используем следующие команды для данного счётчика: 0x0130 (чтение тарифа). В запросе передаём два значения: индекс глубины опроса (0 – текущие значения) и номер тарифа (1…5). Запрос:C0 48 D2 04 FD 00 31 DE 0B 00 D2 01 30 00 02 33 C0C0 – END48 – OPTD2 04 – адрес счётчика 1234FD 00 – адрес контроллера 25331 DE 0B 00 – Passw 777777D2 – запрос с двумя байтами в пакете01 – AddrH30 – AddrL00 – текущие значения02 – тариф №233 – CRC8C0 – END Ответ:C0 48 FD 00 D2 04 57 01 30 10 08 21 DE 58 00 00 94 C0C0 – END48 – OPTFD 00 – адрес контроллера 253D2 04 – адрес счётчика 123457 – ответ с семью байтами в пакете01 – AddrH30 – AddrL10 08 21 – текущая дата в двоично-десятичном форматеDE 58 00 00 – значение тарифа №2 (227,5 кВт × ч)94 – CRC8C0 – END 0x011A (чтение серийного номера). Серийник считывается за два запроса с передачей одного байта, который указывает какую часть серийного номера считать, младшую – 0 или старшую – 1. Каждая часть состоит из восьми символов. Запрос:C0 48 D2 04 FD 00 31 DE 0B 00 D1 01 1A 01 CB C0C0 – END48 – OPTD2 04 – адрес счётчика 1234FD 00 – адрес контроллера 25331 DE 0B 00 – Passw 777777D1 – запрос с одним байтом в пакете01 – AddrH1A – AddrL01 – старшая частьCB – CRC8C0 – END Ответ:C0 48 FD 00 D2 04 58 01 1A 30 30 30 30 30 30 30 00 E0 C0C0 – END48 – OPTFD 00 – адрес контроллера 253D2 04 – адрес счётчика 123458 – ответ с восемью байтами в пакете01 – AddrH1A – AddrL30 30 30 30 30 30 30 00 – старшая часть серийного номера (0000000)E0 – CRC8C0 – END Запрос:C0 48 D2 04 FD 00 31 DE 0B 00 D1 01 1A 00 7E C0C0 – END48 – OPTD2 04 – адрес счётчика 1234FD 00 – адрес контроллера 25331 DE 0B 00 – Passw 777777D1 – запрос с одним байтом в пакете01 – AddrH1A – AddrL00 – младшая часть7E – CRC8C0 – END Ответ:C0 48 FD 00 D2 04 58 01 1A 34 33 32 31 30 30 30 30 DB DD C0C0 – END48 – OPTFD 00 – адрес контроллера 253D2 04 – адрес счётчика 123458 – ответ с восемью байтами в пакете01 – AddrH1A – AddrL30 30 30 30 30 30 30 00 – младшая часть серийного номера (0000000)DB DD – CRC8 (0xDB с учётом ESC-последовательности)C0 – END Данный электросчётчик интересен двумя моментами. Во-первых, он имеет встроенный источник питания для порта RS-485, вследствие чего, подключение к контроллеру осуществляется всего двумя проводами – A и B. Скорость обмена данными 9600 бит/сек, 7 бит данных, контроль чётности. Во-вторых, он может работать без адресации, поэтому не нужно указывать никаких цифр серийного номера, чтобы снимать с него данные. Протокол обмена этого электросчётчика соответствует ГОСТ Р МЭК 61107-2001 «Обмен данными при считывании показаний счетчиков, тарификации и управлении нагрузкой». Он достаточно навороченный, но в стандарте описан весьма тщательно, поэтому полностью приводить здесь я его не буду, а сосредоточусь лишь на основных моментах и примерах запросов. Описание команд применительно к данному счётчику приведено здесь. В первую очередь надо отметить, что протоколом предусмотрены следующие управляющие символы: ACK (0x06) – подтверждениеSOH (0x01) – начало заголовкаSTX (0x02) – начало текстаETX (0x03) – конец текста Хотя протокол и основан на системе «запрос-ответ», но единого формата пакетов тут нет. Более того, одни запросы и ответы могут содержать контрольную сумму, а другие передаются без неё! Контрольную сумму далее будем обозначать как BCC. Она рассчитывается как сумма всех байтов за исключением начального SOH или STX. Чтобы что-то считать со счётчика в первую очередь нужно установить связь специальной командой, затем отправить нужные команды на считывание параметров, после чего другой командой завершить обмен. Разберём эти команды подробнее. В примерах далее пробелы будут разделять символы команд для наглядности, реально они не передаются. Специальным символы будут указываться своими аббревиатурами, а различные числовые значения в 16-ричном формате с префиксом 0x: Начало передачи данных без адреса. С это команды начинается обмен:Запрос:/?! 0x0D 0x0A Ответ:/EKT5CE102Mv01 0x0D 0x0A Подтверждение начала обмена:Запрос:ACK 051 0x0D 0x0A0 – нормальная процедура протокола5 – скорость 9600 бод1 – режим программирования. Ответ:SOH P0 STX (1234) ETX BCCP – команда пароля0 – без пароля(1234) – серийный номер в скобках Чтение величины напряжения:Запрос:SOH R1 STX VOLTA() ETX BCCR – команда чтения1 – чтение в формате ASCIIVOLTA() – чтение напряжения Ответ:STX VOLTA(230.1) 0x0D 0x0A ETX BCCVOLTA(230.1) – величина напряжения в скобках Чтение величины тока нагрузки, мощности и частоты сетиДанные команды аналогичный команде чтения напряжения за исключением текстового названия кода команды:CURRE() – ток нагрузкиPOWEP() – мощность нагрузкиFREQU() – частота электрической сети Чтение значения тарифов:Запрос:SOH R1 STX ET0PE(02) ETX BCCET0PE – команда нужного тарифа. Нумерация начинается с 02. Индекс 01 предназначен для считывания суммарного значения всех тарифов Ответ:STX ET0PE(118.74) 0x0D 0x0A ETX BCCET0PE(118.74) – значение тарифа в скобках Завершение обмена:Запрос:SOH B0 ETX BCCB – команда выхода0 – признак завершения обмена Ответа на данную команду нет. Данный электросчётчик имеет много схожего с вышеописанными моделями. Он подключается к считывающему устройству четырьмя проводами: линии A, B интерфейса RS-485, питание и «земля». Скорость обмена данными 9600 бит/сек без контроля чётности. Напряжение питания может быть в диапазоне от 10 до 24В. Для считывания данных следует обязательно использовать адресацию по пяти последним цифрам серийного номера. Протокол обмена этого электросчётчика собственный. К сожалению, в открытом доступе его описание мне найти не удалось, поэтому мы обратились к производителю. Всего через неделю после запроса нам на электронную почту прислали текстовый документ с подробным описанием протокола. Никаких NDA подписывать не потребовалось. Даже никто не уточнил зачем он нам нужен.  Итак, разберём необходимые нам команды.  Формат запроса и ответа следующий: Условное обозначение Длина поля (байт) Значение  Примечание Start1 1 0x73   Start2 1 0x55   Parameters + Len 1 С V0 D L4 L3 L2 L1 L0 Для этих полей вычисляется CRC8 Это подлежит байтстаффингу Reserved 1 0x00 Address Destination 2  Address Source 2  Command 1  Password / Status 4  Data 0…31  CRC8 1   Stop 1 0x55   Start1, Start2: начало пакета. Stop: конец  пакета. Parameters:бит C – кодирование данных (1 – данные закодированы, 0 – нет).бит V0 – вид структуры пакета (0 – пакет для  устройств с малыми вычислительными мощностями (счётчиков), 1 – пакет для  устройств с достаточными вычислительными мощностями (УСПД).бит D – направление движения пакета (1 – запрос к устройству, 0 – ответ устройства).биты L4…L0 –длина поля Data. Address Destination: адрес устройства. Address Source: адрес программы опроса, всегда равен 0xFFFF. Command: код команды. Password / Status: пароль для пакета запроса / статус для пакета ответа. Пароль заполняется только для пакетов, которые адресованы устройству. Когда устройство отвечает на запрос, оно заполняет это поле статусными значениями, это могут быть флаги уведомления об авариях в устройстве и другие информационные идентификаторы, к примеру код ошибки выполнения команды. Data: поле данных. Оно может быть пустым, если в нём нет необходимости.  Многобайтные значения передаются младшим байтом вперёд. Все дробные значения представляются как целые, с жёстко фиксированным положением запятой, согласно описанию структуры данных. Контрольная сумма CRC8 вычисляется с использованием полинома 0хA9 и стартового значения 0x00. Пакет перед отправкой подлежит обработке механизмом байтстаффинга, а при приёме – обратного байтстаффинга. Байтстаффингу подвергаются все байты пакета за исключением стартовых и стопового. При байтстаффинге анализируется каждый байт, и:0х55 заменяется на 0х73 0х110х73 заменяется на 0х73 0х22 При обратном байтстаффинге проводится противоположная замена. Рассмотрев эти четыре модели электросчётчиков можно сделать вывод о большом разнообразии протоколов обмена. Мне больше всего понравились реализации от Инкотекс и IEK. Они простые, бинарные, без лишних заморочек. Жаль только, что производители не пришли ещё к какой-то единой реализации. А пока на данном эмуляторе мы тестируем все наши изделия во всём возможном диапазоне напряжений, токов, частоты и мощности. Программа эмулятора представляет из себя экран с настройками и выбором COM‑порта, через который будет осуществляться обмен. Поддерживаются все указанные выше электросчётчики.  Менять любые параметры можно прямо в процессе работы, и тут же видеть результат: Скачать эмулятор можно по ссылке. Схемотехник