
В прошлой статье https://habr.com/p/1103196/ я рассказал о своем подходе к разработке среды программирования промышленного контроллера — а именно о части, касающейся визуализации данных из цепей лестничных диаграмм и функциональных блоков, которые выполняются на стороне микроконтроллера. В этот раз подробнее остановлюсь на цепочке событий.
Как я уже упоминал, вся модель среды ПЛК (которую я разрабатываю) содержится в XML‑файле. Этот файл включает в себя список функциональных блоков:
<LD_Unit Name="GTM" Group="Timer" Width="100" Height="55">

На основе этих данных среда (GUI‑приложение на ПК) группирует блоки по вкладкам, используя тег <Group>. Внутри этих модулей (юнитов) также содержатся графические примитивы, которые определяют визуальный облик каждого блока.
<lists> <Item Type="RECT" color="#808080" Style="box" > <Value> </Value> <xy x="1" y="20" /> <dimension width="117" height="57" /> <stroke Stroke="1" /> <fill Fill="1" /> </Item>
Вся цепочка — от XML‑строки до отрисовки блока на экране — выглядит следующим образом:

В параметры FBD‑блоков я добавил тип Style="box". Теперь при очень длинных названиях в момент отрисовки функциональный блок автоматически расширяется под размер строки. Поначалу я хотел просто обрезать строки (как это сделано в типичных китайских средах разработки), но пришел к выводу, что подход небезопасен. Если элемент ссылается на поле сложной структуры — например, на элемент массива в самом конце строки, — то важную часть данных можно просто выпустить из виду, что неминуемо приведет к ошибкам:

После того как мы получили список примитивов, определяющих визуальный дизайн отрисовки функционального блока, мы применяем указанный в XML стиль — то есть, что этот примитив (линия, круг, текст) — должен делать с числом которое приходит из памяти микроконтроллера(ПЛК). Происходит это непосредственно перед рендерингом примитива (в моем случае код написан на Java):
private void drawLine() { gc.setColor(AnimFabric.parseColor(color)); if(Style!=null && sm!=null) { if(Style.contains("onoff")) { gc.setColor(AnimFabric.onOff(sm.getValue(),Style)); } } Graphics2D g2d = (Graphics2D) gc; g2d.setStroke(new BasicStroke((float) stroke.Stroke)); g2d.drawLine((int) xy.x+X, (int) xy.y+Y, (int) x2y2.x+X, (int) x2y2.y+Y); }
Класс AnimFabric содержит типы анимации, а объект sm — тег и данные, привязанные к этому примитиву.
Первоначально я хотел сделать среду более современной, но затем расставил приоритеты в пользу легковесности. Для этого я использовал стандартные классы OpenJDK — как для отрисовки графики, так и для дизайна GUI в целом. В итоге среда спокойно запускается даже на ранних версиях Raspberry Pi и требует всего 120–200 МБ ОЗУ. Таким образом, из слабого мини‑ПК можно сделать полноценный самопрограммируемый промышленный контроллер.
Так же, еще раз процесс работы из прошлого поста:
Нативная часть для железа выполняющая программу в качестве ПЛК, требует на стороне микроконтроллера 5 кб ОЗУ, и 32 кб флеш. Работает на микроконтроллерах начиная с STM32G030, где после установки интерпретатора байт‑кода, есть еще 2–3 Кб на программу чего достаточно чтоб превратить такой микроконтроллер в простое программируемое реле.
Комментарии (16)

Siemargl
04.11.2026 04:32XML осуждаю. Слишком много визуального шума.
Сошлюсь на практику мировых вендоров, у которых программу можно править и в виде LD и в виде парного представления IL (с ограничениями конечно же) одновременно

zoshytlogic Автор
04.11.2026 04:32Спасибо за комментарий! Напишу новую статью о том как реализовано , я взял за пример Allen Bradley , у них логика веток (построение) описывается типа :
"XIC XIC BST XIO XIC NXB XIC BND XIO XIO "
то есть, ветки обозначаются маркерами BST,NXB ,BND . У меня тоже самое - есть скрипт который это описывает подобным образом.
.xml в моих модулях он хранит всего лишь - отрисовку графики блока, внутри локального прямоугольника+ описание поведения ASM подобным синтаксисом.
А сами ветки в глобальном плане- ход программы - он описывается скриптом : какая инструкция за какой идет, и какие ветки где находятся.
Или еще аналогия: .xml хранит классы (библиотеки) как визуального вида так и функций программы. А скрипт хранит логику веток, схему, и комментарии.
Для текстовых языков типа ST - конечно никаких .xml не нужно, там просто текст без графики.

Siemargl
04.11.2026 04:32В простых случаев вызовов блоков - автолайоут.
Сложные - как пример можно посмотреть Siemens cfc. Там автороутинг соединений а блоки можно перемещать по многолистовой схеме

Make_Pic
04.11.2026 04:32Расскажите как реализован интерпретатор байт-кода, как организована компиляция в байт код, как связь с железом (ADC, DAC, DI, DO) осуществляется. Как разделены host = Rasberry и STM32G, Как осуществляется мониторинг и индикация - состояние портов и т.д. Связь с внешним миром - Ethernet, RS485, и т.д. Как делается логирование, сообщения об ошибках?

