Code generation for Arduino (PWM on finite automata)
In this example, we will develop a simple model in Engee for pulse width modulation on the output of Arduino-compatible boards using the Finite Automata library to build the algorithm and the C Function
block to communicate with the peripherals of the target device.
Introduction
The purpose of this example is to show the process of developing a PWM contact control algorithm for Arduino-compatible platforms using the terminal automata library. In this example, unlike the demo example arduino_blink_chart
, all possible states of the algorithm are reduced to a single state, and the output variables are changed in conditional transitions. This makes it possible to reduce the size of the compiled file loaded into the target device, even slightly. In addition, the example shows how to use the C Function
block to access controller peripherals and functions of the Arduino development environment.
The hardware used in this example is the same as in the example arduino_blink_chart
.
Model Description
In the Arduino board PWM pin control model, the Сhart
block directly reproduces the control algorithm, its output pins cnt
and out
are used to output and store the corresponding variables. The C Function
block is used to communicate with the controller periphery via functions used in the Arduino IDE. Block Outport
("Cnt") in the model is necessary for successful code generation.

The "in" input of the C Function
block receives the value of the PWM pulse duration, where it is further transferred to the PWM pin (~13) of the Arduino board.
State diagram
The state diagram of the block Chart
, as mentioned earlier, in this example is represented by a single state - Counter
. As can be seen from the diagram below, this state does not reproduce any actions except for the checks of transition conditions. At each step of the model computation, the transition condition is checked in the specified order until one of them is fulfilled. When the condition is fulfilled, the condition body is executed and the transition to the initial state occurs, after which the cycle repeats.

The condition body assigns one of 6 possible values to the PWM pulse width variable out
and increments the counter variable cnt
. The condition for one of the transitions is that the counter variable is within one of the specified ranges. When the counter variable cnt
reaches the maximum value "1000", the counter is reset (cnt = 0;
) and the PWM pulse duration is set to "0".
.
Thus, we get a step change of PWM pulse duration at the output of Out
block Chart
.

The initial values of the output variables are "0", as can be seen in the signal setting menu in the status diagram.
Block C Function
The C Function
block is used in the considered model exclusively for code generation. Therefore, for successful compilation and verification of the Engee model, the user code in the C Function
sections is enclosed in the conditional compilation directives #ifdef ... #endif
. The compilation condition written in the code C Function
is executed only when the header file Arduino.h
is connected, which happens automatically when compiling from the Arduino IDE, and does not happen when compiling in the Engee modelling environment.
The StartCode
section of the block is used to initialise the controller peripherals and will be called once in the Arduino IDE in the function setup()
.

The OutputCode
section of the block is used to change the duration of the PWM pulse and output this value to the serial port. It will be called every 1 millisecond in the function loop()
.

A detailed description of each procedure is given in the block comments C Function
.
Modelling results
Let's load the described model:
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);
From the obtained model data, plot the change in counter value and PWM pulse width:
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)
As can be seen from the simulation results, the received counter signal Cnt
increases in increments of "1" every 1 millisecond from "0" to "1000" for 1 second. The PWM pulse width signal Out
increases stepwise with values depending on the value of the counter value: "51", "102", "153", "204", "255".
Now, having made sure that the algorithm and the model work correctly, we can proceed to code generation and reproduce the work of the model on the target device.
Uploading the code to Arduino
To transfer the developed model to the target device, let's generate C code:
engee.generate_code( "$(@__DIR__)/pwm_chart.engee",
"$(@__DIR__)/pwm_chart_code" )
Plug-in files were generated in the specified directory pwm_chart_code
. Also in the directory of the demo example arduino_pwm_chart
there is a pre-written Arduino sketch with the name of this directory arduino_pwm_chart.ino
. In it, the header file obtained during code generation is connected, the model calculation time variables are initialised and called, and the model calculation functions are called. At the same time, the model calculation functions are now used not only to calculate the control algorithm, but also to control the controller periphery. A detailed description of the sketch is given in the comments of its code.
To execute the code on Arduino, you need to download the arduino_pwm_chart
directory and upload the arduino_pwm_chart.ino
sketch from Arduino IDE to the target device. In our case, as stated earlier, it is Amperka's Iskra Neo.
After successful compilation and downloading the executable code to the target device, the Arduino IDE diagnostic window displays a message about the success of the operation and the size of the output file:

Code execution on Arduino
Since in the C Function
block we used the PWM period duration value not only to control the PWM channel but also to output the calculated value to the serial port of the computer, let's go to the Arduino IDE tools and run the connection plotter over the serial connection. The connection plotter will output the change in the variable out
at each calculation step.


As can be seen from the plotter graph, the period of change of the PWM pulse duration is 200 milliseconds, and the values of the durations have the previously indicated values. In addition, on the Arduino board it is possible to observe a stepwise, with a period of 1 second gradual increase in the brightness of the built-in LED, since both the LED and pin 13 of the board are connected to the same channel of the controller.
Capturing signals from the Arduino board
To complete the testing of the model on the target device, we will oscillograph the required signal from pin 13 of the Arduino board.

The presented oscillogram shows a gradual increase in the PWM pulse duration with a duration change period of ~200 milliseconds and a total duration of the duration increase cycle of 1 second.
Conclusion
In this demo, a model of a PWM control algorithm for Arduino-compatible platforms based on a library of finite automata has been developed. Also a separate attention was paid to the consideration of working with the periphery of the target device by means of the block C Function
. As it was established by the data received from the microcontroller and oscillograms taken from the debug board, the C-code generated from the Engee model exactly reproduces the algorithm and corresponds to the simulation results.