Как исправить проблему с нечитаемыми символами («кракозябрами») при работе с COM-портом (RS-232) в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При интеграции различного торгового оборудования — весов, сканеров штрихкодов, терминалов сбора данных или RFID-считывателей — разработчики на платформе 1С 7.7 часто сталкиваются с неприятной ситуацией. В системных утилитах тестирования (например, в HyperTerminal или PuTTY) данные из COM-порта поступают в чистом, красивом и читаемом виде, но при попытке получить их в коде 1С с помощью сторонних библиотек вроде rs232.dll программа возвращает «неведомую кодировку» — хаотичный набор нечитаемых символов.

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

Почему в 1С 7.7 из COM-порта приходят «кракозябры»?

Для начала выясним причину такого поведения системы. Если терминал показывает текст корректно, значит, само устройство работает исправно. Искажение информации происходит на этапе передачи данных из буфера операционной системы в среду 1С. Выделим четыре основные причины:

  1. Несовпадение параметров инициализации (UART-кадра). Если скорость передачи (Baud Rate), четность (Parity), биты данных (Data Bits) или стоповые биты (Stop Bits) настроены в коде 1С не так, как на самом устройстве, принимаемые байты аппаратно сдвигаются. Каждый байт деформируется на уровне битов, превращаясь в случайный символ, который не сможет расшифровать ни один текстовый декодер.
  2. Разница кодировок DOS (CP866) и Windows (CP1251). Большинство старого торгового оборудования передает текстовые данные в кодировке DOS (OEM/CP866). HyperTerminal автоматически на лету переводит её в читаемый ANSI-вид. Платформа 1С 7.7 работает исключительно в однобайтовой кодировке Windows-1251. Без принудительной конвертации русские буквы превратятся в символы псевдографики.
  3. Использование двухбайтового Юникода (UTF-16 LE). Современные DLL-библиотеки часто скомпилированы с поддержкой Unicode. При передаче строки в 1С 7.7 (которая является ANSI-приложением) каждый символ представляется двумя байтами. Для латиницы вторым байтом всегда идет нулевой байт 0x00. В 1С 7.7 нулевой байт интерпретируется как маркер конца строки, из-за чего строка обрезается после первого же символа. Если же передается кириллица, то двухбайтовые символы склеиваются в пары и отображаются в виде хаотичных китайских иероглифов или спецсимволов.
  4. Проблема бинарных данных и нулевого байта. Если весы или датчики передают не текст, а бинарные пакеты (где вес закодирован числами, в которых могут встречаться нулевые байты 0x00), любая стандартная текстовая компонента обрежет строку при первой же попытке передать её в 1С.

Давайте подробно разберем, как исправить каждую из этих проблем по шагам.

Решение 1. Проверяем параметры инициализации порта в коде

Прежде всего, убедимся, что параметры инициализации порта в коде 1С 7.7 в точности соответствуют настройкам устройства. Стандартный набор параметров выглядит так: 9600,N,8,1 (скорость 9600 bps, без четности, 8 бит данных, 1 стоповый бит). Проверьте документацию к вашему оборудованию. Если параметры не совпадают, измените их при вызове метода инициализации вашей библиотеки.

Решение 2. Программная перекодировка из CP866 в CP1251

Если данные приходят искаженными из-за DOS-кодировки оборудования, нам необходимо перекодировать полученную строку внутри 1С. Разберем по шагам, как написать функцию конвертации символов на основе стандартных кодовых таблиц:


Функция ПерекодироватьИзDOS(СтрДанных)
    Перем Результат, НомерСимвола, КодСимвола, НовыйКод;
    Результат = "";
    
    Для НомерСимвола = 1 По СтрДлина(СтрДанных) Цикл
        ТекущийСимвол = Сред(СтрДанных, НомерСимвола, 1);
        КодСимвола = КодСимв(ТекущийСимвол);
        
        // Перевод символов основной кириллицы CP866 -> CP1251
        Если (КодСимвола >= 128) И (КодСимвола <= 175) Тогда
            НовыйКод = КодСимвола + 64;
        ИначеЕсли (КодСимвола >= 224) И (КодСимвола <= 239) Тогда
            НовыйКод = КодСимвола + 16;
        ИначеЕсли КодСимвола = 240 Тогда // Буква Ё
            НовыйКод = 168;
        ИначеЕсли КодСимвола = 241 Тогда // Буква ё
            НовыйКод = 184;
        Иначе
            // Оставляем латиницу и цифры без изменений
            НовыйКод = КодСимвола;
        КонецЕсли;
        
        Результат = Результат + Симв(НовыйКод);
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Применим эту функцию к буферу, прочитанному из порта, чтобы вернуть тексту нормальный вид.

Решение 3. Переход на стандартный ActiveX-компонент MSCOMM32.OCX

Чтобы не гадать, как именно работает неизвестная библиотека rs232.dll, и не тратить время на ее декомпиляцию, крайне рекомендуется использовать проверенное временем стандартное решение от Microsoft — библиотеку MSCOMM32.OCX. Она официально документирована, стабильна и легко настраивается.