zoshytlogic Автор
04.11.2026 04:32Я буду и дальше писать периодические посты как это работает. Если коротко:
Компилятор переводит текст программы(собственный язык: си подобные структуры и данные, в инструкции как у ассемблера) в 32 битные единицы и нули.
Массив этих байт (виртуальная прошивка) идет по uart в микроконтроллер в виртуальное ОЗУ ( массив uint8_t memory[size] - в нем все хранится, программа, данные, стек, буферы для связи с внешним миром, единый массив).
Цикл wile() читает эти байты(инструкции) и вызывает обработчики : функция + -прыжок между инструкциями,мвсе как на физическом процессоре, только тут он программный нарисан на си (есть еще и на FPGA).
Но цикл while() не простой, там есть постоянное чтение флага состояния процессора:
Сработало прерывание? Ставим машину в режим : отдать данные на пк, иои сменить задачу (если несколько виртуальных задач работаеют) так же если происходит ошибка (например в лестнице программы плк, деление на ноль или еще что) ставим машину в режим ошибки и вызываем нужную функцию или си, или переводим счетчик команд виртульной машины на виртуальный обработчик (как это в языках ява или питон).
Тут много нюансов есть.
В этом массиве под виртуальное озу: вы можете выделить память под буфер для rs485 /ethernet.
Интеграция с конкретным микроконтроллером необходима тоже если делать плк.
У компилятора есть инструкция extfn, если нужно что то особенное (как например ethernet) компиялтор (то есть среда на ПК) будет вставлять эту инструкцию в ваш нарисованый функциональный блок, а микроконтроллер будет вызывать функцию на си, которую вы внедрили в свой плк.
Для пользователя это будет всего лишь еще один нарисованный функциональный блок, а для производителя плк, нужно будет еще написать функцию что с этими данными из этого блока делать.
Тут главное для понимания не путать нативную прошивку (,который ставит производитель плк на заводе) с виртуальной (программы плк: ST, LD, FBD)

Make_Pic
04.11.2026 04:32Идет у вас почти по моим аналогичным планам во всяком случае то что описали, контроллер то же на FPGA, разница только в компиляторе и среде программирования софте. С интересом буду ждать продолжения цикла статей. Rasberry под линуксом?

NutsUnderline
04.11.2026 04:32тут нет так давно рассказывали про идею мультиядерного ПЛК, с горячим резервированием и валидацией ядер, тож на fpga делали но оно там оказалось чисто теоритическим, в продакт не пойдет

NutsUnderline
04.11.2026 04:32Цикл wile() читает эти байты(инструкции) и вызывает обработчики : функция + -прыжок между инструкциями,мвсе как на физическом процессоре, только тут он программный нарисан на си (есть еще и на FPGA).
по предыдущим дискуссиям стало интересно как оценивать надежность такой вирутуалки (риск что она зависнет намертво в какой то ситуации), по логике это должно быть какое то массовое тестирование

zoshytlogic Автор
04.11.2026 04:32Тестирование есть, это 8 задач с глубокими переходами из функции в функцию 8-10 уровней(то есть , виртуальные функции, программа ST, а не нативная) и их эти задачи хаотично прерывает таймер меняя , вытесняя задачи местами . Так тстировал сохранение контекста , целостность стеков, адресов возврата и прочее. Это суточный мониторинг. Если за сутки ничего не случилось , сотни миллионов смен задач произошли штатно, и все работает значит все норм, , в отладке просматривается все ли на своих местах, не затерлись или не испортились какие то данные даже если программа не слетела. Тестируются другие сценарии. Тут без поблажек

NutsUnderline
04.11.2026 04:32В итоге среда спокойно запускается даже на ранних версиях Raspberry Pi и требует всего 120–200 МБ ОЗУ. Таким образом, из слабого мини‑ПК можно сделать полноценный самопрограммируемый промышленный контроллер.
не сразу понял эти фразы в связке. мини‑ПК это все таки обычно про x86 но gpio там если и есть то запрятаны. плюс вопрос "реального времени". если же че то малиноподобное то интересен вопрос экрана, его размеров и удобства пользования средой на мелких экранах.
а то вон в соседней теме сделали ПЛК с простеньким визуальным ladder на экране на экране 0.96" - вообще никаких сред, все на простом контроллере фурычит

zoshytlogic Автор
04.11.2026 04:32Идея мини плк который имеет в себе и компилятор, и сам выполняет программу плк (например случай когда - сеть не предусмотрена , перепрошивать удаленно, и чтоб не надо было с собой носить ноутбук). То есть можно на месте отлаживать и запускать. А ПЛК с простым ladder и другого поста , - тут вопрос масштаба. С одной стороны и мой рантайм заработает на stm32g030 на аквариуме, но я целился на соревнования с Allen Bradley

NutsUnderline
04.11.2026 04:32ну это да, а экран (на 27" дюймов 6) с собой носить или к каждому ПЛК приставить?

zoshytlogic Автор
04.11.2026 04:32Можно экран 320*280. Не думаю что фирма не найдет 10-15$ на такой дисплей если им нужно будет. С другой стороны, сам рантайм работабщий на мк, можно изменить под себя вывести кнопки и записывать значения. Виртуальная машина, ее память хранится в обычном массиве, сменить байт с 0x6 на 0x8 чтоб изменить инструкцию, или сменить два байта адреса чтоб поменять переменную, не трудно будет
Anchomov
"В прошлой статье я рассказал о своем подходе к..."
Здесь ещё можно вставить ссылку на прошлую статью.
И часть, как данные от внешних устройств превращаются в XML файл, можно кратенько где-то осветить для преемственности изложения, - пожалуйста.
Я не критикую ( Боже упаси! ) , просто прошу, идея классная, сам хотел бы таким позаниматься, но не с нуля. Спасибо!
zoshytlogic Автор
Критиковать можно, даже выставляю посты на эту тему на p...bu, а там публика не подготовленная , читал всякое. На публике я хладнокровен :)
Статьи просто пытаюсь не раздувать сильно текстом, со временем все исходники я раскрою полностью , как среды на ПК так и для железа.