ПЛК на микроконтроллере. Визуализаци цепей и отладка в реальном времени⁠

—

от автора

Расскажу  подход в оживлении цепей и функциональных блоков в своей среде разработки под ПЛК. Я не использую  никаких графических фреймворков и библиотек, тут как раз случай когда самому сделать быстрее чем изучать что то новое. Все функциональные блоки программы  отображающие в среде на ПК : рисуют примитивами (прямоугольниками, линиями, точками,текстом etc…) .

На этапе проектирования платформы я сразу взял за цель — максимальную гибкость: пользователь сам может нарисовать функциональный блок, обозначить его сигналы, и сделать описание поведения в цепи. Для этого я сделал шаблон:

 <LD_Unit Name="SEND" Group="Message" Width="120" Height="80">      <Variables>         -----Входящие сигналы/Переменные-----------      </Variables>      <types>               SEND typedef              {                 Структура              }      </types>      <lists>           Линия -------           Квадрат------           Текст--------      </lists>      <code>        <Line>             ------------------------- КОД -----------------------       </Line>      </code>    </LD_Unit>

Главное — те примитивы которые будут анимированы, привязываются к переменным:

        <Item Type="LINE" color="#ffffff" Style="onoff:#96C1FF">          <Value>this</Value>...После запуска проекта, Item Type="LINE" - конвертируется в обьект.

Style=“onoff:#96C1FF” — как раз и говорит что делать- если значение переменной больше 0, меняем цвет, положение, текст и другие эффекты.

Компилятор.

Компилятор — собственной разработки, не LLVM\Clang и подобные конструкторы. Вся логика расстановки переменных и инструкций в памяти разрабатывал сам, и вместе с программой для ПЛК создается файл на подобии .elf:

--- DISASSEMBLY & BINARY CODE ---Instruction [Offset]                          | Binary Representation (MSB..LSB)------------------------------------------------------------------------0] LDRI R3 Address: 818                       | 00000110 00110000 00000011 001100104] LDPHY R3 R3 R0                             | 00001001 00011000 11000000 000000008] SDRI R3 Address: 814                       | 00001101 00110000 00000011 0010111012] MOV R0 R28 R0                             | 00111100 00000111 00000000 0000000016] SDRI R0 Address: 818                      | 00001101 00000000 00000011 00110010--- SYMBOLS & VARIABLES MEMORY MAP ---Address    | Name                           | Type            | Size  --------------------------------------------------------------------------------------818        | system.AddrTime                | dword           | 4     814        | system.Time                    | dword           | 4     778        | system.IN_phy                  | pointer         | 4     798        | system.emodule_.DI_0           | byte            | 1     800        | system.emodule_.DI_2           | byte            | 1     804        | system.emodule_.DI_6           | byte            | 1 
--- SYMBOLS & VARIABLES MEMORY MAP ---Address    | Name                           | Type            | Size  --------------------------------------------------------------------------------------818        | system.AddrTime                | dword           | 4     814        | system.Time                    | dword           | 4     778        | system.IN_phy                  | pointer         | 4     798        | system.emodule_.DI_0           | byte            | 1     800        | system.emodule_.DI_2           | byte            | 1     804        | system.emodule_.DI_6           | byte            | 1 

Вместе с человекочитамым текстом формируется файл для моей среды разработки:

#####XML_SYMBOLS_BEGIN#####<?xml version="1.0" encoding="UTF-8"?><symbols>  <symbol name="system.AddrTime" type="dword" address="818" size="4"/>  <symbol name="system.Time" type="dword" address="814" size="4"/>  <symbol name="system.IN_phy" type="pointer" address="778" size="4"/>  <symbol name="system.emodule_.DI_0" type="byte" address="798" size="1"/>  <symbol name="system.emodule_.DI_2" type="byte" address="800" size="1"/>

Тут содержится имя переменной, ее тип и адрес. Это позволяет не только отправить команду чтоб записать в переменную какое то значение, но и читать:

Установка значения переменной в программе ПЛК.

Установка значения переменной в программе ПЛК.

Теперь когда компилятор вернул нам регион памяти переменных, мы отправляем команду на МК — просто прислать нам регион памяти (а память у нас виртуальная, обычный массив uint8_t meory[size] )

Получаем в среде этот регион из массива, и среда уже понимает какая переменна за что отвечает, а движок отрисовки на этих значениях знает что делать.

В целом графика выглядит так:

Очень легкая среда которая даже в режиме отрисовки занимает в ОЗУ всего 120 Мб, и может работать даже на первых версиях Raspberry PI (Среда разработана с Open JDK).

ссылка на оригинал статьи https://habr.com/ru/articles/1103196/