Документация Engee
Notebook

Генерация кода для Arduino (ШИМ на конечных автоматах)

В этом примере мы разработаем простейшую модель в Engee для широтно-импульсной модуляции на выходе Arduino-совместимых плат с использованием библиотеки Конечных автоматов для построения алгоритма и блока C Function для взаимодействия с периферией целевого устройства.

Введение

Цель этого примера - показать процесс разработки алгоритма управления контактами ШИМ для Arduino-совместимых платформ с использованием библиотеки конечных автоматов. В этом примере, в отличие от демонстрационного примера arduino_blink_chart, все возможные состояния алгоритма сведены к единственному, а изменение выходных переменных происходит в условных переходах. Это дает возможность пусть незначительно, но уменьшить объем загружаемого в целевое устройство скомпилированного файла. Кроме того, пример показывает, как при помощи блока C Function обращаться к периферии контроллера и функциям среды разработки Arduino.

Аппаратное обеспечение в этом примере используется то же, что и в примере arduino_blink_chart.

Описание модели

В модели управления контактом ШИМ платы Arduino блок Сhart непосредственно воспроизводит управляющий алгоритм, его выходные контакты cnt и out используются для вывода и сохранения соответствующих переменных. Блок C Function используется для взаимодействия с периферией контроллера через функции, используемые в Arduino IDE. Блок Outport ("Cnt") в модели необходим для успешной кодогенерации.

image_2.png

На вход "in" блока C Function поступает величина длительности импульса ШИМ, где далее она передается на контакт ШИМ (~13) платы Arduino.

Диаграмма состояний

Диаграмма состояний блока Chart, как и упоминалось ранее, в данном примере представлена одним состоянием - Counter. Как видно из диаграммы ниже, это состояние не воспроизводит никаких действий, кроме проверок условий переходов. На каждом шаге расчета модели происходит проверка условия перехода по указанному порядку, пока не выполнится одно из них. При выполнении условия исполняется тело условия и происходит переход в начальное состояние, после чего цикл повторяется.

image.png

В теле условия выполняется присваивание одного из 6 возможных значений переменной out длительности импульса ШИМ и инкрементируется переменная счетчика cnt. Условие для выполнения одного из переходов - нахождение переменной счетчика в одном из указанных диапазонов. При достижении переменной cnt максимального значения "1000", счетчик сбрасывается (cnt = 0;), длительность импульса ШИМ устанавливается равной "0".

Таким образом, мы получаем на выходе Out блока Chart ступенчатое изменение длительности импульса ШИМ.

image.png

Начальные значения выходных переменных равны "0", как это видно из меню настройки сигналов в диаграмме состояний.

Блок C Function

Блок C Function используется в рассматриваемой модели исключительно для кодогенерации. Поэтому для успешной компиляции и проверки работы модели Engee пользовательский код в секциях C Function заключен в директивы условной компиляции #ifdef ... #endif. Прописанное в коде C Function условие компиляции выполняется только при подключении заголовочного файла Arduino.h, что происходит автоматически при компиляции из Arduino IDE, и не происходит при компиляции в среде моделирования Engee.

Секция StartCode блока используется для инициализации периферии контроллера и будет вызвана в Arduino IDE один раз в функции setup().

image.png

Секция OutputCode блока используется для изменения длительности импульса ШИМ и вывода этого значения в последовательный порт. Она будет вызываться каждую 1 миллисекунду в функции loop().

image_3.png

Подробное описание каждой процедуры дано в комментариях блока C Function.

Результаты моделирования

Загрузим описанную модель:

In [ ]:
if "pwm_chart" in [m.name for m in engee.get_all_models()]
    m = engee.open( "pwm_chart" );
else
    m = engee.load( "$(@__DIR__)/pwm_chart.engee" );
end

data = engee.run(m);

Из полученных данных модели построим графики изменения значения счетчика и длительности импульса ШИМ:

In [ ]:
using Plots
plotlyjs();
plot(data["Chart.cnt"].time, data["Chart.cnt"].value,
    label="Cnt", size=(900,300), lw=2)
plot!(data["Chart.out"].time, data["Chart.out"].value,
    label="Out", size=(900,300), lw=2)
xlims!(0.0,3.0)
Out[0]:

Как видно из результатов моделирования, полученный сигнал счетчика Cnt увеличивается с шагом "1" каждую 1 миллисекунду от "0" до "1000" в течение 1 секунды. Сигнал длительности импульса ШИМ Out в зависимости от величины значения счетчика ступенчато возрастает со значениями: "51", "102", "153", "204", "255".

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

Загрузка кода в Arduino

Для переноса разработанной модели на целевое устройство сгенерируем Си-код:

In [ ]:
engee.generate_code( "$(@__DIR__)/pwm_chart.engee",
                     "$(@__DIR__)/pwm_chart_code" )
Out[0]:
"Created directory - /user/start/examples/codegen/arduino_pwm_chart/pwm_chart_code"

В указанной директории pwm_chart_code сгенерировались подключаемые файлы. Также в директории демонстрационного примера arduino_pwm_chart выложен заранее написанный скетч Arduino с именем этой директории arduino_pwm_chart.ino. В нем подключается заголовочный файл, полученный при кодогенерации, инициализируются и вызываются переменные времени расчета модели, а также вызываются функции расчета модели. При этом, функции расчета модели теперь используются не только для расчета управляющего алгоритма, но и для управления периферией контроллера. Подробное описание скетча дано в комментариях его кода.

Для выполнения кода на Arduino необходимо скачать директорию arduino_pwm_chart и загрузить скетч arduino_pwm_chart.ino из Arduino IDE в целевое устройство. В нашем случае, как говорилось ранее, это - Iskra Neo от Amperka.

После успешной компиляции и загрузки исполняемого кода на целевое устройство в окно диагностики Arduino IDE выводится сообщение об успешности операции и размере выходного файла:

image.png

Выполнение кода на Arduino

Так как в блоке C Function мы использовали значение длительности периода ШИМ не только для управления каналом ШИМ, но и для вывода рассчитанного значения в последовательный порт компьютера, перейдем в инструменты Arduino IDE и запустим плоттер по последовательному соединению. На плоттер соединения будет выводиться изменение переменной out на каждом шагу расчета.

.gif

image.png

Как видно из графика, представленного на плоттере, период изменения длительности импульса ШИМ составляет 200 миллисекунд, а значения длительностей имеют ранее указанные значения. Кроме этого, на плате Arduino можно наблюдать ступенчатое, с периодом в 1 секунду постепенное увеличение яркости встроенного светодиода, так как и светодиод, и контакт 13 платы подключены к одному каналу контроллера.

Снятие сигналов с платы Arduino

В завершение тестирования работы модели на целевом устройстве проведем осциллографирование необходимого сигнала с контакта 13 платы Arduino.

imag098.png

На представленной осциллограмме наблюдается постепенное увеличение длительности импульса ШИМ с периодом изменения длительности ~200 миллисекунд и общей длительностью цикла увеличения длительности 1 секунда.

Вывод

В рассмотренном демонстрационном примере была разработана модель алгоритма управления ШИМ для Arduino-совместимых платформ на основе библиотеки конечных автоматов. Также отдельное внимание уделено рассмотрению работы с периферией целевого устройства посредством блока C Function. Как было установлено по полученным из микроконтроллера данным и снятым с отладочной платы осциллограммам, сгенерированный из модели Engee Си-код в точности воспроизводит заложенный алгоритм и соответствует результатам моделирования.

Блоки, использованные в примере