Для начала зарегистрируем её в операционной системе. Для этого запустим командную строку от имени администратора и выполним команду:

regsvr32 mscomm32.ocx

После успешной регистрации мы можем напрямую работать с COM-портом из кода 1С 7.7. Рассмотрим пример реализации:


Процедура ПолучитьДанныеИзПорта()
    Перем КомПорт, ВходящаяСтрока;
    
    Попытка
        // Создаем COM-объект Microsoft Communications Control
        КомПорт = СоздатьОбъект("MSCOMMLib.MSComm");
    Исключение
        Предупреждение("Компонента MSCOMM32.OCX не зарегистрирована в системе!");
        Возврат;
    КонецПопытки;
    
    // Настраиваем параметры подключения
    КомПорт.CommPort = 1; // Указываем номер COM-порта (например, COM1)
    КомПорт.Settings = "9600,N,8,1"; // Скорость, четность, бит данных, стоп-бит
    КомПорт.InputLen = 0; // Настройка указывает читать весь накопившийся буфер за один раз
    
    Попытка
        КомПорт.PortOpen = 1; // Открываем порт
    Исключение
        Предупреждение("Не удалось открыть COM-порт! Возможно, он занят другим приложением.");
        Возврат;
    КонецПопытки;
    
    // Делаем небольшую паузу для ожидания ответа от физического устройства
    // (актуально для весов и сканеров)
    Для х = 1 По 10000 Цикл
        // Пустой цикл-задержка или использование встроенного ожидания
    КонецЦикла;
    
    Если КомПорт.InBufferCount > 0 Тогда
        ВходящаяСтрока = КомПорт.Input;
        // Перекодируем, если устройство шлет данные в DOS-кодировке
        ЧитаемыйТекст = ПерекодироватьИзDOS(ВходящаяСтрока);
        Сообщить("Успешно получено: " + ЧитаемыйТекст);
    Иначе
        Сообщить("Буфер порта пуст, данные не поступили.");
    КоENDЕсли;
    
    // Обязательно закрываем порт после завершения сессии связи
    КомПорт.PortOpen = 0;
КонецПроцедуры

Решение 4. Использование внешней компоненты Ромикса (vk_rs232.dll / vk_rs232_hex.dll)

Если ваше оборудование передает бинарные пакеты, содержащие нулевые байты 0x00, стандартные текстовые методы работы с COM-портом вам не подойдут — строка будет постоянно обрезаться. В этом случае идеальным выбором станет использование специализированной внешней компоненты Ромикса под названием vk_rs232_hex.dll.

Эта компонента решает проблему кардинально: она считывает данные из порта в бинарном режиме и переводит их в текстовую шестнадцатеричную последовательность (HEX). Например, вместо неопределенного байта 0x00 вы получите обычную текстовую пару "00", а вместо спецсимволов — "FF", "CC" и т.д. Полученную строку можно легко разобрать побайтно средствами самой 1С 7.7.

Рассмотрим по шагам пример работы с hex-версией компоненты:


Процедура ПрочитатьБинарныйПорт()
    Перем Компонента, ДанныеВФорматеHex, ТекущийБайт;
    
    // Загружаем внешнюю компоненту
    Если ЗагрузитьВнешнююКомпоненту("vk_rs232_hex.dll") = 0 Тогда
        Предупреждение("Не найдена библиотека vk_rs232_hex.dll!");
        Возврат;
    КонецЕсли;
    
    // Создаем объект связи с портом
    Компонента = СоздатьОбъект("AddIn.Vk_RS232_Hex");
    
    // Открываем порт COM1 со скоростью 9600
    Если Компонента.ОткрытьПорт(1, 9600, 0, 8, 1) = 0 Тогда
        Предупреждение("Не удалось открыть COM-порт.");
        Возврат;
    КонецЕсли;
    
    // Считываем шестнадцатеричную строку из буфера устройства
    ДанныеВФорматеHex = Компонента.ЧитатьСтроку();
    
    Если ПустаяСтрока(ДанныеВФорматеHex) = 0 Тогда
        Сообщить("Получен HEX-пакет: " + ДанныеВФорматеHex);
        
        // Разбираем пакет побайтно (каждые 2 символа HEX строки — это 1 байт данных)
        Для к = 1 По СтрДлина(ДанныеВФорматеHex) / 2 Цикл
            ТекущийБайт = Сред(ДанныеВФорматеHex, (к - 1) * 2 + 1, 2);
            Сообщить("Байт № " + к + " = " + ТекущийБайт);
            
            // Здесь вы можете проанализировать конкретные байты веса или штрихкода
            // Например, если первый байт "02" (STX), а последний "03" (ETX)
        КонецЦикла;
    КонецЕсли;
    
    // Закрываем соединение
    Компонента.ЗакрытьПорт();
КонецПроцедуры

Подведем итоги

Мы выяснили, что «неведомая кодировка» в 1С 7.7 при работе с последовательным портом — это не случайный сбой, а вполне логичное следствие различий в представлении данных между старыми аппаратными устройствами и операционной системой Windows. Для исправления ситуации достаточно применить правильный инструмент:

← На главную